Merge "Consolidate input OWNERS files"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 4b64203..260ee8d 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -67,5 +67,66 @@
         }
       ]
     }
+  ],
+  "hwasan-postsubmit": [
+    {
+      "name": "SurfaceFlinger_test",
+      "options": [
+        {
+          "include-filter": "*CredentialsTest.*"
+        },
+        {
+          "include-filter": "*SurfaceFlingerStress.*"
+        },
+        {
+          "include-filter": "*SurfaceInterceptorTest.*"
+        },
+        {
+          "include-filter": "*LayerTransactionTest.*"
+        },
+        {
+          "include-filter": "*LayerTypeTransactionTest.*"
+        },
+        {
+          "include-filter": "*LayerUpdateTest.*"
+        },
+        {
+          "include-filter": "*GeometryLatchingTest.*"
+        },
+        {
+          "include-filter": "*CropLatchingTest.*"
+        },
+        {
+          "include-filter": "*ChildLayerTest.*"
+        },
+        {
+          "include-filter": "*ScreenCaptureTest.*"
+        },
+        {
+          "include-filter": "*ScreenCaptureChildOnlyTest.*"
+        },
+        {
+          "include-filter": "*DereferenceSurfaceControlTest.*"
+        },
+        {
+          "include-filter": "*BoundlessLayerTest.*"
+        },
+        {
+          "include-filter": "*MultiDisplayLayerBoundsTest.*"
+        },
+        {
+          "include-filter": "*InvalidHandleTest.*"
+        },
+        {
+          "include-filter": "*VirtualDisplayTest.*"
+        },
+        {
+          "include-filter": "*RelativeZTest.*"
+        },
+        {
+          "include-filter": "*RefreshRateOverlayTest.*"
+        }
+      ]
+    }
   ]
 }
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 7aee795..b94f3da 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -1194,6 +1194,11 @@
     bool traceStream = false;
     bool onlyUserspace = false;
 
+    fprintf(stderr,
+            "** Warning: atrace will end vendor support in the next Android Release. **\n"
+            "** Perfetto is the suggested replacement tool. It will gain vendor      **\n"
+            "** support. See https://perfetto.dev/docs/quickstart/android-tracing    **\n\n");
+
     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
         showHelp(argv[0]);
         exit(0);
@@ -1224,10 +1229,7 @@
 
         if (ret < 0) {
             for (int i = optind; i < argc; i++) {
-                if (!setCategoryEnable(argv[i])) {
-                    fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
-                    exit(1);
-                }
+                setCategoryEnable(argv[i]);
             }
             break;
         }
@@ -1343,10 +1345,10 @@
         // contain entries from only one CPU can cause "begin" entries without a
         // matching "end" entry to show up if a task gets migrated from one CPU to
         // another.
-        if (!onlyUserspace)
+        if (!onlyUserspace) {
             ok = clearTrace();
-
-        writeClockSyncMarker();
+            writeClockSyncMarker();
+        }
         if (ok && !async && !traceStream) {
             // Sleep to allow the trace to be captured.
             struct timespec timeLeft;
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 1c3a4f2..a417493 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -292,12 +292,9 @@
     write /sys/kernel/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
     write /sys/kernel/debug/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
 
-# Set up histogram triggers
-    # rss_stat_throttled (bucket size == 512KB)
-    chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
+    # allow creating event triggers
     chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger
-    write /sys/kernel/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
-    write /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
+    chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
 
 # Only create the tracing instance if persist.mm_events.enabled
 # Attempting to remove the tracing instance after it has been created
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index a2491e5..a60972b 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -101,6 +101,7 @@
         "libhidlbase",
         "liblog",
         "libutils",
+        "libvintf",
         "libbinderdebug",
         "packagemanager_aidl-cpp",
     ],
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 0e9ce89..942a17e 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -88,6 +88,7 @@
 #include <private/android_logger.h>
 #include <serviceutils/PriorityDumper.h>
 #include <utils/StrongPointer.h>
+#include <vintf/VintfObject.h>
 #include "DumpstateInternal.h"
 #include "DumpstateService.h"
 #include "dumpstate.h"
@@ -829,7 +830,8 @@
 
     // Logging statement  below is useful to time how long each entry takes, but it's too verbose.
     // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
-    int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
+    size_t flags = ZipWriter::kCompress | ZipWriter::kDefaultCompression;
+    int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), flags,
                                                   get_mtime(fd, ds.now_));
     if (err != 0) {
         MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
@@ -921,7 +923,8 @@
 
 bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
     MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
-    int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
+    size_t flags = ZipWriter::kCompress | ZipWriter::kDefaultCompression;
+    int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), flags, ds.now_);
     if (err != 0) {
         MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
                ZipWriter::ErrorCodeString(err));
@@ -1394,6 +1397,23 @@
     }
 }
 
+// Dump all of the files that make up the vendor interface.
+// See the files listed in dumpFileList() for the latest list of files.
+static void DumpVintf() {
+    const auto vintfFiles = android::vintf::details::dumpFileList();
+    for (const auto vintfFile : vintfFiles) {
+        struct stat st;
+        if (stat(vintfFile.c_str(), &st) == 0) {
+            if (S_ISDIR(st.st_mode)) {
+                ds.AddDir(vintfFile, true /* recursive */);
+            } else {
+                ds.EnqueueAddZipEntryAndCleanupIfNeeded(ZIP_ROOT_DIR + vintfFile,
+                        vintfFile);
+            }
+        }
+    }
+}
+
 static void DumpExternalFragmentationInfo() {
     struct stat st;
     if (stat("/proc/buddyinfo", &st) != 0) {
@@ -1619,6 +1639,8 @@
         do_dmesg();
     }
 
+    DumpVintf();
+
     RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
 
     RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
@@ -1648,7 +1670,7 @@
 
     DumpPacketStats();
 
-    RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
+    RunDumpsys("EBPF MAP STATS", {"connectivity", "trafficcontroller"});
 
     DoKmsg();
 
@@ -2084,7 +2106,7 @@
     int timeout_failures = 0;
     bool dalvik_found = false;
 
-    const std::set<int> hal_pids = get_interesting_hal_pids();
+    const std::set<int> hal_pids = get_interesting_pids();
 
     struct dirent* d;
     while ((d = readdir(proc.get()))) {
@@ -2418,7 +2440,7 @@
     // Given that bugreport is required to diagnose failures, it's better to set an arbitrary amount
     // of timeout for IDumpstateDevice than to block the rest of bugreport. In the timeout case, we
     // will kill the HAL and grab whatever it dumped in time.
-    constexpr size_t timeout_sec = 30;
+    constexpr size_t timeout_sec = 45;
 
     if (dumpstate_hal_handle_aidl != nullptr) {
         DoDumpstateBoardAidl(dumpstate_hal_handle_aidl, dumpstate_fds, options_->bugreport_mode,
@@ -2733,8 +2755,8 @@
                                         const android::base::unique_fd& screenshot_fd_in,
                                         bool is_screenshot_requested) {
     // Duplicate the fds because the passed in fds don't outlive the binder transaction.
-    bugreport_fd.reset(dup(bugreport_fd_in.get()));
-    screenshot_fd.reset(dup(screenshot_fd_in.get()));
+    bugreport_fd.reset(fcntl(bugreport_fd_in.get(), F_DUPFD_CLOEXEC, 0));
+    screenshot_fd.reset(fcntl(screenshot_fd_in.get(), F_DUPFD_CLOEXEC, 0));
 
     SetOptionsFromMode(bugreport_mode, this, is_screenshot_requested);
 }
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 49c1318..f0c19b9 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -65,6 +65,7 @@
                                              const sp<LocalRegistrationCallback>&));
     MOCK_METHOD2(unregisterForNotifications, status_t(const String16&,
                                              const sp<LocalRegistrationCallback>&));
+    MOCK_METHOD0(getServiceDebugInfo, std::vector<ServiceDebugInfo>());
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
 };
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index c9f680b..0f7c489 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -72,8 +72,6 @@
         },
     },
 
-    clang: true,
-
     tidy: true,
     tidy_checks: [
         "-*",
@@ -81,8 +79,9 @@
         "cert-*",
         "-cert-err58-cpp",
     ],
-    tidy_flags: [
-        "-warnings-as-errors=clang-analyzer-security*,cert-*",
+    tidy_checks_as_errors: [
+        "clang-analyzer-security*",
+        "cert-*",
     ],
 }
 
@@ -127,7 +126,6 @@
 cc_test_host {
     name: "run_dex2oat_test",
     test_suites: ["general-tests"],
-    clang: true,
     srcs: [
         "run_dex2oat_test.cpp",
         "run_dex2oat.cpp",
@@ -187,7 +185,6 @@
         "-Wall",
         "-Werror",
     ],
-    clang: true,
 
     srcs: [
         "otapreopt_chroot.cpp",
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index b6ebfca..ee3a67e 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -41,6 +41,7 @@
 #include <fstream>
 #include <functional>
 #include <regex>
+#include <unordered_set>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -54,7 +55,8 @@
 #include <cutils/fs.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
-#include <log/log.h>               // TODO: Move everything to base/logging.
+#include <linux/quota.h>
+#include <log/log.h> // TODO: Move everything to base/logging.
 #include <logwrap/logwrap.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_projectid_config.h>
@@ -81,6 +83,7 @@
 // #define GRANULAR_LOCKS
 
 using android::base::ParseUint;
+using android::base::Split;
 using android::base::StringPrintf;
 using std::endl;
 
@@ -115,6 +118,12 @@
 
 static std::atomic<bool> sAppDataIsolationEnabled(false);
 
+/**
+ * Flag to control if project ids are supported for internal storage
+ */
+static std::atomic<bool> sUsingProjectIdsFlag(false);
+static std::once_flag flag;
+
 namespace {
 
 constexpr const char* kDump = "android.permission.DUMP";
@@ -456,14 +465,41 @@
     return res;
 }
 
-static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid) {
-    if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
+static bool internal_storage_has_project_id() {
+    // The following path is populated in setFirstBoot, so if this file is present
+    // then project ids can be used. Using call once to cache the result of this check
+    // to avoid having to check the file presence again and again.
+    std::call_once(flag, []() {
+        auto using_project_ids =
+                StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+        sUsingProjectIdsFlag = access(using_project_ids.c_str(), F_OK) == 0;
+    });
+    //    return sUsingProjectIdsFlag;
+    return false;
+}
+
+static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid,
+                           long project_id) {
+    if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) {
         PLOG(ERROR) << "Failed to prepare " << path;
         return -1;
     }
+    if (internal_storage_has_project_id()) {
+        return set_quota_project_id(path, project_id, true);
+    }
     return 0;
 }
 
+static int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
+                                 uid_t uid, gid_t gid, long project_id) {
+    auto path = StringPrintf("%s/%s", parent.c_str(), name);
+    int ret = prepare_app_cache_dir(parent, name, target_mode, uid, gid);
+    if (ret == 0 && internal_storage_has_project_id()) {
+        return set_quota_project_id(path, project_id, true);
+    }
+    return ret;
+}
+
 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;
@@ -597,9 +633,10 @@
     }
 }
 
-static binder::Status createAppDataDirs(const std::string& path,
-        int32_t uid, int32_t* previousUid, int32_t cacheGid,
-        const std::string& seInfo, mode_t targetMode) {
+static binder::Status createAppDataDirs(const std::string& path, int32_t uid, int32_t gid,
+                                        int32_t previousUid, int32_t cacheGid,
+                                        const std::string& seInfo, mode_t targetMode,
+                                        long projectIdApp, long projectIdCache) {
     struct stat st{};
     bool parent_dir_exists = (stat(path.c_str(), &st) == 0);
 
@@ -609,23 +646,17 @@
     bool code_cache_exists = (access(code_cache_path.c_str(), F_OK) == 0);
 
     if (parent_dir_exists) {
-        if (*previousUid < 0) {
-            // If previousAppId is -1 in CreateAppDataArgs, we will assume the current owner
-            // of the directory as previousUid. This is required because it is not always possible
-            // to chown app data during app upgrade (e.g. secondary users' CE storage not unlocked)
-            *previousUid = st.st_uid;
-        }
-        if (*previousUid != uid) {
-            if (!chown_app_dir(path, uid, *previousUid, cacheGid)) {
+        if (previousUid > 0 && previousUid != uid) {
+            if (!chown_app_dir(path, uid, previousUid, cacheGid)) {
                 return error("Failed to chown " + path);
             }
         }
     }
 
     // Prepare only the parent app directory
-    if (prepare_app_dir(path, targetMode, uid) ||
-            prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
-            prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
+    if (prepare_app_dir(path, targetMode, uid, gid, projectIdApp) ||
+        prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid, projectIdCache) ||
+        prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid, projectIdCache)) {
         return error("Failed to prepare " + path);
     }
 
@@ -666,12 +697,9 @@
 
     int32_t uid = multiuser_get_uid(userId, appId);
 
-    // If previousAppId < 0, we will use the existing app data owner as previousAppUid
-    // If previousAppId == 0, we use uid as previousUid (no data migration will happen)
-    // if previousAppId > 0, an app is upgrading and changing its app ID
-    int32_t previousUid = previousAppId > 0
-        ? (int32_t) multiuser_get_uid(userId, previousAppId)
-        : (previousAppId == 0 ? uid : -1);
+    // If previousAppId > 0, an app is changing its app ID
+    int32_t previousUid =
+            previousAppId > 0 ? (int32_t)multiuser_get_uid(userId, previousAppId) : -1;
 
     int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
     mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
@@ -681,10 +709,14 @@
         cacheGid = uid;
     }
 
+    long projectIdApp = get_project_id(uid, PROJECT_ID_APP_START);
+    long projectIdCache = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
+
     if (flags & FLAG_STORAGE_CE) {
         auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
 
-        auto status = createAppDataDirs(path, uid, &previousUid, cacheGid, seInfo, targetMode);
+        auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode,
+                                        projectIdApp, projectIdCache);
         if (!status.isOk()) {
             return status;
         }
@@ -709,11 +741,12 @@
     if (flags & FLAG_STORAGE_DE) {
         auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
 
-        auto status = createAppDataDirs(path, uid, &previousUid, cacheGid, seInfo, targetMode);
+        auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode,
+                                        projectIdApp, projectIdCache);
         if (!status.isOk()) {
             return status;
         }
-        if (previousUid != uid) {
+        if (previousUid > 0 && previousUid != uid) {
             chown_app_profile_dir(packageName, appId, userId);
         }
 
@@ -722,38 +755,38 @@
         }
     }
 
-    // TODO(b/220095381): Due to boot time regression, we have omitted call to
-    // createSdkSandboxDataDirectory from here temporarily (unless it's for testing)
-    if (uuid_ != nullptr && strcmp(uuid_, "TEST") == 0) {
-        auto status = createSdkSandboxDataDirectory(uuid, packageName, userId, appId, previousAppId,
-                                                    seInfo, flags);
-        if (!status.isOk()) {
-            return status;
+    if (flags & FLAG_STORAGE_SDK) {
+        // Safe to ignore status since we can retry creating this by calling reconcileSdkData
+        auto ignore = createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId, flags);
+        if (!ignore.isOk()) {
+            PLOG(WARNING) << "Failed to create sdk data package directory for " << packageName;
         }
+
+    } else {
+        // Package does not need sdk storage. Remove it.
+        destroySdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
     }
 
     return ok();
 }
 
 /**
- * Responsible for creating /data/misc_{ce|de}/user/0/sdksandbox/<app-name> directory and other
+ * Responsible for creating /data/misc_{ce|de}/user/0/sdksandbox/<package-name> directory and other
  * app level sub directories, such as ./shared
  */
-binder::Status InstalldNativeService::createSdkSandboxDataDirectory(
+binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory(
         const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
-        int32_t appId, int32_t previousAppId, const std::string& seInfo, int32_t flags) {
+        int32_t appId, int32_t flags) {
     int32_t sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
     if (sdkSandboxUid == -1) {
         // There no valid sdk sandbox process for this app. Skip creation of data directory
         return ok();
     }
 
-    // TODO(b/211763739): what if uuid is not nullptr or TEST?
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
     constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
-    for (int i = 0; i < 2; i++) {
-        int currentFlag = storageFlags[i];
+    for (int currentFlag : storageFlags) {
         if ((flags & currentFlag) == 0) {
             continue;
         }
@@ -762,33 +795,16 @@
         // /data/misc_{ce,de}/<user-id>/sdksandbox directory gets created by vold
         // during user creation
 
-        // Prepare the app directory
-        auto appPath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
-                                                                 packageName.c_str());
-        if (prepare_app_dir(appPath, 0751, AID_SYSTEM)) {
-            return error("Failed to prepare " + appPath);
+        // Prepare the package directory
+        auto packagePath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
+                                                                     packageName.c_str());
+#if SDK_DEBUG
+        LOG(DEBUG) << "Creating app-level sdk data directory: " << packagePath;
+#endif
+
+        if (prepare_app_dir(packagePath, 0751, AID_SYSTEM, AID_SYSTEM, 0)) {
+            return error("Failed to prepare " + packagePath);
         }
-
-        // Now prepare the shared directory which will be accessible by all codes
-        auto sharedPath = create_data_misc_sdk_sandbox_shared_path(uuid_, isCeData, userId,
-                                                                   packageName.c_str());
-
-        int32_t previousSdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, previousAppId);
-        int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
-        if (cacheGid == -1) {
-            return exception(binder::Status::EX_ILLEGAL_STATE,
-                             StringPrintf("cacheGid cannot be -1 for sdksandbox data"));
-        }
-        auto status = createAppDataDirs(sharedPath, sdkSandboxUid, &previousSdkSandboxUid, cacheGid,
-                                        seInfo, 0700);
-        if (!status.isOk()) {
-            return status;
-        }
-
-        // TODO(b/211763739): We also need to handle art profile creations
-
-        // TODO(b/211763739): And return the CE inode of the sdksandbox root directory and
-        // app directory under it so we can clear contents while CE storage is locked
     }
 
     return ok();
@@ -837,6 +853,111 @@
     return ok();
 }
 
+binder::Status InstalldNativeService::reconcileSdkData(
+        const android::os::ReconcileSdkDataArgs& args) {
+    // Locking is performed depeer in the callstack.
+
+    return reconcileSdkData(args.uuid, args.packageName, args.subDirNames, args.userId, args.appId,
+                            args.previousAppId, args.seInfo, args.flags);
+}
+
+/**
+ * Reconciles per-sdk directory under app-level sdk data directory.
+
+ * E.g. `/data/misc_ce/0/sdksandbox/<package-name>/<sdkPackageName>-<randomSuffix>
+ *
+ * - If the sdk data package directory is missing, we create it first.
+ * - If sdkPackageNames is empty, we delete sdk package directory since it's not needed anymore.
+ * - If a sdk level directory we need to prepare already exist, we skip creating it again. This
+ *   is to avoid having same per-sdk directory with different suffix.
+ * - If a sdk level directory exist which is absent from sdkPackageNames, we remove it.
+ */
+binder::Status InstalldNativeService::reconcileSdkData(const std::optional<std::string>& uuid,
+                                                       const std::string& packageName,
+                                                       const std::vector<std::string>& subDirNames,
+                                                       int userId, int appId, int previousAppId,
+                                                       const std::string& seInfo, int flags) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    LOCK_PACKAGE_USER();
+
+#if SDK_DEBUG
+    LOG(DEBUG) << "Creating per sdk data directory for: " << packageName;
+#endif
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+    // Prepare the sdk package directory in case it's missing
+    const auto status =
+            createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId, flags);
+    if (!status.isOk()) {
+        return status;
+    }
+
+    auto res = ok();
+    // We have to create sdk data for CE and DE storage
+    const int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+    for (int currentFlag : storageFlags) {
+        if ((flags & currentFlag) == 0) {
+            continue;
+        }
+        const bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+
+        const auto packagePath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
+                                                                           packageName.c_str());
+
+        // Remove existing sub-directories not referred in subDirNames
+        const std::unordered_set<std::string> expectedSubDirNames(subDirNames.begin(),
+                                                                  subDirNames.end());
+        const auto subDirHandler = [&packagePath, &expectedSubDirNames,
+                                    &res](const std::string& subDirName) {
+            // Remove the per-sdk directory if it is not referred in
+            // expectedSubDirNames
+            if (expectedSubDirNames.find(subDirName) == expectedSubDirNames.end()) {
+                auto path = packagePath + "/" + subDirName;
+                if (delete_dir_contents_and_dir(path) != 0) {
+                    res = error("Failed to delete " + path);
+                    return;
+                }
+            }
+        };
+        const int ec = foreach_subdir(packagePath, subDirHandler);
+        if (ec != 0) {
+            res = error("Failed to process subdirs for " + packagePath);
+            continue;
+        }
+
+        // Now create the subDirNames
+        for (const auto& subDirName : subDirNames) {
+            const std::string path =
+                    create_data_misc_sdk_sandbox_sdk_path(uuid_, isCeData, userId,
+                                                          packageName.c_str(), subDirName.c_str());
+
+            // Create the directory along with cache and code_cache
+            const int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
+            if (cacheGid == -1) {
+                return exception(binder::Status::EX_ILLEGAL_STATE,
+                                 StringPrintf("cacheGid cannot be -1 for sdk data"));
+            }
+            const int32_t sandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
+            int32_t previousSandboxUid = multiuser_get_sdk_sandbox_uid(userId, previousAppId);
+            int32_t appUid = multiuser_get_uid(userId, appId);
+            long projectIdApp = get_project_id(appUid, PROJECT_ID_APP_START);
+            long projectIdCache = get_project_id(appUid, PROJECT_ID_APP_CACHE_START);
+            auto status =
+                    createAppDataDirs(path, sandboxUid, AID_NOBODY, previousSandboxUid, cacheGid,
+                                      seInfo, 0700 | S_ISGID, projectIdApp, projectIdCache);
+            if (!status.isOk()) {
+                res = status;
+                continue;
+            }
+        }
+    }
+
+    return res;
+}
+
 binder::Status InstalldNativeService::migrateAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
@@ -982,6 +1103,47 @@
             }
         }
     }
+    auto status = clearSdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
+    if (!status.isOk()) {
+        res = status;
+    }
+    return res;
+}
+
+binder::Status InstalldNativeService::clearSdkSandboxDataPackageDirectory(
+        const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+        int32_t flags) {
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    const char* pkgname = packageName.c_str();
+
+    binder::Status res = ok();
+    constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+    for (int i = 0; i < 2; i++) {
+        int currentFlag = storageFlags[i];
+        if ((flags & currentFlag) == 0) {
+            continue;
+        }
+        bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+        std::string suffix;
+        if (flags & FLAG_CLEAR_CACHE_ONLY) {
+            suffix = CACHE_DIR_POSTFIX;
+        } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
+            suffix = CODE_CACHE_DIR_POSTFIX;
+        }
+
+        auto appPath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId, pkgname);
+        if (access(appPath.c_str(), F_OK) != 0) continue;
+        const auto subDirHandler = [&appPath, &res, &suffix](const std::string& filename) {
+            auto filepath = appPath + "/" + filename + suffix;
+            if (delete_dir_contents(filepath, true) != 0) {
+                res = error("Failed to clear contents of " + filepath);
+            }
+        };
+        const int ec = foreach_subdir(appPath, subDirHandler);
+        if (ec != 0) {
+            res = error("Failed to process subdirs for " + appPath);
+        }
+    }
     return res;
 }
 
@@ -1078,6 +1240,32 @@
             }
         }
     }
+    auto status = destroySdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
+    if (!status.isOk()) {
+        res = status;
+    }
+    return res;
+}
+
+binder::Status InstalldNativeService::destroySdkSandboxDataPackageDirectory(
+        const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+        int32_t flags) {
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    const char* pkgname = packageName.c_str();
+
+    binder::Status res = ok();
+    constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+    for (int i = 0; i < 2; i++) {
+        int currentFlag = storageFlags[i];
+        if ((flags & currentFlag) == 0) {
+            continue;
+        }
+        bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+        auto appPath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId, pkgname);
+        if (rename_delete_dir_contents_and_dir(appPath) != 0) {
+            res = error("Failed to delete " + appPath);
+        }
+    }
     return res;
 }
 
@@ -1563,6 +1751,36 @@
         }
     }
 
+    // Copy sdk data for all known users
+    for (auto userId : users) {
+        LOCK_USER();
+
+        constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+        for (int currentFlag : storageFlags) {
+            const bool isCeData = currentFlag == FLAG_STORAGE_CE;
+
+            const auto from = create_data_misc_sdk_sandbox_package_path(from_uuid, isCeData, userId,
+                                                                        package_name);
+            if (access(from.c_str(), F_OK) != 0) {
+                LOG(INFO) << "Missing source " << from;
+                continue;
+            }
+            const auto to = create_data_misc_sdk_sandbox_path(to_uuid, isCeData, userId);
+
+            const int rc = copy_directory_recursive(from.c_str(), to.c_str());
+            if (rc != 0) {
+                res = error(rc, "Failed copying " + from + " to " + to);
+                goto fail;
+            }
+        }
+
+        if (!restoreconSdkDataLocked(toUuid, packageName, userId, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
+                                     appId, seInfo)
+                     .isOk()) {
+            res = error("Failed to restorecon");
+            goto fail;
+        }
+    }
     // We let the framework scan the new location and persist that before
     // deleting the data in the old location; this ordering ensures that
     // we can recover from things like battery pulls.
@@ -1590,6 +1808,18 @@
             }
         }
     }
+    for (auto userId : users) {
+        LOCK_USER();
+        constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+        for (int currentFlag : storageFlags) {
+            const bool isCeData = currentFlag == FLAG_STORAGE_CE;
+            const auto to = create_data_misc_sdk_sandbox_package_path(to_uuid, isCeData, userId,
+                                                                      package_name);
+            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
+                LOG(WARNING) << "Failed to rollback " << to;
+            }
+        }
+    }
     return res;
 }
 
@@ -1621,8 +1851,14 @@
     binder::Status res = ok();
     if (flags & FLAG_STORAGE_DE) {
         auto path = create_data_user_de_path(uuid_, userId);
-        if (delete_dir_contents_and_dir(path, true) != 0) {
-            res = error("Failed to delete " + path);
+        // Contents only, as vold is responsible for the user_de dir itself.
+        if (delete_dir_contents(path, true) != 0) {
+            res = error("Failed to delete contents of " + path);
+        }
+        auto sdk_sandbox_de_path =
+                create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/false, userId);
+        if (delete_dir_contents_and_dir(sdk_sandbox_de_path, true) != 0) {
+            res = error("Failed to delete " + sdk_sandbox_de_path);
         }
         if (uuid_ == nullptr) {
             path = create_data_misc_legacy_path(userId);
@@ -1637,12 +1873,19 @@
     }
     if (flags & FLAG_STORAGE_CE) {
         auto path = create_data_user_ce_path(uuid_, userId);
-        if (delete_dir_contents_and_dir(path, true) != 0) {
-            res = error("Failed to delete " + path);
+        // Contents only, as vold is responsible for the user_ce dir itself.
+        if (delete_dir_contents(path, true) != 0) {
+            res = error("Failed to delete contents of " + path);
+        }
+        auto sdk_sandbox_ce_path =
+                create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/true, userId);
+        if (delete_dir_contents_and_dir(sdk_sandbox_ce_path, true) != 0) {
+            res = error("Failed to delete " + sdk_sandbox_ce_path);
         }
         path = findDataMediaPath(uuid, userId);
-        if (delete_dir_contents_and_dir(path, true) != 0) {
-            res = error("Failed to delete " + path);
+        // Contents only, as vold is responsible for the media dir itself.
+        if (delete_dir_contents(path, true) != 0) {
+            res = error("Failed to delete contents of " + path);
         }
     }
     return res;
@@ -1879,20 +2122,70 @@
     return res.str();
 }
 #endif
+// On devices without sdcardfs, if internal and external are on
+// the same volume, a uid such as u0_a123 is used for both
+// internal and external storage; therefore, subtract that
+// amount from internal to make sure we don't count it double.
+// This needs to happen for data, cache and OBB
+static void deductDoubleSpaceIfNeeded(stats* stats, int64_t doubleSpaceToBeDeleted, uid_t uid,
+                                      const std::string& uuid) {
+    if (!supports_sdcardfs()) {
+        stats->dataSize -= doubleSpaceToBeDeleted;
+        long obbProjectId = get_project_id(uid, PROJECT_ID_EXT_OBB_START);
+        int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId);
+        stats->dataSize -= appObbSize;
+    }
+}
 
 static void collectQuotaStats(const std::string& uuid, int32_t userId,
         int32_t appId, struct stats* stats, struct stats* extStats) {
-    int64_t space;
+    int64_t space, doubleSpaceToBeDeleted = 0;
     uid_t uid = multiuser_get_uid(userId, appId);
-    if (stats != nullptr) {
-        if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
-            stats->dataSize += space;
+    static const bool supportsProjectId = internal_storage_has_project_id();
+
+    if (extStats != nullptr) {
+        space = get_occupied_app_space_external(uuid, userId, appId);
+
+        if (space != -1) {
+            extStats->dataSize += space;
+            doubleSpaceToBeDeleted += space;
         }
 
-        int cacheGid = multiuser_get_cache_gid(userId, appId);
-        if (cacheGid != -1) {
-            if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+        space = get_occupied_app_cache_space_external(uuid, userId, appId);
+        if (space != -1) {
+            extStats->dataSize += space; // cache counts for "data"
+            extStats->cacheSize += space;
+            doubleSpaceToBeDeleted += space;
+        }
+    }
+
+    if (stats != nullptr) {
+        if (!supportsProjectId) {
+            if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
+                stats->dataSize += space;
+            }
+            deductDoubleSpaceIfNeeded(stats, doubleSpaceToBeDeleted, uid, uuid);
+            int sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
+            if (sdkSandboxUid != -1) {
+                if ((space = GetOccupiedSpaceForUid(uuid, sdkSandboxUid)) != -1) {
+                    stats->dataSize += space;
+                }
+            }
+            int cacheGid = multiuser_get_cache_gid(userId, appId);
+            if (cacheGid != -1) {
+                if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+                    stats->cacheSize += space;
+                }
+            }
+        } else {
+            long projectId = get_project_id(uid, PROJECT_ID_APP_START);
+            if ((space = GetOccupiedSpaceForProjectId(uuid, projectId)) != -1) {
+                stats->dataSize += space;
+            }
+            projectId = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
+            if ((space = GetOccupiedSpaceForProjectId(uuid, projectId)) != -1) {
                 stats->cacheSize += space;
+                stats->dataSize += space;
             }
         }
 
@@ -1903,47 +2196,6 @@
             }
         }
     }
-
-    if (extStats != nullptr) {
-        static const bool supportsSdCardFs = supports_sdcardfs();
-        space = get_occupied_app_space_external(uuid, userId, appId);
-
-        if (space != -1) {
-            extStats->dataSize += space;
-            if (!supportsSdCardFs && stats != nullptr) {
-                // On devices without sdcardfs, if internal and external are on
-                // the same volume, a uid such as u0_a123 is used for
-                // application dirs on both internal and external storage;
-                // therefore, substract that amount from internal to make sure
-                // we don't count it double.
-                stats->dataSize -= space;
-            }
-        }
-
-        space = get_occupied_app_cache_space_external(uuid, userId, appId);
-        if (space != -1) {
-            extStats->dataSize += space; // cache counts for "data"
-            extStats->cacheSize += space;
-            if (!supportsSdCardFs && stats != nullptr) {
-                // On devices without sdcardfs, if internal and external are on
-                // the same volume, a uid such as u0_a123 is used for both
-                // internal and external storage; therefore, substract that
-                // amount from internal to make sure we don't count it double.
-                stats->dataSize -= space;
-            }
-        }
-
-        if (!supportsSdCardFs && stats != nullptr) {
-            // On devices without sdcardfs, the UID of OBBs on external storage
-            // matches the regular app UID (eg u0_a123); therefore, to avoid
-            // OBBs being include in stats->dataSize, compute the OBB size for
-            // this app, and substract it from the size reported on internal
-            // storage
-            long obbProjectId = uid - AID_APP_START + PROJECT_ID_EXT_OBB_START;
-            int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId);
-            stats->dataSize -= appObbSize;
-        }
-    }
 }
 
 static void collectManualStats(const std::string& path, struct stats* stats) {
@@ -1996,8 +2248,17 @@
     closedir(d);
 }
 
+void collectManualStatsForSubDirectories(const std::string& path, struct stats* stats) {
+    const auto subDirHandler = [&path, &stats](const std::string& subDir) {
+        auto fullpath = path + "/" + subDir;
+        collectManualStats(fullpath, stats);
+    };
+    foreach_subdir(path, subDirHandler);
+}
+
 static void collectManualStatsForUser(const std::string& path, struct stats* stats,
-        bool exclude_apps = false) {
+                                      bool exclude_apps = false,
+                                      bool is_sdk_sandbox_storage = false) {
     DIR *d;
     int dfd;
     struct dirent *de;
@@ -2022,6 +2283,11 @@
                 continue;
             } else if (exclude_apps && (user_uid >= AID_APP_START && user_uid <= AID_APP_END)) {
                 continue;
+            } else if (is_sdk_sandbox_storage) {
+                // In case of sdk sandbox storage (e.g. /data/misc_ce/0/sdksandbox/<package-name>),
+                // collect individual stats of each subdirectory (shared, storage of each sdk etc.)
+                collectManualStatsForSubDirectories(StringPrintf("%s/%s", path.c_str(), name),
+                                                    stats);
             } else {
                 collectManualStats(StringPrintf("%s/%s", path.c_str(), name), stats);
             }
@@ -2064,6 +2330,11 @@
     fts_close(fts);
 }
 static bool ownsExternalStorage(int32_t appId) {
+    // if project id calculation is supported then, there is no need to
+    // calculate in a different way and project_id based calculation can work
+    if (internal_storage_has_project_id()) {
+        return false;
+    }
     //  Fetch external storage owner appid  and check if it is the same as the
     //  current appId whose size is calculated
     struct stat s;
@@ -2164,6 +2435,19 @@
             collectManualStats(dePath, &stats);
             ATRACE_END();
 
+            // In case of sdk sandbox storage (e.g. /data/misc_ce/0/sdksandbox/<package-name>),
+            // collect individual stats of each subdirectory (shared, storage of each sdk etc.)
+            if (appId >= AID_APP_START && appId <= AID_APP_END) {
+                ATRACE_BEGIN("sdksandbox");
+                auto sdkSandboxCePath =
+                        create_data_misc_sdk_sandbox_package_path(uuid_, true, userId, pkgname);
+                collectManualStatsForSubDirectories(sdkSandboxCePath, &stats);
+                auto sdkSandboxDePath =
+                        create_data_misc_sdk_sandbox_package_path(uuid_, false, userId, pkgname);
+                collectManualStatsForSubDirectories(sdkSandboxDePath, &stats);
+                ATRACE_END();
+            }
+
             if (!uuid) {
                 ATRACE_BEGIN("profiles");
                 calculate_tree_size(
@@ -2400,6 +2684,13 @@
         collectManualStatsForUser(dePath, &stats);
         ATRACE_END();
 
+        ATRACE_BEGIN("sdksandbox");
+        auto sdkSandboxCePath = create_data_misc_sdk_sandbox_path(uuid_, true, userId);
+        collectManualStatsForUser(sdkSandboxCePath, &stats, false, true);
+        auto sdkSandboxDePath = create_data_misc_sdk_sandbox_path(uuid_, false, userId);
+        collectManualStatsForUser(sdkSandboxDePath, &stats, false, true);
+        ATRACE_END();
+
         if (!uuid) {
             ATRACE_BEGIN("profile");
             auto userProfilePath = create_primary_cur_profile_dir_path(userId);
@@ -2539,6 +2830,9 @@
         auto obbPath = StringPrintf("%s/Android/obb",
                 create_data_media_path(uuid_, userId).c_str());
         calculate_tree_size(obbPath, &obbSize);
+        if (!(flags & FLAG_USE_QUOTA)) {
+            totalSize -= obbSize;
+        }
         ATRACE_END();
     }
 
@@ -2921,6 +3215,49 @@
     return res;
 }
 
+binder::Status InstalldNativeService::restoreconSdkDataLocked(
+        const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+        int32_t flags, int32_t appId, const std::string& seInfo) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+
+    binder::Status res = ok();
+
+    // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here.
+    unsigned int seflags = SELINUX_ANDROID_RESTORECON_RECURSE;
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    const char* pkgName = packageName.c_str();
+    const char* seinfo = seInfo.c_str();
+
+    uid_t uid = multiuser_get_sdk_sandbox_uid(userId, appId);
+    constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+    for (int currentFlag : storageFlags) {
+        if ((flags & currentFlag) == 0) {
+            continue;
+        }
+        const bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+        const auto packagePath =
+                create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId, pkgName);
+        if (access(packagePath.c_str(), F_OK) != 0) {
+            LOG(INFO) << "Missing source " << packagePath;
+            continue;
+        }
+        const auto subDirHandler = [&packagePath, &seinfo, &uid, &seflags,
+                                    &res](const std::string& subDir) {
+            const auto& fullpath = packagePath + "/" + subDir;
+            if (selinux_android_restorecon_pkgdir(fullpath.c_str(), seinfo, uid, seflags) < 0) {
+                res = error("restorecon failed for " + fullpath);
+            }
+        };
+        const auto ec = foreach_subdir(packagePath, subDirHandler);
+        if (ec != 0) {
+            res = error("Failed to restorecon for subdirs of " + packagePath);
+        }
+    }
+    return res;
+}
+
 binder::Status InstalldNativeService::createOatDir(const std::string& oatDir,
         const std::string& instructionSet) {
     ENFORCE_UID(AID_SYSTEM);
@@ -3055,6 +3392,33 @@
     return result ? ok() : error();
 }
 
+bool check_if_ioctl_feature_is_supported() {
+    bool result = false;
+    auto temp_path = StringPrintf("%smisc/installd/ioctl_check", android_data_dir.c_str());
+    if (access(temp_path.c_str(), F_OK) != 0) {
+        open(temp_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
+        result = set_quota_project_id(temp_path, 0, false) == 0;
+        // delete the temp file
+        // remove the external file
+        remove(temp_path.c_str());
+    }
+    return result;
+}
+
+binder::Status InstalldNativeService::setFirstBoot() {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+    std::string uuid;
+    if (GetOccupiedSpaceForProjectId(uuid, 0) != -1 && check_if_ioctl_feature_is_supported()) {
+        auto first_boot_path =
+                StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+        if (access(first_boot_path.c_str(), F_OK) != 0) {
+            open(first_boot_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
+        }
+    }
+    return ok();
+}
+
 binder::Status InstalldNativeService::invalidateMounts() {
     ENFORCE_UID(AID_SYSTEM);
     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
@@ -3141,10 +3505,10 @@
         return error("Failed to stat " + mirrorVolCePath);
     }
 
-    if (mirrorCeStat.st_ino == ceStat.st_ino) {
+    if (mirrorCeStat.st_ino == ceStat.st_ino && mirrorCeStat.st_dev == ceStat.st_dev) {
         // As it's being called by prepareUserStorage, it can be called multiple times.
         // Hence, we if we mount it already, we should skip it.
-        LOG(WARNING) << "CE dir is mounted already: " + cePath;
+        LOG(INFO) << "CE dir is mounted already: " + cePath;
         return ok();
     }
 
@@ -3258,11 +3622,17 @@
     if (flags & FLAG_STORAGE_CE) {
         auto ce_path = create_data_user_ce_path(uuid_cstr, userId);
         cleanup_invalid_package_dirs_under_path(ce_path);
+        auto sdksandbox_ce_path =
+                create_data_misc_sdk_sandbox_path(uuid_cstr, /*isCeData=*/true, userId);
+        cleanup_invalid_package_dirs_under_path(sdksandbox_ce_path);
     }
 
     if (flags & FLAG_STORAGE_DE) {
         auto de_path = create_data_user_de_path(uuid_cstr, userId);
         cleanup_invalid_package_dirs_under_path(de_path);
+        auto sdksandbox_de_path =
+                create_data_misc_sdk_sandbox_path(uuid_cstr, /*isCeData=*/false, userId);
+        cleanup_invalid_package_dirs_under_path(sdksandbox_de_path);
     }
 
     return ok();
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index b2bad1d..95ac516 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -58,12 +58,12 @@
             const std::vector<android::os::CreateAppDataArgs>& args,
             std::vector<android::os::CreateAppDataResult>* _aidl_return);
 
+    binder::Status reconcileSdkData(const android::os::ReconcileSdkDataArgs& args);
+
     binder::Status restoreconAppData(const std::optional<std::string>& uuid,
             const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
             const std::string& seInfo);
-    binder::Status restoreconAppDataLocked(const std::optional<std::string>& uuid,
-                                           const std::string& packageName, int32_t userId,
-                                           int32_t flags, int32_t appId, const std::string& seInfo);
+
     binder::Status migrateAppData(const std::optional<std::string>& uuid,
             const std::string& packageName, int32_t userId, int32_t flags);
     binder::Status clearAppData(const std::optional<std::string>& uuid,
@@ -167,6 +167,7 @@
         int32_t storageFlag, std::vector<uint8_t>* _aidl_return);
 
     binder::Status invalidateMounts();
+    binder::Status setFirstBoot();
     binder::Status isQuotaSupported(const std::optional<std::string>& volumeUuid,
             bool* _aidl_return);
     binder::Status tryMountDataMirror(const std::optional<std::string>& volumeUuid);
@@ -203,11 +204,28 @@
                                        int32_t flags, int32_t appId, int32_t previousAppId,
                                        const std::string& seInfo, int32_t targetSdkVersion,
                                        int64_t* _aidl_return);
+    binder::Status restoreconAppDataLocked(const std::optional<std::string>& uuid,
+                                           const std::string& packageName, int32_t userId,
+                                           int32_t flags, int32_t appId, const std::string& seInfo);
 
-    binder::Status createSdkSandboxDataDirectory(const std::optional<std::string>& uuid,
-                                                 const std::string& packageName, int32_t userId,
-                                                 int32_t appId, int32_t previousAppId,
-                                                 const std::string& seInfo, int32_t flags);
+    binder::Status createSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
+                                                        const std::string& packageName,
+                                                        int32_t userId, int32_t appId,
+                                                        int32_t flags);
+    binder::Status clearSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
+                                                       const std::string& packageName,
+                                                       int32_t userId, int32_t flags);
+    binder::Status destroySdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
+                                                         const std::string& packageName,
+                                                         int32_t userId, int32_t flags);
+    binder::Status reconcileSdkData(const std::optional<std::string>& uuid,
+                                    const std::string& packageName,
+                                    const std::vector<std::string>& subDirNames, int32_t userId,
+                                    int32_t appId, int32_t previousAppId, const std::string& seInfo,
+                                    int flags);
+    binder::Status restoreconSdkDataLocked(const std::optional<std::string>& uuid,
+                                           const std::string& packageName, int32_t userId,
+                                           int32_t flags, int32_t appId, const std::string& seInfo);
 };
 
 }  // namespace installd
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index 3f0fb6d..fc4cfc9 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -30,6 +30,14 @@
     },
     {
       "name": "CtsCompilationTestCases"
+    },
+    {
+      "name": "SdkSandboxStorageHostTest",
+      "options": [
+        {
+          "exclude-annotation": "android.platform.test.annotations.LargeTest"
+        }
+      ]
     }
   ]
 }
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index f4fd9a9..c17c6bf 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -20,10 +20,12 @@
 interface IInstalld {
     void createUserData(@nullable @utf8InCpp String uuid, int userId, int userSerial, int flags);
     void destroyUserData(@nullable @utf8InCpp String uuid, int userId, int flags);
-
+    void setFirstBoot();
     android.os.CreateAppDataResult createAppData(in android.os.CreateAppDataArgs args);
     android.os.CreateAppDataResult[] createAppDataBatched(in android.os.CreateAppDataArgs[] args);
 
+    void reconcileSdkData(in android.os.ReconcileSdkDataArgs args);
+
     void restoreconAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
             int userId, int flags, int appId, @utf8InCpp String seInfo);
     void migrateAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
@@ -131,6 +133,7 @@
     const int FLAG_STORAGE_DE = 0x1;
     const int FLAG_STORAGE_CE = 0x2;
     const int FLAG_STORAGE_EXTERNAL = 0x4;
+    const int FLAG_STORAGE_SDK = 0x8;
 
     const int FLAG_CLEAR_CACHE_ONLY = 0x10;
     const int FLAG_CLEAR_CODE_CACHE_ONLY = 0x20;
diff --git a/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl b/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl
new file mode 100644
index 0000000..583a36d
--- /dev/null
+++ b/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/** {@hide} */
+parcelable ReconcileSdkDataArgs {
+    @nullable @utf8InCpp String uuid;
+    @utf8InCpp String packageName;
+    @utf8InCpp List<String> subDirNames;
+    int userId;
+    int appId;
+    int previousAppId;
+    @utf8InCpp String seInfo;
+    int flags;
+}
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index e390bab..07f73b9 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -11,7 +11,6 @@
 cc_test {
     name: "installd_utils_test",
     test_suites: ["device-tests"],
-    clang: true,
     srcs: ["installd_utils_test.cpp"],
     cflags: [
         "-Wall",
@@ -26,6 +25,7 @@
         "libasync_safe",
         "libdiskusage",
         "libext2_uuid",
+        "libgmock",
         "libinstalld",
         "liblog",
     ],
@@ -35,7 +35,6 @@
 cc_test {
     name: "installd_cache_test",
     test_suites: ["device-tests"],
-    clang: true,
     srcs: ["installd_cache_test.cpp"],
     cflags: [
         "-Wall",
@@ -81,7 +80,6 @@
 cc_test {
     name: "installd_service_test",
     test_suites: ["device-tests"],
-    clang: true,
     srcs: ["installd_service_test.cpp"],
     cflags: [
         "-Wall",
@@ -106,6 +104,7 @@
         "libziparchive",
         "liblog",
         "liblogwrap",
+        "libc++fs",
     ],
     test_config: "installd_service_test.xml",
 
@@ -128,7 +127,6 @@
 cc_test {
     name: "installd_dexopt_test",
     test_suites: ["device-tests"],
-    clang: true,
     srcs: ["installd_dexopt_test.cpp"],
     cflags: [
         "-Wall",
@@ -175,7 +173,6 @@
 cc_test {
     name: "installd_otapreopt_test",
     test_suites: ["device-tests"],
-    clang: true,
     srcs: ["installd_otapreopt_test.cpp"],
     cflags: [
         "-Wall",
@@ -196,7 +193,6 @@
 cc_test {
     name: "installd_file_test",
     test_suites: ["device-tests"],
-    clang: true,
     srcs: ["installd_file_test.cpp"],
     cflags: [
         "-Wall",
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index aeba451..800e141 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -879,6 +879,11 @@
 
 TEST_F(DexoptTest, DexoptDex2oat64Enabled) {
     LOG(INFO) << "DexoptDex2oat64Enabled";
+    std::string zygote_prop = android::base::GetProperty("ro.zygote", "");
+    ASSERT_GT(zygote_prop.size(), 0);
+    if (zygote_prop != "zygote32_64" && zygote_prop != "zygote64_32") {
+        GTEST_SKIP() << "DexoptDex2oat64Enabled skipped for single-bitness Zygote.";
+    }
     const std::string property = "dalvik.vm.dex2oat64.enabled";
     const std::string previous_value = android::base::GetProperty(property, "");
     auto restore_property = android::base::make_scope_guard([=]() {
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 21ab5b8..effb401 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -32,16 +32,20 @@
 #include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
+#include <filesystem>
+#include <fstream>
 
 #include <android/content/pm/IPackageManagerNative.h>
 #include <binder/IServiceManager.h>
 #include "InstalldNativeService.h"
+#include "binder/Status.h"
 #include "binder_test_utils.h"
 #include "dexopt.h"
 #include "globals.h"
 #include "utils.h"
 
 using android::base::StringPrintf;
+using std::filesystem::is_empty;
 
 namespace android {
 std::string get_package_name(uid_t uid) {
@@ -75,12 +79,18 @@
 namespace installd {
 
 static constexpr const char* kTestUuid = "TEST";
-static constexpr const char* kTestPath = "/data/local/tmp/user/0";
+static const std::string kTestPath = "/data/local/tmp";
+static constexpr const uid_t kNobodyUid = 9999;
 static constexpr const uid_t kSystemUid = 1000;
 static constexpr const int32_t kTestUserId = 0;
 static constexpr const uid_t kTestAppId = 19999;
+static constexpr const int FLAG_STORAGE_SDK = InstalldNativeService::FLAG_STORAGE_SDK;
+static constexpr const int FLAG_CLEAR_CACHE_ONLY = InstalldNativeService::FLAG_CLEAR_CACHE_ONLY;
+static constexpr const int FLAG_CLEAR_CODE_CACHE_ONLY =
+        InstalldNativeService::FLAG_CLEAR_CODE_CACHE_ONLY;
 
 const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId);
+const gid_t kTestCacheGid = multiuser_get_cache_gid(kTestUserId, kTestAppId);
 const uid_t kTestSdkSandboxUid = multiuser_get_sdk_sandbox_uid(kTestUserId, kTestAppId);
 
 #define FLAG_FORCE InstalldNativeService::FLAG_FORCE
@@ -103,18 +113,18 @@
     return create_cache_path_default(path, src, instruction_set);
 }
 
-static std::string get_full_path(const char* path) {
-    return StringPrintf("%s/%s", kTestPath, path);
+static std::string get_full_path(const std::string& path) {
+    return StringPrintf("%s/%s", kTestPath.c_str(), path.c_str());
 }
 
-static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
+static void mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
     const std::string fullPath = get_full_path(path);
     EXPECT_EQ(::mkdir(fullPath.c_str(), mode), 0);
     EXPECT_EQ(::chown(fullPath.c_str(), owner, group), 0);
     EXPECT_EQ(::chmod(fullPath.c_str(), mode), 0);
 }
 
-static int create(const char* path, uid_t owner, gid_t group, mode_t mode) {
+static int create(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
     int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
     EXPECT_NE(fd, -1);
     EXPECT_EQ(::fchown(fd, owner, group), 0);
@@ -122,8 +132,8 @@
     return fd;
 }
 
-static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
-    EXPECT_EQ(::close(create(path, owner, group, mode)), 0);
+static void touch(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
+    EXPECT_EQ(::close(create(path.c_str(), owner, group, mode)), 0);
 }
 
 static int stat_gid(const char* path) {
@@ -138,7 +148,7 @@
     return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
 }
 
-static bool exists(const char* path) {
+static bool exists(const std::string& path) {
     return ::access(get_full_path(path).c_str(), F_OK) == 0;
 }
 
@@ -161,8 +171,8 @@
     return result;
 }
 
-static bool exists_renamed_deleted_dir() {
-    return find_file(kTestPath, [](const std::string& name, bool is_dir) {
+static bool exists_renamed_deleted_dir(const std::string& rootDirectory) {
+    return find_file((kTestPath + rootDirectory).c_str(), [](const std::string& name, bool is_dir) {
         return is_dir && is_renamed_deleted_dir(name);
     });
 }
@@ -179,197 +189,205 @@
         service = new InstalldNativeService();
         testUuid = kTestUuid;
         system("rm -rf /data/local/tmp/user");
+        system("rm -rf /data/local/tmp/misc_ce");
+        system("rm -rf /data/local/tmp/misc_de");
         system("mkdir -p /data/local/tmp/user/0");
-
+        system("mkdir -p /data/local/tmp/misc_ce/0/sdksandbox");
+        system("mkdir -p /data/local/tmp/misc_de/0/sdksandbox");
         init_globals_from_data_and_root();
     }
 
     virtual void TearDown() {
         delete service;
         system("rm -rf /data/local/tmp/user");
+        system("rm -rf /data/local/tmp/misc_ce");
+        system("rm -rf /data/local/tmp/misc_de");
     }
 };
 
 TEST_F(ServiceTest, FixupAppData_Upgrade) {
     LOG(INFO) << "FixupAppData_Upgrade";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/normal", 10000, 10000, 0700);
-    mkdir("com.example/cache", 10000, 10000, 0700);
-    touch("com.example/cache/file", 10000, 10000, 0700);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/normal", 10000, 10000, 0700);
+    mkdir("user/0/com.example/cache", 10000, 10000, 0700);
+    touch("user/0/com.example/cache/file", 10000, 10000, 0700);
 
     service->fixupAppData(testUuid, 0);
 
-    EXPECT_EQ(10000, stat_gid("com.example/normal"));
-    EXPECT_EQ(20000, stat_gid("com.example/cache"));
-    EXPECT_EQ(20000, stat_gid("com.example/cache/file"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/normal"));
+    EXPECT_EQ(20000, stat_gid("user/0/com.example/cache"));
+    EXPECT_EQ(20000, stat_gid("user/0/com.example/cache/file"));
 
-    EXPECT_EQ(0700, stat_mode("com.example/normal"));
-    EXPECT_EQ(02771, stat_mode("com.example/cache"));
-    EXPECT_EQ(0700, stat_mode("com.example/cache/file"));
+    EXPECT_EQ(0700, stat_mode("user/0/com.example/normal"));
+    EXPECT_EQ(02771, stat_mode("user/0/com.example/cache"));
+    EXPECT_EQ(0700, stat_mode("user/0/com.example/cache/file"));
 }
 
 TEST_F(ServiceTest, FixupAppData_Moved) {
     LOG(INFO) << "FixupAppData_Moved";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0700);
-    mkdir("com.example/bar", 10000, 20000, 0700);
-    touch("com.example/bar/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+    touch("user/0/com.example/foo/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example/bar", 10000, 20000, 0700);
+    touch("user/0/com.example/bar/file", 10000, 20000, 0700);
 
     service->fixupAppData(testUuid, 0);
 
-    EXPECT_EQ(10000, stat_gid("com.example/foo"));
-    EXPECT_EQ(20000, stat_gid("com.example/foo/file"));
-    EXPECT_EQ(10000, stat_gid("com.example/bar"));
-    EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/foo"));
+    EXPECT_EQ(20000, stat_gid("user/0/com.example/foo/file"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/bar"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/bar/file"));
 
     service->fixupAppData(testUuid, FLAG_FORCE);
 
-    EXPECT_EQ(10000, stat_gid("com.example/foo"));
-    EXPECT_EQ(10000, stat_gid("com.example/foo/file"));
-    EXPECT_EQ(10000, stat_gid("com.example/bar"));
-    EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/foo"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/foo/file"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/bar"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/bar/file"));
 }
 
 TEST_F(ServiceTest, DestroyUserData) {
     LOG(INFO) << "DestroyUserData";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0700);
-    mkdir("com.example/bar", 10000, 20000, 0700);
-    touch("com.example/bar/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+    touch("user/0/com.example/foo/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example/bar", 10000, 20000, 0700);
+    touch("user/0/com.example/bar/file", 10000, 20000, 0700);
 
-    EXPECT_TRUE(exists("com.example/foo"));
-    EXPECT_TRUE(exists("com.example/foo/file"));
-    EXPECT_TRUE(exists("com.example/bar"));
-    EXPECT_TRUE(exists("com.example/bar/file"));
+    EXPECT_TRUE(exists("user/0/com.example/foo"));
+    EXPECT_TRUE(exists("user/0/com.example/foo/file"));
+    EXPECT_TRUE(exists("user/0/com.example/bar"));
+    EXPECT_TRUE(exists("user/0/com.example/bar/file"));
 
     service->destroyUserData(testUuid, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE);
 
-    EXPECT_FALSE(exists("com.example/foo"));
-    EXPECT_FALSE(exists("com.example/foo/file"));
-    EXPECT_FALSE(exists("com.example/bar"));
-    EXPECT_FALSE(exists("com.example/bar/file"));
+    EXPECT_FALSE(exists("user/0/com.example/foo"));
+    EXPECT_FALSE(exists("user/0/com.example/foo/file"));
+    EXPECT_FALSE(exists("user/0/com.example/bar"));
+    EXPECT_FALSE(exists("user/0/com.example/bar/file"));
 
-    EXPECT_FALSE(exists_renamed_deleted_dir());
+    EXPECT_FALSE(exists_renamed_deleted_dir("/user/0"));
 }
 
 TEST_F(ServiceTest, DestroyAppData) {
     LOG(INFO) << "DestroyAppData";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0700);
-    mkdir("com.example/bar", 10000, 20000, 0700);
-    touch("com.example/bar/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+    touch("user/0/com.example/foo/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example/bar", 10000, 20000, 0700);
+    touch("user/0/com.example/bar/file", 10000, 20000, 0700);
 
-    EXPECT_TRUE(exists("com.example/foo"));
-    EXPECT_TRUE(exists("com.example/foo/file"));
-    EXPECT_TRUE(exists("com.example/bar"));
-    EXPECT_TRUE(exists("com.example/bar/file"));
+    EXPECT_TRUE(exists("user/0/com.example/foo"));
+    EXPECT_TRUE(exists("user/0/com.example/foo/file"));
+    EXPECT_TRUE(exists("user/0/com.example/bar"));
+    EXPECT_TRUE(exists("user/0/com.example/bar/file"));
 
     service->destroyAppData(testUuid, "com.example", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, 0);
 
-    EXPECT_FALSE(exists("com.example/foo"));
-    EXPECT_FALSE(exists("com.example/foo/file"));
-    EXPECT_FALSE(exists("com.example/bar"));
-    EXPECT_FALSE(exists("com.example/bar/file"));
+    EXPECT_FALSE(exists("user/0/com.example/foo"));
+    EXPECT_FALSE(exists("user/0/com.example/foo/file"));
+    EXPECT_FALSE(exists("user/0/com.example/bar"));
+    EXPECT_FALSE(exists("user/0/com.example/bar/file"));
 
-    EXPECT_FALSE(exists_renamed_deleted_dir());
+    EXPECT_FALSE(exists_renamed_deleted_dir("/user/0"));
 }
 
 TEST_F(ServiceTest, CleanupInvalidPackageDirs) {
     LOG(INFO) << "CleanupInvalidPackageDirs";
 
-    mkdir("5b14b6458a44==deleted==", 10000, 10000, 0700);
-    mkdir("5b14b6458a44==deleted==/foo", 10000, 10000, 0700);
-    touch("5b14b6458a44==deleted==/foo/file", 10000, 20000, 0700);
-    mkdir("5b14b6458a44==deleted==/bar", 10000, 20000, 0700);
-    touch("5b14b6458a44==deleted==/bar/file", 10000, 20000, 0700);
+    std::string rootDirectoryPrefix[] = {"user/0", "misc_ce/0/sdksandbox", "misc_de/0/sdksandbox"};
+    for (auto& prefix : rootDirectoryPrefix) {
+        mkdir(prefix + "/5b14b6458a44==deleted==", 10000, 10000, 0700);
+        mkdir(prefix + "/5b14b6458a44==deleted==/foo", 10000, 10000, 0700);
+        touch(prefix + "/5b14b6458a44==deleted==/foo/file", 10000, 20000, 0700);
+        mkdir(prefix + "/5b14b6458a44==deleted==/bar", 10000, 20000, 0700);
+        touch(prefix + "/5b14b6458a44==deleted==/bar/file", 10000, 20000, 0700);
 
-    auto fd = create("5b14b6458a44==deleted==/bar/opened_file", 10000, 20000, 0700);
+        auto fd = create(prefix + "/5b14b6458a44==deleted==/bar/opened_file", 10000, 20000, 0700);
 
-    mkdir("b14b6458a44NOTdeleted", 10000, 10000, 0700);
-    mkdir("b14b6458a44NOTdeleted/foo", 10000, 10000, 0700);
-    touch("b14b6458a44NOTdeleted/foo/file", 10000, 20000, 0700);
-    mkdir("b14b6458a44NOTdeleted/bar", 10000, 20000, 0700);
-    touch("b14b6458a44NOTdeleted/bar/file", 10000, 20000, 0700);
+        mkdir(prefix + "/b14b6458a44NOTdeleted", 10000, 10000, 0700);
+        mkdir(prefix + "/b14b6458a44NOTdeleted/foo", 10000, 10000, 0700);
+        touch(prefix + "/b14b6458a44NOTdeleted/foo/file", 10000, 20000, 0700);
+        mkdir(prefix + "/b14b6458a44NOTdeleted/bar", 10000, 20000, 0700);
+        touch(prefix + "/b14b6458a44NOTdeleted/bar/file", 10000, 20000, 0700);
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0700);
-    mkdir("com.example/bar", 10000, 20000, 0700);
-    touch("com.example/bar/file", 10000, 20000, 0700);
+        mkdir(prefix + "/com.example", 10000, 10000, 0700);
+        mkdir(prefix + "/com.example/foo", 10000, 10000, 0700);
+        touch(prefix + "/com.example/foo/file", 10000, 20000, 0700);
+        mkdir(prefix + "/com.example/bar", 10000, 20000, 0700);
+        touch(prefix + "/com.example/bar/file", 10000, 20000, 0700);
 
-    mkdir("==deleted==", 10000, 10000, 0700);
-    mkdir("==deleted==/foo", 10000, 10000, 0700);
-    touch("==deleted==/foo/file", 10000, 20000, 0700);
-    mkdir("==deleted==/bar", 10000, 20000, 0700);
-    touch("==deleted==/bar/file", 10000, 20000, 0700);
+        mkdir(prefix + "/==deleted==", 10000, 10000, 0700);
+        mkdir(prefix + "/==deleted==/foo", 10000, 10000, 0700);
+        touch(prefix + "/==deleted==/foo/file", 10000, 20000, 0700);
+        mkdir(prefix + "/==deleted==/bar", 10000, 20000, 0700);
+        touch(prefix + "/==deleted==/bar/file", 10000, 20000, 0700);
 
-    EXPECT_TRUE(exists("5b14b6458a44==deleted==/foo"));
-    EXPECT_TRUE(exists("5b14b6458a44==deleted==/foo/file"));
-    EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar"));
-    EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar/file"));
-    EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar/opened_file"));
+        EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/foo"));
+        EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/foo/file"));
+        EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/bar"));
+        EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/bar/file"));
+        EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/bar/opened_file"));
 
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo"));
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo/file"));
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar"));
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar/file"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo/file"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar/file"));
 
-    EXPECT_TRUE(exists("com.example/foo"));
-    EXPECT_TRUE(exists("com.example/foo/file"));
-    EXPECT_TRUE(exists("com.example/bar"));
-    EXPECT_TRUE(exists("com.example/bar/file"));
+        EXPECT_TRUE(exists(prefix + "/com.example/foo"));
+        EXPECT_TRUE(exists(prefix + "/com.example/foo/file"));
+        EXPECT_TRUE(exists(prefix + "/com.example/bar"));
+        EXPECT_TRUE(exists(prefix + "/com.example/bar/file"));
 
-    EXPECT_TRUE(exists("==deleted==/foo"));
-    EXPECT_TRUE(exists("==deleted==/foo/file"));
-    EXPECT_TRUE(exists("==deleted==/bar"));
-    EXPECT_TRUE(exists("==deleted==/bar/file"));
+        EXPECT_TRUE(exists(prefix + "/==deleted==/foo"));
+        EXPECT_TRUE(exists(prefix + "/==deleted==/foo/file"));
+        EXPECT_TRUE(exists(prefix + "/==deleted==/bar"));
+        EXPECT_TRUE(exists(prefix + "/==deleted==/bar/file"));
 
-    EXPECT_TRUE(exists_renamed_deleted_dir());
+        EXPECT_TRUE(exists_renamed_deleted_dir("/" + prefix));
 
-    service->cleanupInvalidPackageDirs(testUuid, 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE);
+        service->cleanupInvalidPackageDirs(testUuid, 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE);
 
-    EXPECT_EQ(::close(fd), 0);
+        EXPECT_EQ(::close(fd), 0);
 
-    EXPECT_FALSE(exists("5b14b6458a44==deleted==/foo"));
-    EXPECT_FALSE(exists("5b14b6458a44==deleted==/foo/file"));
-    EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar"));
-    EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar/file"));
-    EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar/opened_file"));
+        EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/foo"));
+        EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/foo/file"));
+        EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/bar"));
+        EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/bar/file"));
+        EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/bar/opened_file"));
 
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo"));
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo/file"));
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar"));
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar/file"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo/file"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar/file"));
 
-    EXPECT_TRUE(exists("com.example/foo"));
-    EXPECT_TRUE(exists("com.example/foo/file"));
-    EXPECT_TRUE(exists("com.example/bar"));
-    EXPECT_TRUE(exists("com.example/bar/file"));
+        EXPECT_TRUE(exists(prefix + "/com.example/foo"));
+        EXPECT_TRUE(exists(prefix + "/com.example/foo/file"));
+        EXPECT_TRUE(exists(prefix + "/com.example/bar"));
+        EXPECT_TRUE(exists(prefix + "/com.example/bar/file"));
 
-    EXPECT_FALSE(exists("==deleted==/foo"));
-    EXPECT_FALSE(exists("==deleted==/foo/file"));
-    EXPECT_FALSE(exists("==deleted==/bar"));
-    EXPECT_FALSE(exists("==deleted==/bar/file"));
+        EXPECT_FALSE(exists(prefix + "/==deleted==/foo"));
+        EXPECT_FALSE(exists(prefix + "/==deleted==/foo/file"));
+        EXPECT_FALSE(exists(prefix + "/==deleted==/bar"));
+        EXPECT_FALSE(exists(prefix + "/==deleted==/bar/file"));
 
-    EXPECT_FALSE(exists_renamed_deleted_dir());
+        EXPECT_FALSE(exists_renamed_deleted_dir(prefix));
+    }
 }
 
 TEST_F(ServiceTest, HashSecondaryDex) {
     LOG(INFO) << "HashSecondaryDex";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+    touch("user/0/com.example/foo/file", 10000, 20000, 0700);
 
     std::vector<uint8_t> result;
-    std::string dexPath = get_full_path("com.example/foo/file");
+    std::string dexPath = get_full_path("user/0/com.example/foo/file");
     EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
         dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
 
@@ -389,7 +407,7 @@
     LOG(INFO) << "HashSecondaryDex_NoSuch";
 
     std::vector<uint8_t> result;
-    std::string dexPath = get_full_path("com.example/foo/file");
+    std::string dexPath = get_full_path("user/0/com.example/foo/file");
     EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
         dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
 
@@ -399,12 +417,12 @@
 TEST_F(ServiceTest, HashSecondaryDex_Unreadable) {
     LOG(INFO) << "HashSecondaryDex_Unreadable";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0300);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+    touch("user/0/com.example/foo/file", 10000, 20000, 0300);
 
     std::vector<uint8_t> result;
-    std::string dexPath = get_full_path("com.example/foo/file");
+    std::string dexPath = get_full_path("user/0/com.example/foo/file");
     EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
         dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
 
@@ -414,12 +432,12 @@
 TEST_F(ServiceTest, HashSecondaryDex_WrongApp) {
     LOG(INFO) << "HashSecondaryDex_WrongApp";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+    touch("user/0/com.example/foo/file", 10000, 20000, 0700);
 
     std::vector<uint8_t> result;
-    std::string dexPath = get_full_path("com.example/foo/file");
+    std::string dexPath = get_full_path("user/0/com.example/foo/file");
     EXPECT_BINDER_FAIL(service->hashSecondaryDexFile(
         dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result));
 }
@@ -447,7 +465,7 @@
     EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
     EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
 }
-TEST_F(ServiceTest, GetAppSize) {
+TEST_F(ServiceTest, GetAppSizeManualForMedia) {
     struct stat s;
 
     std::string externalPicDir =
@@ -491,6 +509,100 @@
         system(removeCommand.c_str());
     }
 }
+// TEST_F(ServiceTest, GetAppSizeProjectID_UID) {
+//     struct stat s;
+//     std::string externalPicDir =
+//             StringPrintf("%s/Pictures", create_data_media_path(nullptr, 0).c_str());
+//     if (stat(externalPicDir.c_str(), &s) == 0) {
+//         // fetch the appId from the uid of the external storage owning app
+//         int32_t externalStorageAppId = multiuser_get_app_id(s.st_uid);
+//         // Fetch Package Name for the external storage owning app uid
+//         std::string pkg = get_package_name(s.st_uid);
+//
+//         std::vector<int64_t> externalStorageSize, externalStorageSizeAfterAddingCacheFile;
+//         std::vector<int64_t> ceDataInodes;
+//
+//         std::vector<std::string> codePaths;
+//         std::vector<std::string> packageNames;
+//         // set up parameters
+//         packageNames.push_back(pkg);
+//         ceDataInodes.push_back(0);
+//         // initialise the mounts
+//         service->invalidateMounts();
+//         auto using_project_ids =
+//                 StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+//         bool usingProjectIds = access(using_project_ids.c_str(), F_OK) == 0;
+//         if (!usingProjectIds) {
+//             service->setFirstBoot();
+//         }
+//
+//         if (access(using_project_ids.c_str(), F_OK) != 0) {
+//             // projectids is not used, so check that ioctl features should be absent
+//             auto temp_path = StringPrintf("%smisc/installd/ioctl_check",
+//             android_data_dir.c_str());
+//
+//             if (access(temp_path.c_str(), F_OK) != 0) {
+//                 open(temp_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
+//                 bool result = set_quota_project_id(temp_path, 0, false) == 0;
+//                 // delete the temp file
+//                 // remove the external file
+//                 remove(temp_path.c_str());
+//                 // since using_project_ids file is not present, so ioctl settings should be
+//                 absent
+//                 //  that is denoted by the result of setting project id flag as false
+//                 ASSERT_FALSE(result);
+//             }
+//         }
+//         // call the getAppSize to get the current size of the external storage owning app
+//         service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+//                             externalStorageAppId, ceDataInodes, codePaths, &externalStorageSize);
+//         // add a file with 20MB size to the external storage
+//         std::string externalStorageCacheDir =
+//                 StringPrintf("%s/%s/cache", create_data_user_ce_path(nullptr, 0).c_str(),
+//                              pkg.c_str());
+//         std::string cacheFileLocation =
+//                 StringPrintf("%s/%s", externalStorageCacheDir.c_str(), "External.jpg");
+//         std::string externalFileContentCommand =
+//                 StringPrintf("dd if=/dev/zero of=%s bs=1M count=20", cacheFileLocation.c_str());
+//         system(externalFileContentCommand.c_str());
+//         // call the getAppSize again to get the new size of the external storage owning app
+//         service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+//                             externalStorageAppId, ceDataInodes, codePaths,
+//                             &externalStorageSizeAfterAddingCacheFile);
+//         // check that the size of cache and data increases when cache file is added
+//         int64_t sizeDiffData = externalStorageSizeAfterAddingCacheFile[1] -
+//         externalStorageSize[1]; int64_t sizeDiffCache =
+//         externalStorageSizeAfterAddingCacheFile[2] - externalStorageSize[2];
+//         ASSERT_TRUE(sizeDiffData == sizeDiffCache);
+//         // remove the external file
+//         std::string removeCommand = StringPrintf("rm -f %s", cacheFileLocation.c_str());
+//         system(removeCommand.c_str());
+//         // remove the setFirstBoot setting
+//         std::string removeCommand2 = "rm -f /data/misc/installd/using_project_ids";
+//         system(removeCommand2.c_str());
+//         // Do now without project id
+//         std::vector<int64_t> sizeWithUID, sizeWithUIDAfterAddingCacheFile;
+//         // call the getAppSize to get the current size of the external storage owning app
+//         service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+//                             externalStorageAppId, ceDataInodes, codePaths, &sizeWithUID);
+//         // add a file with 20MB size to the external storage
+//         system(externalFileContentCommand.c_str());
+//         // call the getAppSize again to get the new size of the external storage owning app
+//         service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+//                             externalStorageAppId, ceDataInodes, codePaths,
+//                             &sizeWithUIDAfterAddingCacheFile);
+//         // check that the size of cache and data increases when cache file is added
+//         sizeDiffData = sizeWithUIDAfterAddingCacheFile[1] - sizeWithUID[1];
+//         sizeDiffCache = sizeWithUIDAfterAddingCacheFile[2] - sizeWithUID[2];
+//         ASSERT_TRUE(sizeDiffData == sizeDiffCache);
+//         // remove the external file
+//         system(removeCommand.c_str());
+//         // reset the using_project_id if it was initially set
+//         if (usingProjectIds) {
+//             service->setFirstBoot();
+//         }
+//     }
+// }
 TEST_F(ServiceTest, GetAppSizeWrongSizes) {
     int32_t externalStorageAppId = -1;
     std::vector<int64_t> externalStorageSize;
@@ -951,26 +1063,42 @@
 
 class SdkSandboxDataTest : public testing::Test {
 public:
-    void CheckFileAccess(const std::string& path, uid_t uid, mode_t mode) {
+    void CheckFileAccess(const std::string& path, uid_t uid, gid_t gid, mode_t mode) {
         const auto fullPath = "/data/local/tmp/" + path;
         ASSERT_TRUE(exists(fullPath.c_str())) << "For path: " << fullPath;
         struct stat st;
         ASSERT_EQ(0, stat(fullPath.c_str(), &st));
         ASSERT_EQ(uid, st.st_uid) << "For path: " << fullPath;
-        ASSERT_EQ(uid, st.st_gid) << "For path: " << fullPath;
+        ASSERT_EQ(gid, st.st_gid) << "For path: " << fullPath;
         ASSERT_EQ(mode, st.st_mode) << "For path: " << fullPath;
     }
 
     bool exists(const char* path) { return ::access(path, F_OK) == 0; }
 
     // Creates a default CreateAppDataArgs object
-    android::os::CreateAppDataArgs createAppDataArgs() {
+    android::os::CreateAppDataArgs createAppDataArgs(const std::string& packageName) {
         android::os::CreateAppDataArgs args;
         args.uuid = kTestUuid;
-        args.packageName = "com.foo";
+        args.packageName = packageName;
         args.userId = kTestUserId;
         args.appId = kTestAppId;
         args.seInfo = "default";
+        args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
+        return args;
+    }
+
+    android::os::ReconcileSdkDataArgs reconcileSdkDataArgs(
+            const std::string& packageName, const std::vector<std::string>& subDirNames) {
+        android::os::ReconcileSdkDataArgs args;
+        args.uuid = kTestUuid;
+        args.packageName = packageName;
+        for (const auto& subDirName : subDirNames) {
+            args.subDirNames.push_back(subDirName);
+        }
+        args.userId = kTestUserId;
+        args.appId = kTestAppId;
+        args.previousAppId = -1;
+        args.seInfo = "default";
         args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
         return args;
     }
@@ -999,58 +1127,72 @@
 
 private:
     void clearAppData() {
+        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user", true));
         ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true));
         ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_ce", true));
         ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_de", true));
-        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true));
     }
 };
 
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSupplementalAppData) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData) {
     android::os::CreateAppDataResult result;
-    android::os::CreateAppDataArgs args = createAppDataArgs();
-    args.packageName = "com.foo";
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+    const std::string fooCePath = "misc_ce/0/sdksandbox/com.foo";
+    CheckFileAccess(fooCePath, kSystemUid, kSystemUid, S_IFDIR | 0751);
+
+    const std::string fooDePath = "misc_de/0/sdksandbox/com.foo";
+    CheckFileAccess(fooDePath, kSystemUid, kSystemUid, S_IFDIR | 0751);
+}
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutSdkFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
     args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
 
     // Create the app user data.
     ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
 
-    CheckFileAccess("misc_ce/0/sdksandbox/com.foo", kSystemUid, S_IFDIR | 0751);
-    CheckFileAccess("misc_ce/0/sdksandbox/com.foo/shared", kTestSdkSandboxUid, S_IFDIR | 0700);
-    CheckFileAccess("misc_ce/0/sdksandbox/com.foo/shared/cache", kTestSdkSandboxUid,
-                    S_IFDIR | S_ISGID | 0771);
-    CheckFileAccess("misc_ce/0/sdksandbox/com.foo/shared/code_cache", kTestSdkSandboxUid,
-                    S_IFDIR | S_ISGID | 0771);
-
-    CheckFileAccess("misc_de/0/sdksandbox/com.foo", kSystemUid, S_IFDIR | 0751);
-    CheckFileAccess("misc_de/0/sdksandbox/com.foo/shared", kTestSdkSandboxUid, S_IFDIR | 0700);
-    CheckFileAccess("misc_de/0/sdksandbox/com.foo/shared/cache", kTestSdkSandboxUid,
-                    S_IFDIR | S_ISGID | 0771);
-    CheckFileAccess("misc_de/0/sdksandbox/com.foo/shared/code_cache", kTestSdkSandboxUid,
-                    S_IFDIR | S_ISGID | 0771);
+    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
 }
 
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSupplementalAppData_WithoutDeFlag) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutSdkFlagDeletesExisting) {
     android::os::CreateAppDataResult result;
-    android::os::CreateAppDataArgs args = createAppDataArgs();
-    args.packageName = "com.foo";
-    args.flags = FLAG_STORAGE_CE;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+    ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+
+    args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutDeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_SDK;
 
     // Create the app user data.
     ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
 
     // Only CE paths should exist
-    CheckFileAccess("misc_ce/0/sdksandbox/com.foo", kSystemUid, S_IFDIR | 0751);
+    CheckFileAccess("misc_ce/0/sdksandbox/com.foo", kSystemUid, kSystemUid, S_IFDIR | 0751);
 
     // DE paths should not exist
     ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
 }
 
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSupplementalAppData_WithoutCeFlag) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutCeFlag) {
     android::os::CreateAppDataResult result;
-    android::os::CreateAppDataArgs args = createAppDataArgs();
-    args.packageName = "com.foo";
-    args.flags = FLAG_STORAGE_DE;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.flags = FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
 
     // Create the app user data.
     ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
@@ -1059,7 +1201,223 @@
     ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
 
     // Only DE paths should exist
-    CheckFileAccess("misc_de/0/sdksandbox/com.foo", kSystemUid, S_IFDIR | 0751);
+    CheckFileAccess("misc_de/0/sdksandbox/com.foo", kSystemUid, kSystemUid, S_IFDIR | 0751);
+}
+
+TEST_F(SdkSandboxDataTest, ReconcileSdkData) {
+    android::os::ReconcileSdkDataArgs args =
+            reconcileSdkDataArgs("com.foo", {"bar@random1", "baz@random2"});
+
+    // Create the sdk data.
+    ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
+
+    const std::string barCePath = "misc_ce/0/sdksandbox/com.foo/bar@random1";
+    CheckFileAccess(barCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+    CheckFileAccess(barCePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+    CheckFileAccess(barCePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+
+    const std::string bazCePath = "misc_ce/0/sdksandbox/com.foo/baz@random2";
+    CheckFileAccess(bazCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+    CheckFileAccess(bazCePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+    CheckFileAccess(bazCePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+
+    const std::string barDePath = "misc_de/0/sdksandbox/com.foo/bar@random1";
+    CheckFileAccess(barDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+    CheckFileAccess(barDePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+    CheckFileAccess(barDePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+
+    const std::string bazDePath = "misc_de/0/sdksandbox/com.foo/baz@random2";
+    CheckFileAccess(bazDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+    CheckFileAccess(bazDePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+    CheckFileAccess(bazDePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+}
+
+TEST_F(SdkSandboxDataTest, ReconcileSdkData_ExtraCodeDirectoriesAreDeleted) {
+    android::os::ReconcileSdkDataArgs args =
+            reconcileSdkDataArgs("com.foo", {"bar@random1", "baz@random2"});
+
+    // Create the sdksandbox data.
+    ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
+
+    // Retry with different package name
+    args.subDirNames[0] = "bar.diff@random1";
+
+    // Create the sdksandbox data again
+    ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
+
+    // New directoris should exist
+    CheckFileAccess("misc_ce/0/sdksandbox/com.foo/bar.diff@random1", kTestSdkSandboxUid, kNobodyUid,
+                    S_IFDIR | S_ISGID | 0700);
+    CheckFileAccess("misc_ce/0/sdksandbox/com.foo/baz@random2", kTestSdkSandboxUid, kNobodyUid,
+                    S_IFDIR | S_ISGID | 0700);
+    // Directory for old unreferred sdksandbox package name should be removed
+    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/bar@random1"));
+}
+
+class DestroyAppDataTest : public SdkSandboxDataTest {};
+
+TEST_F(DestroyAppDataTest, DestroySdkSandboxDataDirectories_WithCeAndDeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.packageName = "com.foo";
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    // Destroy the app user data.
+    ASSERT_BINDER_SUCCESS(service->destroyAppData(args.uuid, args.packageName, args.userId,
+                                                  args.flags, result.ceDataInode));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+TEST_F(DestroyAppDataTest, DestroySdkSandboxDataDirectories_WithoutDeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.packageName = "com.foo";
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    // Destroy the app user data.
+    ASSERT_BINDER_SUCCESS(service->destroyAppData(args.uuid, args.packageName, args.userId,
+                                                  FLAG_STORAGE_CE, result.ceDataInode));
+    ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+}
+
+TEST_F(DestroyAppDataTest, DestroySdkSandboxDataDirectories_WithoutCeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.packageName = "com.foo";
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    // Destroy the app user data.
+    ASSERT_BINDER_SUCCESS(service->destroyAppData(args.uuid, args.packageName, args.userId,
+                                                  FLAG_STORAGE_DE, result.ceDataInode));
+    ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+class ClearAppDataTest : public SdkSandboxDataTest {
+public:
+    void createTestSdkData(const std::string& packageName, std::vector<std::string> sdkNames) {
+        const auto& cePackagePath = "/data/local/tmp/misc_ce/0/sdksandbox/" + packageName;
+        const auto& dePackagePath = "/data/local/tmp/misc_de/0/sdksandbox/" + packageName;
+        ASSERT_TRUE(mkdirs(cePackagePath, 0700));
+        ASSERT_TRUE(mkdirs(dePackagePath, 0700));
+        const std::vector<std::string> packagePaths = {cePackagePath, dePackagePath};
+        for (const auto& packagePath : packagePaths) {
+            for (auto sdkName : sdkNames) {
+                ASSERT_TRUE(mkdirs(packagePath + "/" + sdkName + "/cache", 0700));
+                ASSERT_TRUE(mkdirs(packagePath + "/" + sdkName + "/code_cache", 0700));
+                std::ofstream{packagePath + "/" + sdkName + "/cache/cachedTestData.txt"};
+                std::ofstream{packagePath + "/" + sdkName + "/code_cache/cachedTestData.txt"};
+            }
+        }
+    }
+};
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndClearCacheFlag) {
+    createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+    // Clear the app user data.
+    ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+                                                FLAG_STORAGE_CE | FLAG_CLEAR_CACHE_ONLY, -1));
+
+    const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+    ASSERT_TRUE(is_empty(packagePath + "/shared/cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk1/cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk2/cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndClearCodeCacheFlag) {
+    createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+    // Clear the app user data.
+    ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+                                                FLAG_STORAGE_CE | FLAG_CLEAR_CODE_CACHE_ONLY, -1));
+
+    const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+    ASSERT_TRUE(is_empty(packagePath + "/shared/code_cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk1/code_cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk2/code_cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndClearCacheFlag) {
+    createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+    // Clear the app user data
+    ASSERT_BINDER_SUCCESS(
+            service->clearAppData(kTestUuid, "com.foo", 0,
+                                  FLAG_STORAGE_DE | (InstalldNativeService::FLAG_CLEAR_CACHE_ONLY),
+                                  -1));
+
+    const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+    ASSERT_TRUE(is_empty(packagePath + "/shared/cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk1/cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk2/cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndClearCodeCacheFlag) {
+    createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+    // Clear the app user data.
+    ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+                                                FLAG_STORAGE_DE | FLAG_CLEAR_CODE_CACHE_ONLY, -1));
+
+    const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+    ASSERT_TRUE(is_empty(packagePath + "/shared/code_cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk1/code_cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk2/code_cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndWithoutAnyCacheFlag) {
+    createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+    // Clear the app user data.
+    ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0, FLAG_STORAGE_CE, -1));
+
+    const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+    ASSERT_TRUE(is_empty(packagePath + "/shared"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk1"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk2"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndWithoutAnyCacheFlag) {
+    createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+    // Clear the app user data.
+    ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0, FLAG_STORAGE_DE, -1));
+
+    const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+    ASSERT_TRUE(is_empty(packagePath + "/shared"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk1"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk2"));
+}
+
+class DestroyUserDataTest : public SdkSandboxDataTest {};
+
+TEST_F(DestroyUserDataTest, DestroySdkData_WithCeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.packageName = "com.foo";
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    // Destroy user data
+    ASSERT_BINDER_SUCCESS(service->destroyUserData(args.uuid, args.userId, FLAG_STORAGE_CE));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox"));
+    ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox"));
+}
+
+TEST_F(DestroyUserDataTest, DestroySdkData_WithDeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.packageName = "com.foo";
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    // Destroy user data
+    ASSERT_BINDER_SUCCESS(service->destroyUserData(args.uuid, args.userId, FLAG_STORAGE_DE));
+    ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox"));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox"));
 }
 
 }  // namespace installd
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 17802a3..910cd63 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -21,6 +21,7 @@
 
 #include <android-base/logging.h>
 #include <android-base/scopeguard.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include "InstalldNativeService.h"
@@ -47,6 +48,8 @@
 namespace android {
 namespace installd {
 
+using ::testing::UnorderedElementsAre;
+
 class UtilsTest : public testing::Test {
 protected:
     virtual void SetUp() {
@@ -658,6 +661,23 @@
     ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700));
 }
 
+TEST_F(UtilsTest, TestForEachSubdir) {
+    auto deleter = [&]() {
+        delete_dir_contents_and_dir("/data/local/tmp/user/0", true /* ignore_if_missing */);
+    };
+    auto scope_guard = android::base::make_scope_guard(deleter);
+
+    system("mkdir -p /data/local/tmp/user/0/com.foo");
+    system("mkdir -p /data/local/tmp/user/0/com.bar");
+    system("touch /data/local/tmp/user/0/some-file");
+
+    std::vector<std::string> result;
+    foreach_subdir("/data/local/tmp/user/0",
+                   [&](const std::string &filename) { result.push_back(filename); });
+
+    EXPECT_THAT(result, UnorderedElementsAre("com.foo", "com.bar"));
+}
+
 TEST_F(UtilsTest, TestSdkSandboxDataPaths) {
     // Ce data paths
     EXPECT_EQ("/data/misc_ce/0/sdksandbox",
@@ -670,9 +690,11 @@
               create_data_misc_sdk_sandbox_package_path(nullptr, true, 10, "com.foo"));
 
     EXPECT_EQ("/data/misc_ce/0/sdksandbox/com.foo/shared",
-              create_data_misc_sdk_sandbox_shared_path(nullptr, true, 0, "com.foo"));
+              create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 0, "com.foo", "shared"));
     EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo/shared",
-              create_data_misc_sdk_sandbox_shared_path(nullptr, true, 10, "com.foo"));
+              create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "shared"));
+    EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo/bar@random",
+              create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "bar@random"));
 
     // De data paths
     EXPECT_EQ("/data/misc_de/0/sdksandbox",
@@ -685,9 +707,11 @@
               create_data_misc_sdk_sandbox_package_path(nullptr, false, 10, "com.foo"));
 
     EXPECT_EQ("/data/misc_de/0/sdksandbox/com.foo/shared",
-              create_data_misc_sdk_sandbox_shared_path(nullptr, false, 0, "com.foo"));
+              create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 0, "com.foo", "shared"));
     EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo/shared",
-              create_data_misc_sdk_sandbox_shared_path(nullptr, false, 10, "com.foo"));
+              create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "shared"));
+    EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo/bar@random",
+              create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "bar@random"));
 }
 
 TEST_F(UtilsTest, WaitChild) {
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 992425d..c7bea3f 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -37,6 +37,7 @@
 #include <android-base/unique_fd.h>
 #include <cutils/fs.h>
 #include <cutils/properties.h>
+#include <linux/fs.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_projectid_config.h>
@@ -212,7 +213,7 @@
 
 /**
  * Create the path name where code data for all codes in a particular app will be stored.
- * E.g. /data/misc_ce/0/sdksandbox/<app-name>
+ * E.g. /data/misc_ce/0/sdksandbox/<package-name>
  */
 std::string create_data_misc_sdk_sandbox_package_path(const char* volume_uuid, bool isCeData,
                                                       userid_t user, const char* package_name) {
@@ -223,15 +224,17 @@
 }
 
 /**
- * Create the path name where shared code data for a particular app will be stored.
- * E.g. /data/misc_ce/0/sdksandbox/<app-name>/shared
+ * Create the path name where sdk data for a particular sdk will be stored.
+ * E.g. /data/misc_ce/0/sdksandbox/<package-name>/com.foo@randomstrings
  */
-std::string create_data_misc_sdk_sandbox_shared_path(const char* volume_uuid, bool isCeData,
-                                                     userid_t user, const char* package_name) {
-    return StringPrintf("%s/shared",
+std::string create_data_misc_sdk_sandbox_sdk_path(const char* volume_uuid, bool isCeData,
+                                                  userid_t user, const char* package_name,
+                                                  const char* sub_dir_name) {
+    return StringPrintf("%s/%s",
                         create_data_misc_sdk_sandbox_package_path(volume_uuid, isCeData, user,
                                                                   package_name)
-                                .c_str());
+                                .c_str(),
+                        sub_dir_name);
 }
 
 std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) {
@@ -421,7 +424,44 @@
 
     return users;
 }
+long get_project_id(uid_t uid, long start_project_id_range) {
+    return uid - AID_APP_START + start_project_id_range;
+}
 
+int set_quota_project_id(const std::string& path, long project_id, bool set_inherit) {
+    struct fsxattr fsx;
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+    if (fd == -1) {
+        PLOG(ERROR) << "Failed to open " << path << " to set project id.";
+        return -1;
+    }
+
+    if (ioctl(fd, FS_IOC_FSGETXATTR, &fsx) == -1) {
+        PLOG(ERROR) << "Failed to get extended attributes for " << path << " to get project id.";
+        return -1;
+    }
+
+    fsx.fsx_projid = project_id;
+    if (ioctl(fd, FS_IOC_FSSETXATTR, &fsx) == -1) {
+        PLOG(ERROR) << "Failed to set project id on " << path;
+        return -1;
+    }
+    if (set_inherit) {
+        unsigned int flags;
+        if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) {
+            PLOG(ERROR) << "Failed to get flags for " << path << " to set project id inheritance.";
+            return -1;
+        }
+
+        flags |= FS_PROJINHERIT_FL;
+
+        if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == -1) {
+            PLOG(ERROR) << "Failed to set flags for " << path << " to set project id inheritance.";
+            return -1;
+        }
+    }
+    return 0;
+}
 int calculate_tree_size(const std::string& path, int64_t* size,
         int32_t include_gid, int32_t exclude_gid, bool exclude_apps) {
     FTS *fts;
@@ -665,16 +705,16 @@
     auto temp_dir_path =
             base::StringPrintf("%s/%s", Dirname(pathname).c_str(), temp_dir_name.c_str());
 
-    if (::rename(pathname.c_str(), temp_dir_path.c_str())) {
+    auto dir_to_delete = temp_dir_path.c_str();
+    if (::rename(pathname.c_str(), dir_to_delete)) {
         if (ignore_if_missing && (errno == ENOENT)) {
             return 0;
         }
-        ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), temp_dir_path.c_str(),
-              strerror(errno));
-        return -errno;
+        ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), dir_to_delete, strerror(errno));
+        dir_to_delete = pathname.c_str();
     }
 
-    return delete_dir_contents(temp_dir_path.c_str(), 1, exclusion_predicate, ignore_if_missing);
+    return delete_dir_contents(dir_to_delete, 1, exclusion_predicate, ignore_if_missing);
 }
 
 bool is_renamed_deleted_dir(const std::string& path) {
@@ -696,6 +736,34 @@
     return std::unique_ptr<DIR, DirCloser>(::opendir(dir));
 }
 
+// Collects filename of subdirectories of given directory and passes it to the function
+int foreach_subdir(const std::string& pathname, const std::function<void(const std::string&)> fn) {
+    auto dir = open_dir(pathname.c_str());
+    if (!dir) return -1;
+
+    int dfd = dirfd(dir.get());
+    if (dfd < 0) {
+        ALOGE("Couldn't dirfd %s: %s\n", pathname.c_str(), strerror(errno));
+        return -1;
+    }
+
+    struct dirent* de;
+    while ((de = readdir(dir.get()))) {
+        if (de->d_type != DT_DIR) {
+            continue;
+        }
+
+        std::string name{de->d_name};
+        // always skip "." and ".."
+        if (name == "." || name == "..") {
+            continue;
+        }
+        fn(name);
+    }
+
+    return 0;
+}
+
 void cleanup_invalid_package_dirs_under_path(const std::string& pathname) {
     auto dir = open_dir(pathname.c_str());
     if (!dir) {
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 4b56f99..ecea1d2 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -32,6 +32,7 @@
 
 #define MEASURE_DEBUG 0
 #define FIXUP_DEBUG 0
+#define SDK_DEBUG 1
 
 #define BYPASS_QUOTA 0
 #define BYPASS_SDCARDFS 0
@@ -64,8 +65,9 @@
                                               userid_t userid);
 std::string create_data_misc_sdk_sandbox_package_path(const char* volume_uuid, bool isCeData,
                                                       userid_t userid, const char* package_name);
-std::string create_data_misc_sdk_sandbox_shared_path(const char* volume_uuid, bool isCeData,
-                                                     userid_t userid, const char* package_name);
+std::string create_data_misc_sdk_sandbox_sdk_path(const char* volume_uuid, bool isCeData,
+                                                  userid_t userid, const char* package_name,
+                                                  const char* sub_dir_name);
 
 std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user);
 std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user);
@@ -130,6 +132,8 @@
 bool is_renamed_deleted_dir(const std::string& path);
 int rename_delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = true);
 
+int foreach_subdir(const std::string& pathname, std::function<void(const std::string&)> fn);
+
 void cleanup_invalid_package_dirs_under_path(const std::string& pathname);
 
 int delete_dir_contents(const char *pathname,
@@ -167,6 +171,8 @@
         uid_t uid, gid_t gid);
 
 bool supports_sdcardfs();
+long get_project_id(uid_t uid, long start_project_id_range);
+int set_quota_project_id(const std::string& path, long project_id, bool set_inherit);
 int64_t get_occupied_app_space_external(const std::string& uuid, int32_t userId, int32_t appId);
 int64_t get_occupied_app_cache_space_external(const std::string& uuid, int32_t userId, int32_t appId);
 
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 555be1ed7..3cfe529 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -295,28 +295,27 @@
 Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
     auto ctx = mAccess->getCallingContext();
 
-    // apps cannot add services
     if (multiuser_get_app_id(ctx.uid) >= AID_APP) {
-        return Status::fromExceptionCode(Status::EX_SECURITY);
+        return Status::fromExceptionCode(Status::EX_SECURITY, "App UIDs cannot add services");
     }
 
     if (!mAccess->canAdd(ctx, name)) {
-        return Status::fromExceptionCode(Status::EX_SECURITY);
+        return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denial");
     }
 
     if (binder == nullptr) {
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Null binder");
     }
 
     if (!isValidServiceName(name)) {
         LOG(ERROR) << "Invalid service name: " << name;
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name");
     }
 
 #ifndef VENDORSERVICEMANAGER
     if (!meetsDeclarationRequirements(binder, name)) {
         // already logged
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "VINTF declaration error");
     }
 #endif  // !VENDORSERVICEMANAGER
 
@@ -324,7 +323,7 @@
     if (binder->remoteBinder() != nullptr &&
         binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
         LOG(ERROR) << "Could not linkToDeath when adding " << name;
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "linkToDeath failure");
     }
 
     // Overwrite the old service if it exists
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index c901c59..34d53a5 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -221,6 +221,12 @@
 }
 
 prebuilt_etc {
+    name: "android.software.opengles.deqp.level-2022-03-01.prebuilt.xml",
+    src: "android.software.opengles.deqp.level-2022-03-01.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
     name: "android.software.sip.voip.prebuilt.xml",
     src: "android.software.sip.voip.xml",
     defaults: ["frameworks_native_data_etc_defaults"],
@@ -239,6 +245,12 @@
 }
 
 prebuilt_etc {
+    name: "android.software.vulkan.deqp.level-2022-03-01.prebuilt.xml",
+    src: "android.software.vulkan.deqp.level-2022-03-01.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
     name: "aosp_excluded_hardware.prebuilt.xml",
     src: "aosp_excluded_hardware.xml",
     defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/data/etc/android.hardware.telephony.calling.xml b/data/etc/android.hardware.telephony.calling.xml
new file mode 100644
index 0000000..f47a00b
--- /dev/null
+++ b/data/etc/android.hardware.telephony.calling.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices to support telephony calling service related APIs -->
+<permissions>
+  <feature name="android.hardware.telephony.calling" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.data.xml b/data/etc/android.hardware.telephony.data.xml
new file mode 100644
index 0000000..897b16b
--- /dev/null
+++ b/data/etc/android.hardware.telephony.data.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices to support telephony data service related APIs -->
+<permissions>
+  <feature name="android.hardware.telephony.data" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.messaging.xml b/data/etc/android.hardware.telephony.messaging.xml
new file mode 100644
index 0000000..416c74f
--- /dev/null
+++ b/data/etc/android.hardware.telephony.messaging.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices to support telephony messaging service related APIs -->
+<permissions>
+  <feature name="android.hardware.telephony.messaging" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.radio.xml b/data/etc/android.hardware.telephony.radio.xml
new file mode 100644
index 0000000..69244b4
--- /dev/null
+++ b/data/etc/android.hardware.telephony.radio.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices to support telephony radio access related APIs -->
+<permissions>
+  <feature name="android.hardware.telephony.radio" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.subscription.xml b/data/etc/android.hardware.telephony.subscription.xml
new file mode 100644
index 0000000..5b3a3ee
--- /dev/null
+++ b/data/etc/android.hardware.telephony.subscription.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices to support telephony subscription APIs -->
+<permissions>
+  <feature name="android.hardware.telephony.subscription" />
+</permissions>
diff --git a/data/etc/android.software.telecom.xml b/data/etc/android.software.telecom.xml
new file mode 100644
index 0000000..db28ba6
--- /dev/null
+++ b/data/etc/android.software.telecom.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard set of features for devices that support the Telecom API. -->
+<permissions>
+    <feature name="android.software.telecom" />
+</permissions>
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index cc0ee82..95b8110 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -38,7 +38,7 @@
     <feature name="android.hardware.security.model.compatible" />
 
     <!-- basic system services -->
-    <feature name="android.software.connectionservice" />
+    <feature name="android.software.telecom" />
     <feature name="android.software.voice_recognizers" notLowRam="true" />
     <feature name="android.software.home_screen" />
     <feature name="android.software.companion_device_setup" />
diff --git a/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml
index e6db4ad..d601931 100644
--- a/data/etc/go_handheld_core_hardware.xml
+++ b/data/etc/go_handheld_core_hardware.xml
@@ -37,7 +37,7 @@
     <feature name="android.hardware.security.model.compatible" />
 
     <!-- basic system services -->
-    <feature name="android.software.connectionservice" />
+    <feature name="android.software.telecom" />
     <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
     <feature name="android.software.input_methods" />
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 41f1514..68b8def 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -42,7 +42,7 @@
 
     <!-- basic system services -->
     <feature name="android.software.app_widgets" />
-    <feature name="android.software.connectionservice" />
+    <feature name="android.software.telecom" />
     <feature name="android.software.voice_recognizers" notLowRam="true" />
     <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 4c83a14..ee392fc 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -235,7 +235,7 @@
  *
  * Available since API level 33.
  */
-int android_tag_socket_with_uid(int sockfd, int tag, uid_t uid) __INTRODUCED_IN(33);
+int android_tag_socket_with_uid(int sockfd, uint32_t tag, uid_t uid) __INTRODUCED_IN(33);
 
 /*
  * Set the socket tag for traffic statistics on the specified socket.
@@ -245,14 +245,26 @@
  * opened by another UID or was previously tagged by another UID. Subsequent
  * calls always replace any existing parameters. The socket tag is kept when the
  * socket is sent to another process using binder IPCs or other mechanisms such
- * as UNIX socket fd passing.
+ * as UNIX socket fd passing. The tag is a value defined by the caller and used
+ * together with uid for data traffic accounting, so that the function callers
+ * can account different types of data usage for a uid.
  *
  * Returns 0 on success, or a negative POSIX error code (see errno.h) on
  * failure.
  *
+ * Some possible error codes:
+ * -EBADF           Bad socketfd.
+ * -EPERM           No permission.
+ * -EAFNOSUPPORT    Socket family is neither AF_INET nor AF_INET6.
+ * -EPROTONOSUPPORT Socket protocol is neither IPPROTO_UDP nor IPPROTO_TCP.
+ * -EMFILE          Too many stats entries.
+ * There are still other error codes that may provided by -errno of
+ * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by
+ * BPF maps read/write sys calls, which are set appropriately.
+ *
  * Available since API level 33.
  */
-int android_tag_socket(int sockfd, int tag) __INTRODUCED_IN(33);
+int android_tag_socket(int sockfd, uint32_t tag) __INTRODUCED_IN(33);
 
 /*
  * Untag a network socket.
@@ -267,6 +279,12 @@
  * Returns 0 on success, or a negative POSIX error code (see errno.h) on
  * failure.
  *
+ * One of possible error code:
+ * -EBADF           Bad socketfd.
+ * Other error codes are either provided by -errno of
+ * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by
+ * BPF map element deletion sys call, which are set appropriately.
+ *
  * Available since API level 33.
  */
 int android_untag_socket(int sockfd) __INTRODUCED_IN(33);
diff --git a/include/android/storage_manager.h b/include/android/storage_manager.h
index 7f2ee08..270570e 100644
--- a/include/android/storage_manager.h
+++ b/include/android/storage_manager.h
@@ -124,6 +124,12 @@
 
 /**
  * Attempts to mount an OBB file. This is an asynchronous operation.
+ *
+ * Since API level 33, this function can only be used to mount unencrypted OBBs,
+ * i.e. the {@code key} parameter must be {@code null} or an empty string. Note
+ * that even before API level 33, mounting encrypted OBBs didn't work on many
+ * Android device implementations. Applications should not assume any particular
+ * behavior when {@code key} is nonempty.
  */
 void AStorageManager_mountObb(AStorageManager* mgr, const char* filename, const char* key,
         AStorageManager_obbCallbackFunc cb, void* data);
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 7f0324a..22b9faa 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -295,6 +295,8 @@
 /*
  * Gets the path of an input device configuration file, if one is available.
  * Considers both system provided and user installed configuration files.
+ * The optional suffix is appended to the end of the file name (before the
+ * extension).
  *
  * The device identifier is used to construct several default configuration file
  * names to try based on the device name, vendor, product, and version.
@@ -302,8 +304,8 @@
  * Returns an empty string if not found.
  */
 extern std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
-        const InputDeviceIdentifier& deviceIdentifier,
-        InputDeviceConfigurationFileType type);
+        const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type,
+        const char* suffix = "");
 
 /*
  * Gets the path of an input device configuration file, if one is available.
diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h
index b2bd535..1da78aa 100644
--- a/include/input/KeyLayoutMap.h
+++ b/include/input/KeyLayoutMap.h
@@ -20,9 +20,8 @@
 #include <android-base/result.h>
 #include <stdint.h>
 #include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
 #include <utils/Tokenizer.h>
+#include <set>
 
 #include <input/InputDevice.h>
 
@@ -65,18 +64,18 @@
  */
 class KeyLayoutMap {
 public:
-    static base::Result<std::shared_ptr<KeyLayoutMap>> load(const std::string& filename);
-    static base::Result<std::shared_ptr<KeyLayoutMap>> load(Tokenizer* tokenizer);
+    static base::Result<std::shared_ptr<KeyLayoutMap>> load(const std::string& filename,
+                                                            const char* contents = nullptr);
     static base::Result<std::shared_ptr<KeyLayoutMap>> loadContents(const std::string& filename,
                                                                     const char* contents);
 
     status_t mapKey(int32_t scanCode, int32_t usageCode,
             int32_t* outKeyCode, uint32_t* outFlags) const;
-    status_t findScanCodesForKey(int32_t keyCode, std::vector<int32_t>* outScanCodes) const;
-    status_t findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const;
-    status_t findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const;
+    std::vector<int32_t> findScanCodesForKey(int32_t keyCode) const;
+    std::optional<int32_t> findScanCodeForLed(int32_t ledCode) const;
+    std::optional<int32_t> findUsageCodeForLed(int32_t ledCode) const;
 
-    status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
+    std::optional<AxisInfo> mapAxis(int32_t scanCode) const;
     const std::string getLoadFileName() const;
     // Return pair of sensor type and sensor data index, for the input device abs code
     base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t absCode);
@@ -84,6 +83,8 @@
     virtual ~KeyLayoutMap();
 
 private:
+    static base::Result<std::shared_ptr<KeyLayoutMap>> load(Tokenizer* tokenizer);
+
     struct Key {
         int32_t keyCode;
         uint32_t flags;
@@ -98,12 +99,13 @@
         int32_t sensorDataIndex;
     };
 
-    KeyedVector<int32_t, Key> mKeysByScanCode;
-    KeyedVector<int32_t, Key> mKeysByUsageCode;
-    KeyedVector<int32_t, AxisInfo> mAxes;
-    KeyedVector<int32_t, Led> mLedsByScanCode;
-    KeyedVector<int32_t, Led> mLedsByUsageCode;
+    std::unordered_map<int32_t, Key> mKeysByScanCode;
+    std::unordered_map<int32_t, Key> mKeysByUsageCode;
+    std::unordered_map<int32_t, AxisInfo> mAxes;
+    std::unordered_map<int32_t, Led> mLedsByScanCode;
+    std::unordered_map<int32_t, Led> mLedsByUsageCode;
     std::unordered_map<int32_t, Sensor> mSensorsByAbsCode;
+    std::set<std::string> mRequiredKernelConfigs;
     std::string mLoadFileName;
 
     KeyLayoutMap();
@@ -124,6 +126,7 @@
         status_t parseAxis();
         status_t parseLed();
         status_t parseSensor();
+        status_t parseRequiredKernelConfig();
     };
 };
 
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index 08ad8c6..9a3e15f 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -61,9 +61,7 @@
     bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
     status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
     status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
-            const std::string& name);
-    std::string getPath(const InputDeviceIdentifier& deviceIdentifier,
-            const std::string& name, InputDeviceConfigurationFileType type);
+                                 const std::string& name);
 };
 
 /**
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index bb40f51..3c6769f 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -39,9 +39,16 @@
 
 cc_library_headers {
     name: "libarect_headers",
+    vendor_available: true,
+    min_sdk_version: "29",
     // TODO(b/153609531): remove when no longer needed.
     native_bridge_supported: true,
     export_include_dirs: ["include"],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media",
+        "com.android.media.swcodec",
+    ],
 }
 
 cc_library_static {
diff --git a/libs/attestation/Android.bp b/libs/attestation/Android.bp
index ea3c341..2bf15d4 100644
--- a/libs/attestation/Android.bp
+++ b/libs/attestation/Android.bp
@@ -28,11 +28,9 @@
         "-Werror",
     ],
     srcs: [
-        "HmacKeyManager.cpp"
+        "HmacKeyManager.cpp",
     ],
 
-    clang: true,
-
     shared_libs: [
         "liblog",
         "libcrypto",
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 63d87da..9389bec 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -60,11 +60,15 @@
 //
 // Currently, these are only on system android (not vendor, not host)
 // TODO(b/183654927) - move these into separate libraries
-libbinder_device_interface_sources = [
-    "IPermissionController.cpp",
-    "PermissionCache.cpp",
-    "PermissionController.cpp",
-]
+
+filegroup {
+    name: "libbinder_device_interface_sources",
+    srcs: [
+        "IPermissionController.cpp",
+        "PermissionCache.cpp",
+        "PermissionController.cpp",
+    ],
+}
 
 cc_library {
     name: "libbinder",
@@ -126,19 +130,20 @@
         "TextOutput.cpp",
         "Utils.cpp",
         ":libbinder_aidl",
+        ":libbinder_device_interface_sources",
     ],
 
     target: {
         android: {
-            srcs: libbinder_device_interface_sources,
-
             // NOT static to keep the wire protocol unfrozen
             static: {
                 enabled: false,
             },
         },
         vendor: {
-            exclude_srcs: libbinder_device_interface_sources,
+            exclude_srcs: [
+                ":libbinder_device_interface_sources",
+            ],
         },
         darwin: {
             enabled: false,
@@ -199,7 +204,6 @@
         "libbinder_headers",
     ],
 
-    clang: true,
     sanitize: {
         misc_undefined: ["integer"],
     },
@@ -217,6 +221,7 @@
         "abseil-*",
         "android-*",
         "bugprone-*",
+        "-bugprone-branch-clone", // b/155034972
         "cert-*",
         "clang-analyzer-*",
         "google-*",
@@ -366,6 +371,7 @@
 
 cc_library {
     name: "libbatterystats_aidl",
+    host_supported: true,
     srcs: [
         "IBatteryStats.cpp",
     ],
@@ -378,6 +384,7 @@
 
 cc_library {
     name: "libprocessinfoservice_aidl",
+    host_supported: true,
     srcs: [
         "IProcessInfoService.cpp",
         "ProcessInfoService.cpp",
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 01b25d3..e2db1a3 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -32,9 +32,12 @@
 #include <utils/misc.h>
 
 #include <inttypes.h>
-#include <linux/sched.h>
 #include <stdio.h>
 
+#ifdef __linux__
+#include <linux/sched.h>
+#endif
+
 #include "RpcState.h"
 
 namespace android {
@@ -49,10 +52,11 @@
 static_assert(sizeof(BBinder) == 20);
 #endif
 
+// global b/c b/230079120 - consistent symbol table
 #ifdef BINDER_RPC_DEV_SERVERS
-constexpr const bool kEnableRpcDevServers = true;
+bool kEnableRpcDevServers = true;
 #else
-constexpr const bool kEnableRpcDevServers = false;
+bool kEnableRpcDevServers = false;
 #endif
 
 // Log any reply transactions for which the data exceeds this size
@@ -156,7 +160,7 @@
 
 status_t IBinder::setRpcClientDebug(android::base::unique_fd socketFd,
                                     const sp<IBinder>& keepAliveBinder) {
-    if constexpr (!kEnableRpcDevServers) {
+    if (!kEnableRpcDevServers) {
         ALOGW("setRpcClientDebug disallowed because RPC is not enabled");
         return INVALID_OPERATION;
     }
@@ -201,6 +205,7 @@
     RpcServerLink(const sp<RpcServer>& rpcServer, const sp<IBinder>& keepAliveBinder,
                   const wp<BBinder>& binder)
           : mRpcServer(rpcServer), mKeepAliveBinder(keepAliveBinder), mBinder(binder) {}
+    virtual ~RpcServerLink();
     void binderDied(const wp<IBinder>&) override {
         LOG_RPC_DETAIL("RpcServerLink: binder died, shutting down RpcServer");
         if (mRpcServer == nullptr) {
@@ -226,16 +231,19 @@
     sp<IBinder> mKeepAliveBinder; // hold to avoid automatically unlinking
     wp<BBinder> mBinder;
 };
+BBinder::RpcServerLink::~RpcServerLink() {}
 
 class BBinder::Extras
 {
 public:
     // unlocked objects
-    bool mRequestingSid = false;
-    bool mInheritRt = false;
     sp<IBinder> mExtension;
+#ifdef __linux__
     int mPolicy = SCHED_NORMAL;
     int mPriority = 0;
+#endif
+    bool mRequestingSid = false;
+    bool mInheritRt = false;
 
     // for below objects
     Mutex mLock;
@@ -404,6 +412,7 @@
     return e->mExtension;
 }
 
+#ifdef __linux__
 void BBinder::setMinSchedulerPolicy(int policy, int priority) {
     LOG_ALWAYS_FATAL_IF(mParceled,
                         "setMinSchedulerPolicy() should not be called after a binder object "
@@ -448,6 +457,7 @@
     if (e == nullptr) return 0;
     return e->mPriority;
 }
+#endif // __linux__
 
 bool BBinder::isInheritRt() {
     Extras* e = mExtras.load(std::memory_order_acquire);
@@ -475,7 +485,12 @@
 }
 
 pid_t BBinder::getDebugPid() {
+#ifdef __linux__
     return getpid();
+#else
+    // TODO: handle other OSes
+    return 0;
+#endif // __linux__
 }
 
 void BBinder::setExtension(const sp<IBinder>& extension) {
@@ -496,7 +511,7 @@
 }
 
 status_t BBinder::setRpcClientDebug(const Parcel& data) {
-    if constexpr (!kEnableRpcDevServers) {
+    if (!kEnableRpcDevServers) {
         ALOGW("%s: disallowed because RPC is not enabled", __PRETTY_FUNCTION__);
         return INVALID_OPERATION;
     }
@@ -521,7 +536,7 @@
 
 status_t BBinder::setRpcClientDebug(android::base::unique_fd socketFd,
                                     const sp<IBinder>& keepAliveBinder) {
-    if constexpr (!kEnableRpcDevServers) {
+    if (!kEnableRpcDevServers) {
         ALOGW("%s: disallowed because RPC is not enabled", __PRETTY_FUNCTION__);
         return INVALID_OPERATION;
     }
@@ -539,7 +554,7 @@
         return UNEXPECTED_NULL;
     }
 
-    size_t binderThreadPoolMaxCount = ProcessState::self()->getThreadPoolMaxThreadCount();
+    size_t binderThreadPoolMaxCount = ProcessState::self()->getThreadPoolMaxTotalThreadCount();
     if (binderThreadPoolMaxCount <= 1) {
         ALOGE("%s: ProcessState thread pool max count is %zu. RPC is disabled for this service "
               "because RPC requires the service to support multithreading.",
@@ -582,6 +597,10 @@
 
 BBinder::~BBinder()
 {
+    if (!wasParceled() && getExtension()) {
+        ALOGW("Binder %p destroyed with extension attached before being parceled.", this);
+    }
+
     Extras* e = mExtras.load(std::memory_order_relaxed);
     if (e) delete e;
 }
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 921e57c..1eb2ffd 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -279,7 +279,7 @@
     if (mAlive) {
         bool privateVendor = flags & FLAG_PRIVATE_VENDOR;
         // don't send userspace flags to the kernel
-        flags = flags & ~FLAG_PRIVATE_VENDOR;
+        flags = flags & ~static_cast<uint32_t>(FLAG_PRIVATE_VENDOR);
 
         // user transactions require a given stability level
         if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
diff --git a/libs/binder/BufferedTextOutput.h b/libs/binder/BufferedTextOutput.h
index fdd532a..57e03cb 100644
--- a/libs/binder/BufferedTextOutput.h
+++ b/libs/binder/BufferedTextOutput.h
@@ -18,8 +18,8 @@
 #define ANDROID_BUFFEREDTEXTOUTPUT_H
 
 #include <binder/TextOutput.h>
-#include <utils/threads.h>
 #include <sys/uio.h>
+#include <utils/Mutex.h>
 
 // ---------------------------------------------------------------------------
 namespace android {
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index 9c7ff97..c6b0cb7 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -31,7 +31,7 @@
 #include <binder/Parcel.h>
 #include <log/log.h>
 
-#include <utils/threads.h>
+#include <utils/Mutex.h>
 
 #include <map>
 
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index f79075d..d536219 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -27,7 +27,6 @@
 #include <utils/CallStack.h>
 #include <utils/Log.h>
 #include <utils/SystemClock.h>
-#include <utils/threads.h>
 
 #include <atomic>
 #include <errno.h>
@@ -639,7 +638,9 @@
 void IPCThreadState::joinThreadPool(bool isMain)
 {
     LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
-
+    pthread_mutex_lock(&mProcess->mThreadCountLock);
+    mProcess->mCurrentThreads++;
+    pthread_mutex_unlock(&mProcess->mThreadCountLock);
     mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
 
     mIsLooper = true;
@@ -667,6 +668,13 @@
     mOut.writeInt32(BC_EXIT_LOOPER);
     mIsLooper = false;
     talkWithDriver(false);
+    pthread_mutex_lock(&mProcess->mThreadCountLock);
+    LOG_ALWAYS_FATAL_IF(mProcess->mCurrentThreads == 0,
+                        "Threadpool thread count = 0. Thread cannot exist and exit in empty "
+                        "threadpool\n"
+                        "Misconfiguration. Increase threadpool max threads configuration\n");
+    mProcess->mCurrentThreads--;
+    pthread_mutex_unlock(&mProcess->mThreadCountLock);
 }
 
 status_t IPCThreadState::setupPolling(int* fd)
@@ -678,6 +686,9 @@
     mOut.writeInt32(BC_ENTER_LOOPER);
     flushCommands();
     *fd = mProcess->mDriverFD;
+    pthread_mutex_lock(&mProcess->mThreadCountLock);
+    mProcess->mCurrentThreads++;
+    pthread_mutex_unlock(&mProcess->mThreadCountLock);
     return 0;
 }
 
@@ -990,6 +1001,7 @@
         if (acquireResult) *acquireResult = err;
         if (reply) reply->setError(err);
         mLastError = err;
+        logExtendedError();
     }
 
     return err;
@@ -1444,6 +1456,23 @@
     return ret;
 }
 
+void IPCThreadState::logExtendedError() {
+    struct binder_extended_error ee = {.command = BR_OK};
+
+    if (!ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::EXTENDED_ERROR))
+        return;
+
+#if defined(__ANDROID__)
+    if (ioctl(self()->mProcess->mDriverFD, BINDER_GET_EXTENDED_ERROR, &ee) < 0) {
+        ALOGE("Failed to get extended error: %s", strerror(errno));
+        return;
+    }
+#endif
+
+    ALOGE_IF(ee.command != BR_OK, "Binder transaction failure: %d/%d/%d",
+             ee.id, ee.command, ee.param);
+}
+
 void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data,
                                 size_t /*dataSize*/,
                                 const binder_size_t* /*objects*/,
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index ea2f8d2..fd47783 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -99,6 +99,8 @@
 
     status_t unregisterForNotifications(const String16& service,
                                         const sp<AidlRegistrationCallback>& cb) override;
+
+    std::vector<IServiceManager::ServiceDebugInfo> getServiceDebugInfo() override;
     // for legacy ABI
     const String16& getInterfaceDescriptor() const override {
         return mTheRealServiceManager->getInterfaceDescriptor();
@@ -165,7 +167,7 @@
     }
 }
 
-#if !defined(__ANDROID_VNDK__) && defined(__ANDROID__)
+#if !defined(__ANDROID_VNDK__)
 // IPermissionController is not accessible to vendors
 
 bool checkCallingPermission(const String16& permission)
@@ -543,6 +545,23 @@
     return OK;
 }
 
+std::vector<IServiceManager::ServiceDebugInfo> ServiceManagerShim::getServiceDebugInfo() {
+    std::vector<os::ServiceDebugInfo> serviceDebugInfos;
+    std::vector<IServiceManager::ServiceDebugInfo> ret;
+    if (Status status = mTheRealServiceManager->getServiceDebugInfo(&serviceDebugInfos);
+        !status.isOk()) {
+        ALOGW("%s Failed to get ServiceDebugInfo", __FUNCTION__);
+        return ret;
+    }
+    for (const auto& serviceDebugInfo : serviceDebugInfos) {
+        IServiceManager::ServiceDebugInfo retInfo;
+        retInfo.pid = serviceDebugInfo.debugPid;
+        retInfo.name = serviceDebugInfo.name;
+        ret.emplace_back(retInfo);
+    }
+    return ret;
+}
+
 #ifndef __ANDROID__
 // ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API.
 // The internal implementation of the AIDL interface android::os::IServiceManager calls into
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index c4475c7..03553f3 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -23,7 +23,6 @@
 #include <utils/Log.h>
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
-#include <utils/threads.h>
 
 #include <stdint.h>
 #include <stdio.h>
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index e1cbc19..8fe1d2b 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -18,10 +18,13 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/memfd.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <sys/stat.h>
+#include <sys/syscall.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -34,6 +37,24 @@
 
 // ---------------------------------------------------------------------------
 
+#ifdef __BIONIC__
+static int memfd_create_region(const char* name, size_t size) {
+    int fd = memfd_create(name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
+    if (fd == -1) {
+        ALOGE("%s: memfd_create(%s, %zd) failed: %s\n", __func__, name, size, strerror(errno));
+        return -1;
+    }
+
+    if (ftruncate(fd, size) == -1) {
+        ALOGE("%s, ftruncate(%s, %zd) failed for memfd creation: %s\n", __func__, name, size,
+              strerror(errno));
+        close(fd);
+        return -1;
+    }
+    return fd;
+}
+#endif
+
 MemoryHeapBase::MemoryHeapBase()
     : mFD(-1), mSize(0), mBase(MAP_FAILED),
       mDevice(nullptr), mNeedUnmap(false), mOffset(0)
@@ -45,15 +66,33 @@
       mDevice(nullptr), mNeedUnmap(false), mOffset(0)
 {
     const size_t pagesize = getpagesize();
-    size = ((size + pagesize-1) & ~(pagesize-1));
-    int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size);
-    ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
-    if (fd >= 0) {
-        if (mapfd(fd, true, size) == NO_ERROR) {
-            if (flags & READ_ONLY) {
-                ashmem_set_prot_region(fd, PROT_READ);
-            }
+    size = ((size + pagesize - 1) & ~(pagesize - 1));
+    int fd = -1;
+    if (mFlags & FORCE_MEMFD) {
+#ifdef __BIONIC__
+        ALOGV("MemoryHeapBase: Attempting to force MemFD");
+        fd = memfd_create_region(name ? name : "MemoryHeapBase", size);
+        if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
+        const int SEAL_FLAGS = ((mFlags & READ_ONLY) ? F_SEAL_FUTURE_WRITE : 0) |
+                ((mFlags & MEMFD_ALLOW_SEALING_FLAG) ? 0 : F_SEAL_SEAL);
+        if (SEAL_FLAGS && (fcntl(fd, F_ADD_SEALS, SEAL_FLAGS) == -1)) {
+            ALOGE("MemoryHeapBase: MemFD %s sealing with flags %x failed with error  %s", name,
+                  SEAL_FLAGS, strerror(errno));
+            munmap(mBase, mSize);
+            mBase = nullptr;
+            mSize = 0;
+            close(fd);
         }
+        return;
+#else
+        mFlags &= ~(FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG);
+#endif
+    }
+    fd = ashmem_create_region(name ? name : "MemoryHeapBase", size);
+    ALOGE_IF(fd < 0, "MemoryHeapBase: error creating ashmem region: %s", strerror(errno));
+    if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
+    if (mFlags & READ_ONLY) {
+        ashmem_set_prot_region(fd, PROT_READ);
     }
 }
 
@@ -61,6 +100,9 @@
     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
       mDevice(nullptr), mNeedUnmap(false), mOffset(0)
 {
+    if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG)) {
+        LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
+    }
     int open_flags = O_RDWR;
     if (flags & NO_CACHING)
         open_flags |= O_SYNC;
@@ -80,6 +122,9 @@
     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
       mDevice(nullptr), mNeedUnmap(false), mOffset(0)
 {
+    if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG)) {
+        LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
+    }
     const size_t pagesize = getpagesize();
     size = ((size + pagesize-1) & ~(pagesize-1));
     mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset);
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 504c6c2..8739105 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -40,6 +40,7 @@
 #include <binder/Status.h>
 #include <binder/TextOutput.h>
 
+#include <android-base/scopeguard.h>
 #include <cutils/ashmem.h>
 #include <cutils/compiler.h>
 #include <utils/Flattenable.h>
@@ -87,7 +88,8 @@
 static std::atomic<size_t> gParcelGlobalAllocCount;
 static std::atomic<size_t> gParcelGlobalAllocSize;
 
-static size_t gMaxFds = 0;
+// Maximum number of file descriptors per Parcel.
+constexpr size_t kMaxFds = 1024;
 
 // Maximum size of a blob to transfer in-place.
 static const size_t BLOB_INPLACE_LIMIT = 16 * 1024;
@@ -151,6 +153,14 @@
     ALOGE("Invalid object type 0x%08x", obj.hdr.type);
 }
 
+static int toRawFd(const std::variant<base::unique_fd, base::borrowed_fd>& v) {
+    return std::visit([](const auto& fd) { return fd.get(); }, v);
+}
+
+Parcel::RpcFields::RpcFields(const sp<RpcSession>& session) : mSession(session) {
+    LOG_ALWAYS_FATAL_IF(mSession == nullptr);
+}
+
 status_t Parcel::finishFlattenBinder(const sp<IBinder>& binder)
 {
     internal::Stability::tryMarkCompilationUnit(binder.get());
@@ -182,13 +192,14 @@
     if (binder) local = binder->localBinder();
     if (local) local->setParceled();
 
-    if (isForRpc()) {
+    if (const auto* rpcFields = maybeRpcFields()) {
         if (binder) {
             status_t status = writeInt32(1); // non-null
             if (status != OK) return status;
             uint64_t address;
             // TODO(b/167966510): need to undo this if the Parcel is not sent
-            status = mSession->state()->onBinderLeaving(mSession, binder, &address);
+            status = rpcFields->mSession->state()->onBinderLeaving(rpcFields->mSession, binder,
+                                                                   &address);
             if (status != OK) return status;
             status = writeUint64(address);
             if (status != OK) return status;
@@ -259,9 +270,7 @@
 
 status_t Parcel::unflattenBinder(sp<IBinder>* out) const
 {
-    if (isForRpc()) {
-        LOG_ALWAYS_FATAL_IF(mSession == nullptr, "RpcSession required to read from remote parcel");
-
+    if (const auto* rpcFields = maybeRpcFields()) {
         int32_t isPresent;
         status_t status = readInt32(&isPresent);
         if (status != OK) return status;
@@ -271,10 +280,14 @@
         if (isPresent & 1) {
             uint64_t addr;
             if (status_t status = readUint64(&addr); status != OK) return status;
-            if (status_t status = mSession->state()->onBinderEntering(mSession, addr, &binder);
+            if (status_t status =
+                        rpcFields->mSession->state()->onBinderEntering(rpcFields->mSession, addr,
+                                                                       &binder);
                 status != OK)
                 return status;
-            if (status_t status = mSession->state()->flushExcessBinderRefs(mSession, addr, binder);
+            if (status_t status =
+                        rpcFields->mSession->state()->flushExcessBinderRefs(rpcFields->mSession,
+                                                                            addr, binder);
                 status != OK)
                 return status;
         }
@@ -378,8 +391,10 @@
     }
 
     mDataPos = pos;
-    mNextObjectHint = 0;
-    mObjectsSorted = false;
+    if (const auto* kernelFields = maybeKernelFields()) {
+        kernelFields->mNextObjectHint = 0;
+        kernelFields->mObjectsSorted = false;
+    }
 }
 
 status_t Parcel::setDataCapacity(size_t size)
@@ -406,25 +421,27 @@
     if (err == NO_ERROR) {
         memcpy(const_cast<uint8_t*>(data()), buffer, len);
         mDataSize = len;
-        mFdsKnown = false;
+        if (auto* kernelFields = maybeKernelFields()) {
+            kernelFields->mFdsKnown = false;
+        }
     }
     return err;
 }
 
-status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len)
-{
-    if (mSession != parcel->mSession) {
+status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) {
+    if (isForRpc() != parcel->isForRpc()) {
         ALOGE("Cannot append Parcel from one context to another. They may be different formats, "
               "and objects are specific to a context.");
         return BAD_TYPE;
     }
+    if (isForRpc() && maybeRpcFields()->mSession != parcel->maybeRpcFields()->mSession) {
+        ALOGE("Cannot append Parcels from different sessions");
+        return BAD_TYPE;
+    }
 
     status_t err;
-    const uint8_t *data = parcel->mData;
-    const binder_size_t *objects = parcel->mObjects;
-    size_t size = parcel->mObjectsSize;
+    const uint8_t* data = parcel->mData;
     int startPos = mDataPos;
-    int firstIndex = -1, lastIndex = -2;
 
     if (len == 0) {
         return NO_ERROR;
@@ -443,18 +460,6 @@
         return BAD_VALUE;
     }
 
-    // Count objects in range
-    for (int i = 0; i < (int) size; i++) {
-        size_t off = objects[i];
-        if ((off >= offset) && (off + sizeof(flat_binder_object) <= offset + len)) {
-            if (firstIndex == -1) {
-                firstIndex = i;
-            }
-            lastIndex = i;
-        }
-    }
-    int numObjects = lastIndex - firstIndex + 1;
-
     if ((mDataSize+len) > mDataCapacity) {
         // grow data
         err = growData(len);
@@ -470,43 +475,120 @@
 
     err = NO_ERROR;
 
-    if (numObjects > 0) {
-        const sp<ProcessState> proc(ProcessState::self());
-        // grow objects
-        if (mObjectsCapacity < mObjectsSize + numObjects) {
-            if ((size_t) numObjects > SIZE_MAX - mObjectsSize) return NO_MEMORY; // overflow
-            if (mObjectsSize + numObjects > SIZE_MAX / 3) return NO_MEMORY; // overflow
-            size_t newSize = ((mObjectsSize + numObjects)*3)/2;
-            if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflow
-            binder_size_t *objects =
-                (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
-            if (objects == (binder_size_t*)nullptr) {
-                return NO_MEMORY;
+    if (auto* kernelFields = maybeKernelFields()) {
+        auto* otherKernelFields = parcel->maybeKernelFields();
+        LOG_ALWAYS_FATAL_IF(otherKernelFields == nullptr);
+
+        const binder_size_t* objects = otherKernelFields->mObjects;
+        size_t size = otherKernelFields->mObjectsSize;
+        // Count objects in range
+        int firstIndex = -1, lastIndex = -2;
+        for (int i = 0; i < (int)size; i++) {
+            size_t off = objects[i];
+            if ((off >= offset) && (off + sizeof(flat_binder_object) <= offset + len)) {
+                if (firstIndex == -1) {
+                    firstIndex = i;
+                }
+                lastIndex = i;
             }
-            mObjects = objects;
-            mObjectsCapacity = newSize;
+        }
+        int numObjects = lastIndex - firstIndex + 1;
+        if (numObjects > 0) {
+            const sp<ProcessState> proc(ProcessState::self());
+            // grow objects
+            if (kernelFields->mObjectsCapacity < kernelFields->mObjectsSize + numObjects) {
+                if ((size_t)numObjects > SIZE_MAX - kernelFields->mObjectsSize)
+                    return NO_MEMORY; // overflow
+                if (kernelFields->mObjectsSize + numObjects > SIZE_MAX / 3)
+                    return NO_MEMORY; // overflow
+                size_t newSize = ((kernelFields->mObjectsSize + numObjects) * 3) / 2;
+                if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflow
+                binder_size_t* objects = (binder_size_t*)realloc(kernelFields->mObjects,
+                                                                 newSize * sizeof(binder_size_t));
+                if (objects == (binder_size_t*)nullptr) {
+                    return NO_MEMORY;
+                }
+                kernelFields->mObjects = objects;
+                kernelFields->mObjectsCapacity = newSize;
+            }
+
+            // append and acquire objects
+            int idx = kernelFields->mObjectsSize;
+            for (int i = firstIndex; i <= lastIndex; i++) {
+                size_t off = objects[i] - offset + startPos;
+                kernelFields->mObjects[idx++] = off;
+                kernelFields->mObjectsSize++;
+
+                flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(mData + off);
+                acquire_object(proc, *flat, this);
+
+                if (flat->hdr.type == BINDER_TYPE_FD) {
+                    // If this is a file descriptor, we need to dup it so the
+                    // new Parcel now owns its own fd, and can declare that we
+                    // officially know we have fds.
+                    flat->handle = fcntl(flat->handle, F_DUPFD_CLOEXEC, 0);
+                    flat->cookie = 1;
+                    kernelFields->mHasFds = kernelFields->mFdsKnown = true;
+                    if (!mAllowFds) {
+                        err = FDS_NOT_ALLOWED;
+                    }
+                }
+            }
+        }
+    } else {
+        auto* rpcFields = maybeRpcFields();
+        LOG_ALWAYS_FATAL_IF(rpcFields == nullptr);
+        auto* otherRpcFields = parcel->maybeRpcFields();
+        if (otherRpcFields == nullptr) {
+            return BAD_TYPE;
+        }
+        if (rpcFields->mSession != otherRpcFields->mSession) {
+            return BAD_TYPE;
         }
 
-        // append and acquire objects
-        int idx = mObjectsSize;
-        for (int i = firstIndex; i <= lastIndex; i++) {
-            size_t off = objects[i] - offset + startPos;
-            mObjects[idx++] = off;
-            mObjectsSize++;
+        const size_t savedDataPos = mDataPos;
+        base::ScopeGuard scopeGuard = [&]() { mDataPos = savedDataPos; };
 
-            flat_binder_object* flat
-                = reinterpret_cast<flat_binder_object*>(mData + off);
-            acquire_object(proc, *flat, this);
+        rpcFields->mObjectPositions.reserve(otherRpcFields->mObjectPositions.size());
+        if (otherRpcFields->mFds != nullptr) {
+            if (rpcFields->mFds == nullptr) {
+                rpcFields->mFds = std::make_unique<decltype(rpcFields->mFds)::element_type>();
+            }
+            rpcFields->mFds->reserve(otherRpcFields->mFds->size());
+        }
+        for (size_t i = 0; i < otherRpcFields->mObjectPositions.size(); i++) {
+            const binder_size_t objPos = otherRpcFields->mObjectPositions[i];
+            if (offset <= objPos && objPos < offset + len) {
+                size_t newDataPos = objPos - offset + startPos;
+                rpcFields->mObjectPositions.push_back(newDataPos);
 
-            if (flat->hdr.type == BINDER_TYPE_FD) {
-                // If this is a file descriptor, we need to dup it so the
-                // new Parcel now owns its own fd, and can declare that we
-                // officially know we have fds.
-                flat->handle = fcntl(flat->handle, F_DUPFD_CLOEXEC, 0);
-                flat->cookie = 1;
-                mHasFds = mFdsKnown = true;
+                mDataPos = newDataPos;
+                int32_t objectType;
+                if (status_t status = readInt32(&objectType); status != OK) {
+                    return status;
+                }
+                if (objectType != RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) {
+                    continue;
+                }
+
                 if (!mAllowFds) {
-                    err = FDS_NOT_ALLOWED;
+                    return FDS_NOT_ALLOWED;
+                }
+
+                // Read FD, duplicate, and add to list.
+                int32_t fdIndex;
+                if (status_t status = readInt32(&fdIndex); status != OK) {
+                    return status;
+                }
+                const auto& oldFd = otherRpcFields->mFds->at(fdIndex);
+                // To match kernel binder behavior, we always dup, even if the
+                // FD was unowned in the source parcel.
+                rpcFields->mFds->emplace_back(
+                        base::unique_fd(fcntl(toRawFd(oldFd), F_DUPFD_CLOEXEC, 0)));
+                // Fixup the index in the data.
+                mDataPos = newDataPos + 4;
+                if (status_t status = writeInt32(rpcFields->mFds->size() - 1); status != OK) {
+                    return status;
                 }
             }
         }
@@ -563,10 +645,66 @@
 
 bool Parcel::hasFileDescriptors() const
 {
-    if (!mFdsKnown) {
+    if (const auto* rpcFields = maybeRpcFields()) {
+        return rpcFields->mFds != nullptr && !rpcFields->mFds->empty();
+    }
+    auto* kernelFields = maybeKernelFields();
+    if (!kernelFields->mFdsKnown) {
         scanForFds();
     }
-    return mHasFds;
+    return kernelFields->mHasFds;
+}
+
+std::vector<sp<IBinder>> Parcel::debugReadAllStrongBinders() const {
+    std::vector<sp<IBinder>> ret;
+
+    const auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return ret;
+    }
+
+    size_t initPosition = dataPosition();
+    for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
+        binder_size_t offset = kernelFields->mObjects[i];
+        const flat_binder_object* flat =
+                reinterpret_cast<const flat_binder_object*>(mData + offset);
+        if (flat->hdr.type != BINDER_TYPE_BINDER) continue;
+
+        setDataPosition(offset);
+
+        sp<IBinder> binder = readStrongBinder();
+        if (binder != nullptr) ret.push_back(binder);
+    }
+
+    setDataPosition(initPosition);
+    return ret;
+}
+
+std::vector<int> Parcel::debugReadAllFileDescriptors() const {
+    std::vector<int> ret;
+
+    if (const auto* kernelFields = maybeKernelFields()) {
+        size_t initPosition = dataPosition();
+        for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
+            binder_size_t offset = kernelFields->mObjects[i];
+            const flat_binder_object* flat =
+                    reinterpret_cast<const flat_binder_object*>(mData + offset);
+            if (flat->hdr.type != BINDER_TYPE_FD) continue;
+
+            setDataPosition(offset);
+
+            int fd = readFileDescriptor();
+            LOG_ALWAYS_FATAL_IF(fd == -1);
+            ret.push_back(fd);
+        }
+        setDataPosition(initPosition);
+    } else if (const auto* rpcFields = maybeRpcFields(); rpcFields && rpcFields->mFds) {
+        for (const auto& fd : *rpcFields->mFds) {
+            ret.push_back(toRawFd(fd));
+        }
+    }
+
+    return ret;
 }
 
 status_t Parcel::hasFileDescriptorsInRange(size_t offset, size_t len, bool* result) const {
@@ -580,17 +718,33 @@
         return BAD_VALUE;
     }
     *result = false;
-    for (size_t i = 0; i < mObjectsSize; i++) {
-        size_t pos = mObjects[i];
-        if (pos < offset) continue;
-        if (pos + sizeof(flat_binder_object) > offset + len) {
-          if (mObjectsSorted) break;
-          else continue;
+    if (const auto* kernelFields = maybeKernelFields()) {
+        for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
+            size_t pos = kernelFields->mObjects[i];
+            if (pos < offset) continue;
+            if (pos + sizeof(flat_binder_object) > offset + len) {
+                if (kernelFields->mObjectsSorted) {
+                    break;
+                } else {
+                    continue;
+                }
+            }
+            const flat_binder_object* flat =
+                    reinterpret_cast<const flat_binder_object*>(mData + pos);
+            if (flat->hdr.type == BINDER_TYPE_FD) {
+                *result = true;
+                break;
+            }
         }
-        const flat_binder_object* flat = reinterpret_cast<const flat_binder_object*>(mData + pos);
-        if (flat->hdr.type == BINDER_TYPE_FD) {
-            *result = true;
-            break;
+    } else if (const auto* rpcFields = maybeRpcFields()) {
+        for (uint32_t pos : rpcFields->mObjectPositions) {
+            if (offset <= pos && pos < limit) {
+                const auto* type = reinterpret_cast<const RpcFields::ObjectType*>(mData + pos);
+                if (*type == RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) {
+                    *result = true;
+                    break;
+                }
+            }
         }
     }
     return NO_ERROR;
@@ -613,20 +767,24 @@
     LOG_ALWAYS_FATAL_IF(mData != nullptr && mOwner == nullptr,
                         "format must be set before data is written OR on IPC data");
 
-    LOG_ALWAYS_FATAL_IF(session == nullptr, "markForRpc requires session");
-    mSession = session;
+    mVariantFields.emplace<RpcFields>(session);
 }
 
 bool Parcel::isForRpc() const {
-    return mSession != nullptr;
+    return std::holds_alternative<RpcFields>(mVariantFields);
 }
 
 void Parcel::updateWorkSourceRequestHeaderPosition() const {
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return;
+    }
+
     // Only update the request headers once. We only want to point
     // to the first headers read/written.
-    if (!mRequestHeaderPresent) {
-        mWorkSourceRequestHeaderPosition = dataPosition();
-        mRequestHeaderPresent = true;
+    if (!kernelFields->mRequestHeaderPresent) {
+        kernelFields->mWorkSourceRequestHeaderPosition = dataPosition();
+        kernelFields->mRequestHeaderPresent = true;
     }
 }
 
@@ -645,7 +803,7 @@
 }
 
 status_t Parcel::writeInterfaceToken(const char16_t* str, size_t len) {
-    if (CC_LIKELY(!isForRpc())) {
+    if (auto* kernelFields = maybeKernelFields()) {
         const IPCThreadState* threadState = IPCThreadState::self();
         writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
         updateWorkSourceRequestHeaderPosition();
@@ -660,12 +818,16 @@
 
 bool Parcel::replaceCallingWorkSourceUid(uid_t uid)
 {
-    if (!mRequestHeaderPresent) {
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return false;
+    }
+    if (!kernelFields->mRequestHeaderPresent) {
         return false;
     }
 
     const size_t initialPosition = dataPosition();
-    setDataPosition(mWorkSourceRequestHeaderPosition);
+    setDataPosition(kernelFields->mWorkSourceRequestHeaderPosition);
     status_t err = writeInt32(uid);
     setDataPosition(initialPosition);
     return err == NO_ERROR;
@@ -673,12 +835,16 @@
 
 uid_t Parcel::readCallingWorkSourceUid() const
 {
-    if (!mRequestHeaderPresent) {
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return false;
+    }
+    if (!kernelFields->mRequestHeaderPresent) {
         return IPCThreadState::kUnsetWorkSource;
     }
 
     const size_t initialPosition = dataPosition();
-    setDataPosition(mWorkSourceRequestHeaderPosition);
+    setDataPosition(kernelFields->mWorkSourceRequestHeaderPosition);
     uid_t uid = readInt32();
     setDataPosition(initialPosition);
     return uid;
@@ -699,7 +865,7 @@
                               size_t len,
                               IPCThreadState* threadState) const
 {
-    if (CC_LIKELY(!isForRpc())) {
+    if (auto* kernelFields = maybeKernelFields()) {
         // StrictModePolicy.
         int32_t strictPolicy = readInt32();
         if (threadState == nullptr) {
@@ -754,7 +920,10 @@
 
 size_t Parcel::objectsCount() const
 {
-    return mObjectsSize;
+    if (const auto* kernelFields = maybeKernelFields()) {
+        return kernelFields->mObjectsSize;
+    }
+    return 0;
 }
 
 status_t Parcel::errorCheck() const
@@ -1196,11 +1365,40 @@
     return err;
 }
 
-status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership)
-{
-    if (isForRpc()) {
-        ALOGE("Cannot write file descriptor to remote binder.");
-        return BAD_TYPE;
+status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership) {
+    if (auto* rpcFields = maybeRpcFields()) {
+        std::variant<base::unique_fd, base::borrowed_fd> fdVariant;
+        if (takeOwnership) {
+            fdVariant = base::unique_fd(fd);
+        } else {
+            fdVariant = base::borrowed_fd(fd);
+        }
+        if (!mAllowFds) {
+            return FDS_NOT_ALLOWED;
+        }
+        switch (rpcFields->mSession->getFileDescriptorTransportMode()) {
+            case RpcSession::FileDescriptorTransportMode::NONE: {
+                return FDS_NOT_ALLOWED;
+            }
+            case RpcSession::FileDescriptorTransportMode::UNIX: {
+                if (rpcFields->mFds == nullptr) {
+                    rpcFields->mFds = std::make_unique<decltype(rpcFields->mFds)::element_type>();
+                }
+                size_t dataPos = mDataPos;
+                if (dataPos > UINT32_MAX) {
+                    return NO_MEMORY;
+                }
+                if (status_t err = writeInt32(RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR); err != OK) {
+                    return err;
+                }
+                if (status_t err = writeInt32(rpcFields->mFds->size()); err != OK) {
+                    return err;
+                }
+                rpcFields->mObjectPositions.push_back(dataPos);
+                rpcFields->mFds->push_back(std::move(fdVariant));
+                return OK;
+            }
+        }
     }
 
     flat_binder_object obj;
@@ -1320,7 +1518,7 @@
     const size_t len = val.getFlattenedSize();
     const size_t fd_count = val.getFdCount();
 
-    if ((len > INT32_MAX) || (fd_count >= gMaxFds)) {
+    if ((len > INT32_MAX) || (fd_count > kMaxFds)) {
         // don't accept size_t values which may have come from an
         // inadvertent conversion from a negative int.
         return BAD_VALUE;
@@ -1360,8 +1558,11 @@
 
 status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
 {
+    auto* kernelFields = maybeKernelFields();
+    LOG_ALWAYS_FATAL_IF(kernelFields == nullptr, "Can't write flat_binder_object to RPC Parcel");
+
     const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
-    const bool enoughObjects = mObjectsSize < mObjectsCapacity;
+    const bool enoughObjects = kernelFields->mObjectsSize < kernelFields->mObjectsCapacity;
     if (enoughData && enoughObjects) {
 restart_write:
         *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
@@ -1372,14 +1573,14 @@
                 // fail before modifying our object index
                 return FDS_NOT_ALLOWED;
             }
-            mHasFds = mFdsKnown = true;
+            kernelFields->mHasFds = kernelFields->mFdsKnown = true;
         }
 
         // Need to write meta-data?
         if (nullMetaData || val.binder != 0) {
-            mObjects[mObjectsSize] = mDataPos;
+            kernelFields->mObjects[kernelFields->mObjectsSize] = mDataPos;
             acquire_object(ProcessState::self(), val, this);
-            mObjectsSize++;
+            kernelFields->mObjectsSize++;
         }
 
         return finishWrite(sizeof(flat_binder_object));
@@ -1390,14 +1591,15 @@
         if (err != NO_ERROR) return err;
     }
     if (!enoughObjects) {
-        if (mObjectsSize > SIZE_MAX - 2) return NO_MEMORY; // overflow
-        if ((mObjectsSize + 2) > SIZE_MAX / 3) return NO_MEMORY; // overflow
-        size_t newSize = ((mObjectsSize+2)*3)/2;
+        if (kernelFields->mObjectsSize > SIZE_MAX - 2) return NO_MEMORY;       // overflow
+        if ((kernelFields->mObjectsSize + 2) > SIZE_MAX / 3) return NO_MEMORY; // overflow
+        size_t newSize = ((kernelFields->mObjectsSize + 2) * 3) / 2;
         if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflow
-        binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
+        binder_size_t* objects =
+                (binder_size_t*)realloc(kernelFields->mObjects, newSize * sizeof(binder_size_t));
         if (objects == nullptr) return NO_MEMORY;
-        mObjects = objects;
-        mObjectsCapacity = newSize;
+        kernelFields->mObjects = objects;
+        kernelFields->mObjectsCapacity = newSize;
     }
 
     goto restart_write;
@@ -1411,54 +1613,64 @@
 
 status_t Parcel::validateReadData(size_t upperBound) const
 {
+    const auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        // Can't validate RPC Parcel reads because the location of binder
+        // objects is unknown.
+        return OK;
+    }
+
     // Don't allow non-object reads on object data
-    if (mObjectsSorted || mObjectsSize <= 1) {
-data_sorted:
+    if (kernelFields->mObjectsSorted || kernelFields->mObjectsSize <= 1) {
+    data_sorted:
         // Expect to check only against the next object
-        if (mNextObjectHint < mObjectsSize && upperBound > mObjects[mNextObjectHint]) {
+        if (kernelFields->mNextObjectHint < kernelFields->mObjectsSize &&
+            upperBound > kernelFields->mObjects[kernelFields->mNextObjectHint]) {
             // For some reason the current read position is greater than the next object
             // hint. Iterate until we find the right object
-            size_t nextObject = mNextObjectHint;
+            size_t nextObject = kernelFields->mNextObjectHint;
             do {
-                if (mDataPos < mObjects[nextObject] + sizeof(flat_binder_object)) {
+                if (mDataPos < kernelFields->mObjects[nextObject] + sizeof(flat_binder_object)) {
                     // Requested info overlaps with an object
                     ALOGE("Attempt to read from protected data in Parcel %p", this);
                     return PERMISSION_DENIED;
                 }
                 nextObject++;
-            } while (nextObject < mObjectsSize && upperBound > mObjects[nextObject]);
-            mNextObjectHint = nextObject;
+            } while (nextObject < kernelFields->mObjectsSize &&
+                     upperBound > kernelFields->mObjects[nextObject]);
+            kernelFields->mNextObjectHint = nextObject;
         }
         return NO_ERROR;
     }
     // Quickly determine if mObjects is sorted.
-    binder_size_t* currObj = mObjects + mObjectsSize - 1;
+    binder_size_t* currObj = kernelFields->mObjects + kernelFields->mObjectsSize - 1;
     binder_size_t* prevObj = currObj;
-    while (currObj > mObjects) {
+    while (currObj > kernelFields->mObjects) {
         prevObj--;
         if(*prevObj > *currObj) {
             goto data_unsorted;
         }
         currObj--;
     }
-    mObjectsSorted = true;
+    kernelFields->mObjectsSorted = true;
     goto data_sorted;
 
 data_unsorted:
     // Insertion Sort mObjects
     // Great for mostly sorted lists. If randomly sorted or reverse ordered mObjects become common,
     // switch to std::sort(mObjects, mObjects + mObjectsSize);
-    for (binder_size_t* iter0 = mObjects + 1; iter0 < mObjects + mObjectsSize; iter0++) {
+    for (binder_size_t* iter0 = kernelFields->mObjects + 1;
+         iter0 < kernelFields->mObjects + kernelFields->mObjectsSize; iter0++) {
         binder_size_t temp = *iter0;
         binder_size_t* iter1 = iter0 - 1;
-        while (iter1 >= mObjects && *iter1 > temp) {
+        while (iter1 >= kernelFields->mObjects && *iter1 > temp) {
             *(iter1 + 1) = *iter1;
             iter1--;
         }
         *(iter1 + 1) = temp;
     }
-    mNextObjectHint = 0;
-    mObjectsSorted = true;
+    kernelFields->mNextObjectHint = 0;
+    kernelFields->mObjectsSorted = true;
     goto data_sorted;
 }
 
@@ -1472,7 +1684,8 @@
 
     if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
             && len <= pad_size(len)) {
-        if (mObjectsSize > 0) {
+        const auto* kernelFields = maybeKernelFields();
+        if (kernelFields != nullptr && kernelFields->mObjectsSize > 0) {
             status_t err = validateReadData(mDataPos + pad_size(len));
             if(err != NO_ERROR) {
                 // Still increment the data position by the expected length
@@ -1499,7 +1712,8 @@
 
     if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
             && len <= pad_size(len)) {
-        if (mObjectsSize > 0) {
+        const auto* kernelFields = maybeKernelFields();
+        if (kernelFields != nullptr && kernelFields->mObjectsSize > 0) {
             status_t err = validateReadData(mDataPos + pad_size(len));
             if(err != NO_ERROR) {
                 // Still increment the data position by the expected length
@@ -1543,9 +1757,11 @@
 template<class T>
 status_t Parcel::readAligned(T *pArg) const {
     static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+    static_assert(std::is_trivially_copyable_v<T>);
 
     if ((mDataPos+sizeof(T)) <= mDataSize) {
-        if (mObjectsSize > 0) {
+        const auto* kernelFields = maybeKernelFields();
+        if (kernelFields != nullptr && kernelFields->mObjectsSize > 0) {
             status_t err = validateReadData(mDataPos + sizeof(T));
             if(err != NO_ERROR) {
                 // Still increment the data position by the expected length
@@ -1554,9 +1770,8 @@
             }
         }
 
-        const void* data = mData+mDataPos;
+        memcpy(pArg, mData + mDataPos, sizeof(T));
         mDataPos += sizeof(T);
-        *pArg =  *reinterpret_cast<const T*>(data);
         return NO_ERROR;
     } else {
         return NOT_ENOUGH_DATA;
@@ -1576,10 +1791,11 @@
 template<class T>
 status_t Parcel::writeAligned(T val) {
     static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+    static_assert(std::is_trivially_copyable_v<T>);
 
     if ((mDataPos+sizeof(val)) <= mDataCapacity) {
 restart_write:
-        *reinterpret_cast<T*>(mData+mDataPos) = val;
+        memcpy(mData + mDataPos, &val, sizeof(val));
         return finishWrite(sizeof(val));
     }
 
@@ -1862,6 +2078,7 @@
 {
     status_t status = readNullableStrongBinder(val);
     if (status == OK && !val->get()) {
+        ALOGW("Expecting binder but got null!");
         status = UNEXPECTED_NULL;
     }
     return status;
@@ -1922,8 +2139,31 @@
     return h;
 }
 
-int Parcel::readFileDescriptor() const
-{
+int Parcel::readFileDescriptor() const {
+    if (const auto* rpcFields = maybeRpcFields()) {
+        if (!std::binary_search(rpcFields->mObjectPositions.begin(),
+                                rpcFields->mObjectPositions.end(), mDataPos)) {
+            ALOGW("Attempt to read file descriptor from Parcel %p at offset %zu that is not in the "
+                  "object list",
+                  this, mDataPos);
+            return BAD_TYPE;
+        }
+
+        int32_t objectType = readInt32();
+        if (objectType != RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) {
+            return BAD_TYPE;
+        }
+
+        int32_t fdIndex = readInt32();
+        if (rpcFields->mFds == nullptr || fdIndex < 0 ||
+            static_cast<size_t>(fdIndex) >= rpcFields->mFds->size()) {
+            ALOGE("RPC Parcel contains invalid file descriptor index. index=%d fd_count=%zu",
+                  fdIndex, rpcFields->mFds ? rpcFields->mFds->size() : 0);
+            return BAD_VALUE;
+        }
+        return toRawFd(rpcFields->mFds->at(fdIndex));
+    }
+
     const flat_binder_object* flat = readObject(true);
 
     if (flat && flat->hdr.type == BINDER_TYPE_FD) {
@@ -1933,8 +2173,7 @@
     return BAD_TYPE;
 }
 
-int Parcel::readParcelFileDescriptor() const
-{
+int Parcel::readParcelFileDescriptor() const {
     int32_t hasComm = readInt32();
     int fd = readFileDescriptor();
     if (hasComm != 0) {
@@ -2043,7 +2282,7 @@
     const size_t len = this->readInt32();
     const size_t fd_count = this->readInt32();
 
-    if ((len > INT32_MAX) || (fd_count >= gMaxFds)) {
+    if ((len > INT32_MAX) || (fd_count > kMaxFds)) {
         // don't accept size_t values which may have come from an
         // inadvertent conversion from a negative int.
         return BAD_VALUE;
@@ -2089,6 +2328,11 @@
 }
 const flat_binder_object* Parcel::readObject(bool nullMetaData) const
 {
+    const auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return nullptr;
+    }
+
     const size_t DPOS = mDataPos;
     if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) {
         const flat_binder_object* obj
@@ -2103,9 +2347,9 @@
         }
 
         // Ensure that this object is valid...
-        binder_size_t* const OBJS = mObjects;
-        const size_t N = mObjectsSize;
-        size_t opos = mNextObjectHint;
+        binder_size_t* const OBJS = kernelFields->mObjects;
+        const size_t N = kernelFields->mObjectsSize;
+        size_t opos = kernelFields->mNextObjectHint;
 
         if (N > 0) {
             ALOGV("Parcel %p looking for obj at %zu, hint=%zu",
@@ -2124,7 +2368,7 @@
                 // Found it!
                 ALOGV("Parcel %p found obj %zu at index %zu with forward search",
                      this, DPOS, opos);
-                mNextObjectHint = opos+1;
+                kernelFields->mNextObjectHint = opos + 1;
                 ALOGV("readObject Setting data pos of %p to %zu", this, mDataPos);
                 return obj;
             }
@@ -2137,7 +2381,7 @@
                 // Found it!
                 ALOGV("Parcel %p found obj %zu at index %zu with backward search",
                      this, DPOS, opos);
-                mNextObjectHint = opos+1;
+                kernelFields->mNextObjectHint = opos + 1;
                 ALOGV("readObject Setting data pos of %p to %zu", this, mDataPos);
                 return obj;
             }
@@ -2148,20 +2392,23 @@
     return nullptr;
 }
 
-void Parcel::closeFileDescriptors()
-{
-    size_t i = mObjectsSize;
-    if (i > 0) {
-        //ALOGI("Closing file descriptors for %zu objects...", i);
-    }
-    while (i > 0) {
-        i--;
-        const flat_binder_object* flat
-            = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
-        if (flat->hdr.type == BINDER_TYPE_FD) {
-            //ALOGI("Closing fd: %ld", flat->handle);
-            close(flat->handle);
+void Parcel::closeFileDescriptors() {
+    if (auto* kernelFields = maybeKernelFields()) {
+        size_t i = kernelFields->mObjectsSize;
+        if (i > 0) {
+            // ALOGI("Closing file descriptors for %zu objects...", i);
         }
+        while (i > 0) {
+            i--;
+            const flat_binder_object* flat =
+                    reinterpret_cast<flat_binder_object*>(mData + kernelFields->mObjects[i]);
+            if (flat->hdr.type == BINDER_TYPE_FD) {
+                // ALOGI("Closing fd: %ld", flat->handle);
+                close(flat->handle);
+            }
+        }
+    } else if (auto* rpcFields = maybeRpcFields()) {
+        rpcFields->mFds.reset();
     }
 }
 
@@ -2177,35 +2424,43 @@
 
 uintptr_t Parcel::ipcObjects() const
 {
-    return reinterpret_cast<uintptr_t>(mObjects);
+    if (const auto* kernelFields = maybeKernelFields()) {
+        return reinterpret_cast<uintptr_t>(kernelFields->mObjects);
+    }
+    return 0;
 }
 
 size_t Parcel::ipcObjectsCount() const
 {
-    return mObjectsSize;
+    if (const auto* kernelFields = maybeKernelFields()) {
+        return kernelFields->mObjectsSize;
+    }
+    return 0;
 }
 
-void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
-    const binder_size_t* objects, size_t objectsCount, release_func relFunc)
-{
+void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
+                                 size_t objectsCount, release_func relFunc) {
     // this code uses 'mOwner == nullptr' to understand whether it owns memory
     LOG_ALWAYS_FATAL_IF(relFunc == nullptr, "must provide cleanup function");
 
     freeData();
 
+    auto* kernelFields = maybeKernelFields();
+    LOG_ALWAYS_FATAL_IF(kernelFields == nullptr); // guaranteed by freeData.
+
     mData = const_cast<uint8_t*>(data);
     mDataSize = mDataCapacity = dataSize;
-    mObjects = const_cast<binder_size_t*>(objects);
-    mObjectsSize = mObjectsCapacity = objectsCount;
+    kernelFields->mObjects = const_cast<binder_size_t*>(objects);
+    kernelFields->mObjectsSize = kernelFields->mObjectsCapacity = objectsCount;
     mOwner = relFunc;
 
     binder_size_t minOffset = 0;
-    for (size_t i = 0; i < mObjectsSize; i++) {
-        binder_size_t offset = mObjects[i];
+    for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
+        binder_size_t offset = kernelFields->mObjects[i];
         if (offset < minOffset) {
             ALOGE("%s: bad object offset %" PRIu64 " < %" PRIu64 "\n",
                   __func__, (uint64_t)offset, (uint64_t)minOffset);
-            mObjectsSize = 0;
+            kernelFields->mObjectsSize = 0;
             break;
         }
         const flat_binder_object* flat
@@ -2223,7 +2478,7 @@
 
             // WARNING: callers of ipcSetDataReference need to make sure they
             // don't rely on mObjectsSize in their release_func.
-            mObjectsSize = 0;
+            kernelFields->mObjectsSize = 0;
             break;
         }
         minOffset = offset + sizeof(flat_binder_object);
@@ -2231,6 +2486,47 @@
     scanForFds();
 }
 
+status_t Parcel::rpcSetDataReference(const sp<RpcSession>& session, const uint8_t* data,
+                                     size_t dataSize, const uint32_t* objectTable,
+                                     size_t objectTableSize,
+                                     std::vector<base::unique_fd> ancillaryFds,
+                                     release_func relFunc) {
+    // this code uses 'mOwner == nullptr' to understand whether it owns memory
+    LOG_ALWAYS_FATAL_IF(relFunc == nullptr, "must provide cleanup function");
+
+    LOG_ALWAYS_FATAL_IF(session == nullptr);
+
+    freeData();
+    markForRpc(session);
+
+    auto* rpcFields = maybeRpcFields();
+    LOG_ALWAYS_FATAL_IF(rpcFields == nullptr); // guaranteed by markForRpc.
+
+    mData = const_cast<uint8_t*>(data);
+    mDataSize = mDataCapacity = dataSize;
+    mOwner = relFunc;
+
+    if (objectTableSize != ancillaryFds.size()) {
+        ALOGE("objectTableSize=%zu ancillaryFds.size=%zu", objectTableSize, ancillaryFds.size());
+        freeData(); // don't leak mData
+        return BAD_VALUE;
+    }
+
+    rpcFields->mObjectPositions.reserve(objectTableSize);
+    for (size_t i = 0; i < objectTableSize; i++) {
+        rpcFields->mObjectPositions.push_back(objectTable[i]);
+    }
+    if (!ancillaryFds.empty()) {
+        rpcFields->mFds = std::make_unique<decltype(rpcFields->mFds)::element_type>();
+        rpcFields->mFds->reserve(ancillaryFds.size());
+        for (auto& fd : ancillaryFds) {
+            rpcFields->mFds->push_back(std::move(fd));
+        }
+    }
+
+    return OK;
+}
+
 void Parcel::print(TextOutput& to, uint32_t /*flags*/) const
 {
     to << "Parcel(";
@@ -2241,14 +2537,16 @@
     } else if (dataSize() > 0) {
         const uint8_t* DATA = data();
         to << indent << HexDump(DATA, dataSize()) << dedent;
-        const binder_size_t* OBJS = mObjects;
-        const size_t N = objectsCount();
-        for (size_t i=0; i<N; i++) {
-            const flat_binder_object* flat
-                = reinterpret_cast<const flat_binder_object*>(DATA+OBJS[i]);
-            to << endl << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
-                << TypeCode(flat->hdr.type & 0x7f7f7f00)
-                << " = " << flat->binder;
+        if (const auto* kernelFields = maybeKernelFields()) {
+            const binder_size_t* OBJS = kernelFields->mObjects;
+            const size_t N = objectsCount();
+            for (size_t i = 0; i < N; i++) {
+                const flat_binder_object* flat =
+                        reinterpret_cast<const flat_binder_object*>(DATA + OBJS[i]);
+                to << endl
+                   << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
+                   << TypeCode(flat->hdr.type & 0x7f7f7f00) << " = " << flat->binder;
+            }
         }
     } else {
         to << "NULL";
@@ -2259,34 +2557,42 @@
 
 void Parcel::releaseObjects()
 {
-    size_t i = mObjectsSize;
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return;
+    }
+
+    size_t i = kernelFields->mObjectsSize;
     if (i == 0) {
         return;
     }
     sp<ProcessState> proc(ProcessState::self());
     uint8_t* const data = mData;
-    binder_size_t* const objects = mObjects;
+    binder_size_t* const objects = kernelFields->mObjects;
     while (i > 0) {
         i--;
-        const flat_binder_object* flat
-            = reinterpret_cast<flat_binder_object*>(data+objects[i]);
+        const flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(data + objects[i]);
         release_object(proc, *flat, this);
     }
 }
 
 void Parcel::acquireObjects()
 {
-    size_t i = mObjectsSize;
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return;
+    }
+
+    size_t i = kernelFields->mObjectsSize;
     if (i == 0) {
         return;
     }
     const sp<ProcessState> proc(ProcessState::self());
     uint8_t* const data = mData;
-    binder_size_t* const objects = mObjects;
+    binder_size_t* const objects = kernelFields->mObjects;
     while (i > 0) {
         i--;
-        const flat_binder_object* flat
-            = reinterpret_cast<flat_binder_object*>(data+objects[i]);
+        const flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(data + objects[i]);
         acquire_object(proc, *flat, this);
     }
 }
@@ -2302,7 +2608,9 @@
     if (mOwner) {
         LOG_ALLOC("Parcel %p: freeing other owner data", this);
         //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
-        mOwner(this, mData, mDataSize, mObjects, mObjectsSize);
+        auto* kernelFields = maybeKernelFields();
+        mOwner(this, mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
+               kernelFields ? kernelFields->mObjectsSize : 0);
     } else {
         LOG_ALLOC("Parcel %p: freeing allocated data", this);
         releaseObjects();
@@ -2315,7 +2623,8 @@
             }
             free(mData);
         }
-        if (mObjects) free(mObjects);
+        auto* kernelFields = maybeKernelFields();
+        if (kernelFields && kernelFields->mObjects) free(kernelFields->mObjects);
     }
 }
 
@@ -2390,13 +2699,18 @@
     ALOGV("restartWrite Setting data size of %p to %zu", this, mDataSize);
     ALOGV("restartWrite Setting data pos of %p to %zu", this, mDataPos);
 
-    free(mObjects);
-    mObjects = nullptr;
-    mObjectsSize = mObjectsCapacity = 0;
-    mNextObjectHint = 0;
-    mObjectsSorted = false;
-    mHasFds = false;
-    mFdsKnown = true;
+    if (auto* kernelFields = maybeKernelFields()) {
+        free(kernelFields->mObjects);
+        kernelFields->mObjects = nullptr;
+        kernelFields->mObjectsSize = kernelFields->mObjectsCapacity = 0;
+        kernelFields->mNextObjectHint = 0;
+        kernelFields->mObjectsSorted = false;
+        kernelFields->mHasFds = false;
+        kernelFields->mFdsKnown = true;
+    } else if (auto* rpcFields = maybeRpcFields()) {
+        rpcFields->mObjectPositions.clear();
+        rpcFields->mFds.reset();
+    }
     mAllowFds = true;
 
     return NO_ERROR;
@@ -2410,17 +2724,27 @@
         return BAD_VALUE;
     }
 
+    auto* kernelFields = maybeKernelFields();
+    auto* rpcFields = maybeRpcFields();
+
     // If shrinking, first adjust for any objects that appear
     // after the new data size.
-    size_t objectsSize = mObjectsSize;
+    size_t objectsSize =
+            kernelFields ? kernelFields->mObjectsSize : rpcFields->mObjectPositions.size();
     if (desired < mDataSize) {
         if (desired == 0) {
             objectsSize = 0;
         } else {
-            while (objectsSize > 0) {
-                if (mObjects[objectsSize-1] < desired)
-                    break;
-                objectsSize--;
+            if (kernelFields) {
+                while (objectsSize > 0) {
+                    if (kernelFields->mObjects[objectsSize - 1] < desired) break;
+                    objectsSize--;
+                }
+            } else {
+                while (objectsSize > 0) {
+                    if (rpcFields->mObjectPositions[objectsSize - 1] < desired) break;
+                    objectsSize--;
+                }
             }
         }
     }
@@ -2441,7 +2765,7 @@
         }
         binder_size_t* objects = nullptr;
 
-        if (objectsSize) {
+        if (kernelFields && objectsSize) {
             objects = (binder_size_t*)calloc(objectsSize, sizeof(binder_size_t));
             if (!objects) {
                 free(data);
@@ -2452,20 +2776,27 @@
 
             // Little hack to only acquire references on objects
             // we will be keeping.
-            size_t oldObjectsSize = mObjectsSize;
-            mObjectsSize = objectsSize;
+            size_t oldObjectsSize = kernelFields->mObjectsSize;
+            kernelFields->mObjectsSize = objectsSize;
             acquireObjects();
-            mObjectsSize = oldObjectsSize;
+            kernelFields->mObjectsSize = oldObjectsSize;
+        }
+        if (rpcFields) {
+            if (status_t status = truncateRpcObjects(objectsSize); status != OK) {
+                free(data);
+                return status;
+            }
         }
 
         if (mData) {
             memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
         }
-        if (objects && mObjects) {
-            memcpy(objects, mObjects, objectsSize*sizeof(binder_size_t));
+        if (objects && kernelFields && kernelFields->mObjects) {
+            memcpy(objects, kernelFields->mObjects, objectsSize * sizeof(binder_size_t));
         }
         //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
-        mOwner(this, mData, mDataSize, mObjects, mObjectsSize);
+        mOwner(this, mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
+               kernelFields ? kernelFields->mObjectsSize : 0);
         mOwner = nullptr;
 
         LOG_ALLOC("Parcel %p: taking ownership of %zu capacity", this, desired);
@@ -2473,43 +2804,51 @@
         gParcelGlobalAllocCount++;
 
         mData = data;
-        mObjects = objects;
         mDataSize = (mDataSize < desired) ? mDataSize : desired;
         ALOGV("continueWrite Setting data size of %p to %zu", this, mDataSize);
         mDataCapacity = desired;
-        mObjectsSize = mObjectsCapacity = objectsSize;
-        mNextObjectHint = 0;
-        mObjectsSorted = false;
+        if (kernelFields) {
+            kernelFields->mObjects = objects;
+            kernelFields->mObjectsSize = kernelFields->mObjectsCapacity = objectsSize;
+            kernelFields->mNextObjectHint = 0;
+            kernelFields->mObjectsSorted = false;
+        }
 
     } else if (mData) {
-        if (objectsSize < mObjectsSize) {
+        if (kernelFields && objectsSize < kernelFields->mObjectsSize) {
             // Need to release refs on any objects we are dropping.
             const sp<ProcessState> proc(ProcessState::self());
-            for (size_t i=objectsSize; i<mObjectsSize; i++) {
-                const flat_binder_object* flat
-                    = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
+            for (size_t i = objectsSize; i < kernelFields->mObjectsSize; i++) {
+                const flat_binder_object* flat =
+                        reinterpret_cast<flat_binder_object*>(mData + kernelFields->mObjects[i]);
                 if (flat->hdr.type == BINDER_TYPE_FD) {
                     // will need to rescan because we may have lopped off the only FDs
-                    mFdsKnown = false;
+                    kernelFields->mFdsKnown = false;
                 }
                 release_object(proc, *flat, this);
             }
 
             if (objectsSize == 0) {
-                free(mObjects);
-                mObjects = nullptr;
-                mObjectsCapacity = 0;
+                free(kernelFields->mObjects);
+                kernelFields->mObjects = nullptr;
+                kernelFields->mObjectsCapacity = 0;
             } else {
                 binder_size_t* objects =
-                    (binder_size_t*)realloc(mObjects, objectsSize*sizeof(binder_size_t));
+                        (binder_size_t*)realloc(kernelFields->mObjects,
+                                                objectsSize * sizeof(binder_size_t));
                 if (objects) {
-                    mObjects = objects;
-                    mObjectsCapacity = objectsSize;
+                    kernelFields->mObjects = objects;
+                    kernelFields->mObjectsCapacity = objectsSize;
                 }
             }
-            mObjectsSize = objectsSize;
-            mNextObjectHint = 0;
-            mObjectsSorted = false;
+            kernelFields->mObjectsSize = objectsSize;
+            kernelFields->mNextObjectHint = 0;
+            kernelFields->mObjectsSorted = false;
+        }
+        if (rpcFields) {
+            if (status_t status = truncateRpcObjects(objectsSize); status != OK) {
+                return status;
+            }
         }
 
         // We own the data, so we can just do a realloc().
@@ -2545,9 +2884,12 @@
             return NO_MEMORY;
         }
 
-        if(!(mDataCapacity == 0 && mObjects == nullptr
-             && mObjectsCapacity == 0)) {
-            ALOGE("continueWrite: %zu/%p/%zu/%zu", mDataCapacity, mObjects, mObjectsCapacity, desired);
+        if (!(mDataCapacity == 0 &&
+              (kernelFields == nullptr ||
+               (kernelFields->mObjects == nullptr && kernelFields->mObjectsCapacity == 0)))) {
+            ALOGE("continueWrite: %zu/%p/%zu/%zu", mDataCapacity,
+                  kernelFields ? kernelFields->mObjects : nullptr,
+                  kernelFields ? kernelFields->mObjectsCapacity : 0, desired);
         }
 
         LOG_ALLOC("Parcel %p: allocating with %zu capacity", this, desired);
@@ -2564,6 +2906,35 @@
     return NO_ERROR;
 }
 
+status_t Parcel::truncateRpcObjects(size_t newObjectsSize) {
+    auto* rpcFields = maybeRpcFields();
+    if (newObjectsSize == 0) {
+        rpcFields->mObjectPositions.clear();
+        if (rpcFields->mFds) {
+            rpcFields->mFds->clear();
+        }
+        return OK;
+    }
+    while (rpcFields->mObjectPositions.size() > newObjectsSize) {
+        uint32_t pos = rpcFields->mObjectPositions.back();
+        rpcFields->mObjectPositions.pop_back();
+        const auto type = *reinterpret_cast<const RpcFields::ObjectType*>(mData + pos);
+        if (type == RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) {
+            const auto fdIndex =
+                    *reinterpret_cast<const int32_t*>(mData + pos + sizeof(RpcFields::ObjectType));
+            if (rpcFields->mFds == nullptr || fdIndex < 0 ||
+                static_cast<size_t>(fdIndex) >= rpcFields->mFds->size()) {
+                ALOGE("RPC Parcel contains invalid file descriptor index. index=%d fd_count=%zu",
+                      fdIndex, rpcFields->mFds ? rpcFields->mFds->size() : 0);
+                return BAD_VALUE;
+            }
+            // In practice, this always removes the last element.
+            rpcFields->mFds->erase(rpcFields->mFds->begin() + fdIndex);
+        }
+    }
+    return OK;
+}
+
 void Parcel::initState()
 {
     LOG_ALLOC("Parcel %p: initState", this);
@@ -2574,37 +2945,20 @@
     mDataPos = 0;
     ALOGV("initState Setting data size of %p to %zu", this, mDataSize);
     ALOGV("initState Setting data pos of %p to %zu", this, mDataPos);
-    mSession = nullptr;
-    mObjects = nullptr;
-    mObjectsSize = 0;
-    mObjectsCapacity = 0;
-    mNextObjectHint = 0;
-    mObjectsSorted = false;
-    mHasFds = false;
-    mFdsKnown = true;
+    mVariantFields.emplace<KernelFields>();
     mAllowFds = true;
     mDeallocZero = false;
     mOwner = nullptr;
-    mWorkSourceRequestHeaderPosition = 0;
-    mRequestHeaderPresent = false;
-
-    // racing multiple init leads only to multiple identical write
-    if (gMaxFds == 0) {
-        struct rlimit result;
-        if (!getrlimit(RLIMIT_NOFILE, &result)) {
-            gMaxFds = (size_t)result.rlim_cur;
-            //ALOGI("parcel fd limit set to %zu", gMaxFds);
-        } else {
-            ALOGW("Unable to getrlimit: %s", strerror(errno));
-            gMaxFds = 1024;
-        }
-    }
 }
 
 void Parcel::scanForFds() const {
-    status_t status = hasFileDescriptorsInRange(0, dataSize(), &mHasFds);
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return;
+    }
+    status_t status = hasFileDescriptorsInRange(0, dataSize(), &kernelFields->mHasFds);
     ALOGE_IF(status != NO_ERROR, "Error %d calling hasFileDescriptorsInRange()", status);
-    mFdsKnown = true;
+    kernelFields->mFdsKnown = true;
 }
 
 size_t Parcel::getBlobAshmemSize() const
@@ -2617,10 +2971,15 @@
 
 size_t Parcel::getOpenAshmemSize() const
 {
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return 0;
+    }
+
     size_t openAshmemSize = 0;
-    for (size_t i = 0; i < mObjectsSize; i++) {
+    for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
         const flat_binder_object* flat =
-                reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
+                reinterpret_cast<const flat_binder_object*>(mData + kernelFields->mObjects[i]);
 
         // cookie is compared against zero for historical reasons
         // > obj.cookie = takeOwnership ? 1 : 0;
diff --git a/libs/binder/ParcelableHolder.cpp b/libs/binder/ParcelableHolder.cpp
index 2e86b74..3cf94e3 100644
--- a/libs/binder/ParcelableHolder.cpp
+++ b/libs/binder/ParcelableHolder.cpp
@@ -52,7 +52,10 @@
 }
 
 status_t ParcelableHolder::readFromParcel(const Parcel* p) {
-    this->mStability = static_cast<Stability>(p->readInt32());
+    int32_t wireStability;
+    if (status_t status = p->readInt32(&wireStability); status != OK) return status;
+    if (static_cast<int32_t>(this->mStability) != wireStability) return BAD_VALUE;
+
     this->mParcelable = nullptr;
     this->mParcelableName = std::nullopt;
     int32_t rawDataSize;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index baa817c..7faff47 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -25,23 +25,25 @@
 #include <binder/IServiceManager.h>
 #include <binder/Stability.h>
 #include <cutils/atomic.h>
+#include <utils/AndroidThreads.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
-#include <utils/threads.h>
+#include <utils/Thread.h>
 
 #include "Static.h"
 #include "binder_module.h"
 
 #include <errno.h>
 #include <fcntl.h>
-#include <mutex>
+#include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <unistd.h>
+#include <mutex>
 
 #define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
 #define DEFAULT_MAX_BINDER_THREADS 15
@@ -99,6 +101,11 @@
 
 sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
 {
+#ifdef BINDER_IPC_32BIT
+    LOG_ALWAYS_FATAL("32-bit binder IPC is not supported for new devices starting in Android P. If "
+                     "you do need to use this mode, please see b/232423610 or file an issue with "
+                     "AOSP upstream as otherwise this will be removed soon.");
+#endif
 
     if (driver == nullptr) {
         std::lock_guard<std::mutex> l(gProcessMutex);
@@ -169,6 +176,10 @@
     // the thread handler is installed
     if (gProcess) {
         gProcess->mForked = true;
+
+        // "O_CLOFORK"
+        close(gProcess->mDriverFD);
+        gProcess->mDriverFD = -1;
     }
     gProcessMutex.unlock();
 }
@@ -181,7 +192,6 @@
             ALOGW("Extra binder thread started, but 0 threads requested. Do not use "
                   "*startThreadPool when zero threads are requested.");
         }
-
         mThreadPoolStarted = true;
         spawnPooledThread(true);
     }
@@ -289,12 +299,17 @@
     return &mHandleToObject.editItemAt(handle);
 }
 
+// see b/166779391: cannot change the VNDK interface, so access like this
+extern sp<BBinder> the_context_object;
+
 sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
 {
     sp<IBinder> result;
 
     AutoMutex _l(mLock);
 
+    if (handle == 0 && the_context_object != nullptr) return the_context_object;
+
     handle_entry* e = lookupHandleLocked(handle);
 
     if (e != nullptr) {
@@ -385,6 +400,9 @@
         ALOGV("Spawning new pooled thread, name=%s\n", name.string());
         sp<Thread> t = sp<PoolThread>::make(isMain);
         t->run(name.string());
+        pthread_mutex_lock(&mThreadCountLock);
+        mKernelStartedThreads++;
+        pthread_mutex_unlock(&mThreadCountLock);
     }
 }
 
@@ -401,12 +419,44 @@
     return result;
 }
 
-size_t ProcessState::getThreadPoolMaxThreadCount() const {
+size_t ProcessState::getThreadPoolMaxTotalThreadCount() const {
     // may actually be one more than this, if join is called
-    if (mThreadPoolStarted) return mMaxThreads;
+    if (mThreadPoolStarted) {
+        return mCurrentThreads < mKernelStartedThreads
+                ? mMaxThreads
+                : mMaxThreads + mCurrentThreads - mKernelStartedThreads;
+    }
     // must not be initialized or maybe has poll thread setup, we
     // currently don't track this in libbinder
-    return 0;
+    LOG_ALWAYS_FATAL_IF(mKernelStartedThreads != 0,
+                        "Expecting 0 kernel started threads but have"
+                        " %zu",
+                        mKernelStartedThreads);
+    return mCurrentThreads;
+}
+
+#define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
+bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) {
+    static const char* const names[] = {
+        [static_cast<int>(DriverFeature::ONEWAY_SPAM_DETECTION)] =
+            DRIVER_FEATURES_PATH "oneway_spam_detection",
+        [static_cast<int>(DriverFeature::EXTENDED_ERROR)] =
+            DRIVER_FEATURES_PATH "extended_error",
+    };
+    int fd = open(names[static_cast<int>(feature)], O_RDONLY | O_CLOEXEC);
+    char on;
+    if (fd == -1) {
+        ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__,
+                 names[static_cast<int>(feature)], strerror(errno));
+        return false;
+    }
+    if (read(fd, &on, sizeof(on)) == -1) {
+        ALOGE("%s: error reading to %s: %s", __func__,
+                 names[static_cast<int>(feature)], strerror(errno));
+        return false;
+    }
+    close(fd);
+    return on == '1';
 }
 
 status_t ProcessState::enableOnewaySpamDetection(bool enable) {
@@ -452,7 +502,9 @@
     uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
     result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
     if (result == -1) {
-        ALOGV("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
+        ALOGE_IF(ProcessState::isDriverFeatureEnabled(
+                     ProcessState::DriverFeature::ONEWAY_SPAM_DETECTION),
+                 "Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
     }
     return fd;
 }
@@ -466,6 +518,8 @@
         mExecutingThreadsCount(0),
         mWaitingForThreads(0),
         mMaxThreads(DEFAULT_MAX_BINDER_THREADS),
+        mCurrentThreads(0),
+        mKernelStartedThreads(0),
         mStarvationStartTimeMs(0),
         mForked(false),
         mThreadPoolStarted(false),
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index ace5cd5..3bb21ad 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -24,18 +24,19 @@
 #include <thread>
 #include <vector>
 
-#include <android-base/file.h>
 #include <android-base/hex.h>
 #include <android-base/scopeguard.h>
 #include <binder/Parcel.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcTransportRaw.h>
 #include <log/log.h>
+#include <utils/Compat.h>
 
 #include "FdTrigger.h"
 #include "RpcSocketAddress.h"
 #include "RpcState.h"
 #include "RpcWireFormat.h"
+#include "Utils.h"
 
 namespace android {
 
@@ -121,6 +122,14 @@
     mProtocolVersion = version;
 }
 
+void RpcServer::setSupportedFileDescriptorTransportModes(
+        const std::vector<RpcSession::FileDescriptorTransportMode>& modes) {
+    mSupportedFileDescriptorTransportModes.reset();
+    for (RpcSession::FileDescriptorTransportMode mode : modes) {
+        mSupportedFileDescriptorTransportModes.set(static_cast<size_t>(mode));
+    }
+}
+
 void RpcServer::setRootObject(const sp<IBinder>& binder) {
     std::lock_guard<std::mutex> _l(mLock);
     mRootObjectFactory = nullptr;
@@ -134,7 +143,7 @@
     mRootObjectWeak = binder;
 }
 void RpcServer::setPerSessionRootObject(
-        std::function<sp<IBinder>(const sockaddr*, socklen_t)>&& makeObject) {
+        std::function<sp<IBinder>(const void*, size_t)>&& makeObject) {
     std::lock_guard<std::mutex> _l(mLock);
     mRootObject.clear();
     mRootObjectWeak.clear();
@@ -177,14 +186,16 @@
 
     status_t status;
     while ((status = mShutdownTrigger->triggerablePoll(mServer, POLLIN)) == OK) {
-        sockaddr_storage addr;
-        socklen_t addrLen = sizeof(addr);
+        std::array<uint8_t, kRpcAddressSize> addr;
+        static_assert(addr.size() >= sizeof(sockaddr_storage), "kRpcAddressSize is too small");
 
+        socklen_t addrLen = addr.size();
         unique_fd clientFd(
-                TEMP_FAILURE_RETRY(accept4(mServer.get(), reinterpret_cast<sockaddr*>(&addr),
+                TEMP_FAILURE_RETRY(accept4(mServer.get(), reinterpret_cast<sockaddr*>(addr.data()),
                                            &addrLen, SOCK_CLOEXEC | SOCK_NONBLOCK)));
 
-        LOG_ALWAYS_FATAL_IF(addrLen > static_cast<socklen_t>(sizeof(addr)), "Truncated address");
+        LOG_ALWAYS_FATAL_IF(addrLen > static_cast<socklen_t>(sizeof(sockaddr_storage)),
+                            "Truncated address");
 
         if (clientFd < 0) {
             ALOGE("Could not accept4 socket: %s", strerror(errno));
@@ -267,7 +278,7 @@
 }
 
 void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
-                                    const sockaddr_storage addr, socklen_t addrLen) {
+                                    std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen) {
     // mShutdownTrigger can only be cleared once connection threads have joined.
     // It must be set before this thread is started
     LOG_ALWAYS_FATAL_IF(server->mShutdownTrigger == nullptr);
@@ -288,7 +299,8 @@
     RpcConnectionHeader header;
     if (status == OK) {
         iovec iov{&header, sizeof(header)};
-        status = client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1, {});
+        status = client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1,
+                                                std::nullopt, /*enableAncillaryFds=*/false);
         if (status != OK) {
             ALOGE("Failed to read ID for client connecting to RPC server: %s",
                   statusToString(status).c_str());
@@ -302,8 +314,8 @@
             if (header.sessionIdSize == kSessionIdBytes) {
                 sessionId.resize(header.sessionIdSize);
                 iovec iov{sessionId.data(), sessionId.size()};
-                status =
-                        client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1, {});
+                status = client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1,
+                                                        std::nullopt, /*enableAncillaryFds=*/false);
                 if (status != OK) {
                     ALOGE("Failed to read session ID for client connecting to RPC server: %s",
                           statusToString(status).c_str());
@@ -333,7 +345,8 @@
             };
 
             iovec iov{&response, sizeof(response)};
-            status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &iov, 1, {});
+            status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &iov, 1,
+                                                     std::nullopt, nullptr);
             if (status != OK) {
                 ALOGE("Failed to send new session response: %s", statusToString(status).c_str());
                 // still need to cleanup before we can return
@@ -380,24 +393,32 @@
                     return;
                 }
 
-                base::unique_fd fd(TEMP_FAILURE_RETRY(
-                        open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW)));
-                if (!base::ReadFully(fd, sessionId.data(), sessionId.size())) {
-                    ALOGE("Could not read from /dev/urandom to create session ID");
+                auto status = getRandomBytes(sessionId.data(), sessionId.size());
+                if (status != OK) {
+                    ALOGE("Failed to read random session ID: %s", strerror(-status));
                     return;
                 }
             } while (server->mSessions.end() != server->mSessions.find(sessionId));
 
-            session = RpcSession::make();
+            session = sp<RpcSession>::make(nullptr);
             session->setMaxIncomingThreads(server->mMaxThreads);
             if (!session->setProtocolVersion(protocolVersion)) return;
 
+            if (server->mSupportedFileDescriptorTransportModes.test(
+                        header.fileDescriptorTransportMode)) {
+                session->setFileDescriptorTransportMode(
+                        static_cast<RpcSession::FileDescriptorTransportMode>(
+                                header.fileDescriptorTransportMode));
+            } else {
+                ALOGE("Rejecting connection: FileDescriptorTransportMode is not supported: %hhu",
+                      header.fileDescriptorTransportMode);
+                return;
+            }
+
             // if null, falls back to server root
             sp<IBinder> sessionSpecificRoot;
             if (server->mRootObjectFactory != nullptr) {
-                sessionSpecificRoot =
-                        server->mRootObjectFactory(reinterpret_cast<const sockaddr*>(&addr),
-                                                   addrLen);
+                sessionSpecificRoot = server->mRootObjectFactory(addr.data(), addrLen);
                 if (sessionSpecificRoot == nullptr) {
                     ALOGE("Warning: server returned null from root object factory");
                 }
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index e79cb86..41842a7 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -34,6 +34,7 @@
 #include <binder/RpcServer.h>
 #include <binder/RpcTransportRaw.h>
 #include <binder/Stability.h>
+#include <utils/Compat.h>
 #include <utils/String8.h>
 
 #include "FdTrigger.h"
@@ -42,11 +43,7 @@
 #include "RpcWireFormat.h"
 #include "Utils.h"
 
-#ifdef __GLIBC__
-extern "C" pid_t gettid();
-#endif
-
-#ifndef __ANDROID_RECOVERY__
+#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
 #include <android_runtime/vm.h>
 #include <jni.h>
 #endif
@@ -132,6 +129,14 @@
     return mProtocolVersion;
 }
 
+void RpcSession::setFileDescriptorTransportMode(FileDescriptorTransportMode mode) {
+    mFileDescriptorTransportMode = mode;
+}
+
+RpcSession::FileDescriptorTransportMode RpcSession::getFileDescriptorTransportMode() {
+    return mFileDescriptorTransportMode;
+}
+
 status_t RpcSession::setupUnixDomainClient(const char* path) {
     return setupSocketClient(UnixSocketAddress(path));
 }
@@ -152,13 +157,7 @@
 }
 
 status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
-    // Why passing raw fd? When fd is passed as reference, Clang analyzer sees that the variable
-    // `fd` is a moved-from object. To work-around the issue, unwrap the raw fd from the outer `fd`,
-    // pass the raw fd by value to the lambda, and then finally wrap it in unique_fd inside the
-    // lambda.
-    return setupClient([&, raw = fd.release()](const std::vector<uint8_t>& sessionId,
-                                               bool incoming) -> status_t {
-        unique_fd fd(raw);
+    return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) -> status_t {
         if (!fd.ok()) {
             fd = request();
             if (!fd.ok()) return BAD_VALUE;
@@ -167,7 +166,9 @@
             ALOGE("setupPreconnectedClient: %s", res.error().message().c_str());
             return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code();
         }
-        return initAndAddConnection(std::move(fd), sessionId, incoming);
+        status_t status = initAndAddConnection(std::move(fd), sessionId, incoming);
+        fd = unique_fd(); // Explicitly reset after move to avoid analyzer warning.
+        return status;
     });
 }
 
@@ -323,7 +324,7 @@
 }
 
 namespace {
-#ifdef __ANDROID_RECOVERY__
+#if !defined(__ANDROID__) || defined(__ANDROID_RECOVERY__)
 class JavaThreadAttacher {};
 #else
 // RAII object for attaching / detaching current thread to JVM if Android Runtime exists. If
@@ -613,6 +614,7 @@
     RpcConnectionHeader header{
             .version = mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION),
             .options = 0,
+            .fileDescriptorTransportMode = static_cast<uint8_t>(mFileDescriptorTransportMode),
             .sessionIdSize = static_cast<uint16_t>(sessionId.size()),
     };
 
@@ -621,8 +623,8 @@
     }
 
     iovec headerIov{&header, sizeof(header)};
-    auto sendHeaderStatus =
-            server->interruptableWriteFully(mShutdownTrigger.get(), &headerIov, 1, {});
+    auto sendHeaderStatus = server->interruptableWriteFully(mShutdownTrigger.get(), &headerIov, 1,
+                                                            std::nullopt, nullptr);
     if (sendHeaderStatus != OK) {
         ALOGE("Could not write connection header to socket: %s",
               statusToString(sendHeaderStatus).c_str());
@@ -633,7 +635,8 @@
         iovec sessionIov{const_cast<void*>(static_cast<const void*>(sessionId.data())),
                          sessionId.size()};
         auto sendSessionIdStatus =
-                server->interruptableWriteFully(mShutdownTrigger.get(), &sessionIov, 1, {});
+                server->interruptableWriteFully(mShutdownTrigger.get(), &sessionIov, 1,
+                                                std::nullopt, nullptr);
         if (sendSessionIdStatus != OK) {
             ALOGE("Could not write session ID ('%s') to socket: %s",
                   base::HexString(sessionId.data(), sessionId.size()).c_str(),
@@ -696,7 +699,7 @@
     {
         std::lock_guard<std::mutex> _l(mMutex);
         connection->rpcTransport = std::move(rpcTransport);
-        connection->exclusiveTid = gettid();
+        connection->exclusiveTid = base::GetThreadId();
         mConnections.mOutgoing.push_back(connection);
     }
 
@@ -706,10 +709,7 @@
                 mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
     }
 
-    {
-        std::lock_guard<std::mutex> _l(mMutex);
-        connection->exclusiveTid = std::nullopt;
-    }
+    clearConnectionTid(connection);
 
     return status;
 }
@@ -722,6 +722,7 @@
     LOG_ALWAYS_FATAL_IF(mEventListener != nullptr);
     LOG_ALWAYS_FATAL_IF(eventListener == nullptr);
     LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr);
+    LOG_ALWAYS_FATAL_IF(mCtx != nullptr);
 
     mShutdownTrigger = FdTrigger::make();
     if (mShutdownTrigger == nullptr) return false;
@@ -753,7 +754,7 @@
 
     sp<RpcConnection> session = sp<RpcConnection>::make();
     session->rpcTransport = std::move(rpcTransport);
-    session->exclusiveTid = gettid();
+    session->exclusiveTid = base::GetThreadId();
 
     mConnections.mIncoming.push_back(session);
     mConnections.mMaxIncoming = mConnections.mIncoming.size();
@@ -779,6 +780,15 @@
     return false;
 }
 
+void RpcSession::clearConnectionTid(const sp<RpcConnection>& connection) {
+    std::unique_lock<std::mutex> _l(mMutex);
+    connection->exclusiveTid = std::nullopt;
+    if (mConnections.mWaitingThreads > 0) {
+        _l.unlock();
+        mAvailableConnectionCv.notify_one();
+    }
+}
+
 std::vector<uint8_t> RpcSession::getCertificate(RpcCertificateFormat format) {
     return mCtx->getCertificate(format);
 }
@@ -789,7 +799,7 @@
     connection->mConnection = nullptr;
     connection->mReentrant = false;
 
-    pid_t tid = gettid();
+    uint64_t tid = base::GetThreadId();
     std::unique_lock<std::mutex> _l(session->mMutex);
 
     session->mConnections.mWaitingThreads++;
@@ -853,10 +863,16 @@
         }
 
         if (session->mConnections.mOutgoing.size() == 0) {
-            ALOGE("Session has no client connections. This is required for an RPC server to make "
-                  "any non-nested (e.g. oneway or on another thread) calls. Use: %d. Server "
-                  "connections: %zu",
-                  static_cast<int>(use), session->mConnections.mIncoming.size());
+            ALOGE("Session has no outgoing connections. This is required for an RPC server to make "
+                  "any non-nested (e.g. oneway or on another thread) calls. Use code request "
+                  "reason: %d. Incoming connections: %zu. %s.",
+                  static_cast<int>(use), session->mConnections.mIncoming.size(),
+                  (session->server()
+                           ? "This is a server session, so see RpcSession::setMaxIncomingThreads "
+                             "for the corresponding client"
+                           : "This is a client session, so see RpcSession::setMaxOutgoingThreads "
+                             "for this client or RpcServer::setMaxThreads for the corresponding "
+                             "server"));
             return WOULD_BLOCK;
         }
 
@@ -870,7 +886,7 @@
     return OK;
 }
 
-void RpcSession::ExclusiveConnection::findConnection(pid_t tid, sp<RpcConnection>* exclusive,
+void RpcSession::ExclusiveConnection::findConnection(uint64_t tid, sp<RpcConnection>* exclusive,
                                                      sp<RpcConnection>* available,
                                                      std::vector<sp<RpcConnection>>& sockets,
                                                      size_t socketsIndexHint) {
@@ -902,12 +918,7 @@
     // is using this fd, and it retains the right to it. So, we don't give up
     // exclusive ownership, and no thread is freed.
     if (!mReentrant && mConnection != nullptr) {
-        std::unique_lock<std::mutex> _l(mSession->mMutex);
-        mConnection->exclusiveTid = std::nullopt;
-        if (mSession->mConnections.mWaitingThreads > 0) {
-            _l.unlock();
-            mSession->mAvailableConnectionCv.notify_one();
-        }
+        mSession->clearConnectionTid(mConnection);
     }
 }
 
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 2e7084e..2b1d0e5 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -21,12 +21,14 @@
 #include <android-base/hex.h>
 #include <android-base/macros.h>
 #include <android-base/scopeguard.h>
+#include <android-base/stringprintf.h>
 #include <binder/BpBinder.h>
 #include <binder/IPCThreadState.h>
 #include <binder/RpcServer.h>
 
 #include "Debug.h"
 #include "RpcWireFormat.h"
+#include "Utils.h"
 
 #include <random>
 
@@ -35,6 +37,7 @@
 namespace android {
 
 using base::ScopeGuard;
+using base::StringPrintf;
 
 #if RPC_FLAKE_PRONE
 void rpcMaybeWaitToFlake() {
@@ -49,6 +52,15 @@
 }
 #endif
 
+static bool enableAncillaryFds(RpcSession::FileDescriptorTransportMode mode) {
+    switch (mode) {
+        case RpcSession::FileDescriptorTransportMode::NONE:
+            return false;
+        case RpcSession::FileDescriptorTransportMode::UNIX:
+            return true;
+    }
+}
+
 RpcState::RpcState() {}
 RpcState::~RpcState() {}
 
@@ -309,17 +321,21 @@
     mData.reset(new (std::nothrow) uint8_t[size]);
 }
 
-status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection,
-                           const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs,
-                           const std::function<status_t()>& altPoll) {
+status_t RpcState::rpcSend(
+        const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+        const char* what, iovec* iovs, int niovs,
+        const std::optional<android::base::function_ref<status_t()>>& altPoll,
+        const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
     for (int i = 0; i < niovs; i++) {
-        LOG_RPC_DETAIL("Sending %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+        LOG_RPC_DETAIL("Sending %s (part %d of %d) on RpcTransport %p: %s",
+                       what, i + 1, niovs, connection->rpcTransport.get(),
                        android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
     }
 
     if (status_t status =
                 connection->rpcTransport->interruptableWriteFully(session->mShutdownTrigger.get(),
-                                                                  iovs, niovs, altPoll);
+                                                                  iovs, niovs, altPoll,
+                                                                  ancillaryFds);
         status != OK) {
         LOG_RPC_DETAIL("Failed to write %s (%d iovs) on RpcTransport %p, error: %s", what, niovs,
                        connection->rpcTransport.get(), statusToString(status).c_str());
@@ -332,9 +348,9 @@
 
 status_t RpcState::rpcRec(const sp<RpcSession::RpcConnection>& connection,
                           const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs) {
-    if (status_t status =
-                connection->rpcTransport->interruptableReadFully(session->mShutdownTrigger.get(),
-                                                                 iovs, niovs, {});
+    if (status_t status = connection->rpcTransport->interruptableReadFully(
+                session->mShutdownTrigger.get(), iovs, niovs, std::nullopt,
+                enableAncillaryFds(session->getFileDescriptorTransportMode()));
         status != OK) {
         LOG_RPC_DETAIL("Failed to read %s (%d iovs) on RpcTransport %p, error: %s", what, niovs,
                        connection->rpcTransport.get(), statusToString(status).c_str());
@@ -343,7 +359,8 @@
     }
 
     for (int i = 0; i < niovs; i++) {
-        LOG_RPC_DETAIL("Received %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+        LOG_RPC_DETAIL("Received %s (part %d of %d) on RpcTransport %p: %s",
+                       what, i + 1, niovs, connection->rpcTransport.get(),
                        android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
     }
     return OK;
@@ -367,7 +384,7 @@
             .msg = RPC_CONNECTION_INIT_OKAY,
     };
     iovec iov{&init, sizeof(init)};
-    return rpcSend(connection, session, "connection init", &iov, 1);
+    return rpcSend(connection, session, "connection init", &iov, 1, std::nullopt);
 }
 
 status_t RpcState::readConnectionInit(const sp<RpcSession::RpcConnection>& connection,
@@ -446,20 +463,12 @@
 status_t RpcState::transact(const sp<RpcSession::RpcConnection>& connection,
                             const sp<IBinder>& binder, uint32_t code, const Parcel& data,
                             const sp<RpcSession>& session, Parcel* reply, uint32_t flags) {
-    if (!data.isForRpc()) {
-        ALOGE("Refusing to send RPC with parcel not crafted for RPC call on binder %p code "
-              "%" PRIu32,
-              binder.get(), code);
-        return BAD_TYPE;
+    std::string errorMsg;
+    if (status_t status = validateParcel(session, data, &errorMsg); status != OK) {
+        ALOGE("Refusing to send RPC on binder %p code %" PRIu32 ": Parcel %p failed validation: %s",
+              binder.get(), code, &data, errorMsg.c_str());
+        return status;
     }
-
-    if (data.objectsCount() != 0) {
-        ALOGE("Parcel at %p has attached objects but is being used in an RPC call on binder %p "
-              "code %" PRIu32,
-              &data, binder.get(), code);
-        return BAD_TYPE;
-    }
-
     uint64_t address;
     if (status_t status = onBinderLeaving(session, binder, &address); status != OK) return status;
 
@@ -491,14 +500,21 @@
         }
     }
 
-    LOG_ALWAYS_FATAL_IF(std::numeric_limits<int32_t>::max() - sizeof(RpcWireHeader) -
-                                        sizeof(RpcWireTransaction) <
-                                data.dataSize(),
-                        "Too much data %zu", data.dataSize());
+    auto* rpcFields = data.maybeRpcFields();
+    LOG_ALWAYS_FATAL_IF(rpcFields == nullptr);
 
+    Span<const uint32_t> objectTableSpan = Span<const uint32_t>{rpcFields->mObjectPositions.data(),
+                                                                rpcFields->mObjectPositions.size()};
+
+    uint32_t bodySize;
+    LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(sizeof(RpcWireTransaction), data.dataSize(),
+                                               &bodySize) ||
+                                __builtin_add_overflow(objectTableSpan.byteSize(), bodySize,
+                                                       &bodySize),
+                        "Too much data %zu", data.dataSize());
     RpcWireHeader command{
             .command = RPC_COMMAND_TRANSACT,
-            .bodySize = static_cast<uint32_t>(sizeof(RpcWireTransaction) + data.dataSize()),
+            .bodySize = bodySize,
     };
 
     RpcWireTransaction transaction{
@@ -506,6 +522,8 @@
             .code = code,
             .flags = flags,
             .asyncNumber = asyncNumber,
+            // bodySize didn't overflow => this cast is safe
+            .parcelDataSize = static_cast<uint32_t>(data.dataSize()),
     };
 
     constexpr size_t kWaitMaxUs = 1000000;
@@ -514,31 +532,33 @@
 
     // Oneway calls have no sync point, so if many are sent before, whether this
     // is a twoway or oneway transaction, they may have filled up the socket.
-    // So, make sure we drain them before polling.
-    std::function<status_t()> drainRefs = [&] {
-        if (waitUs > kWaitLogUs) {
-            ALOGE("Cannot send command, trying to process pending refcounts. Waiting %zuus. Too "
-                  "many oneway calls?",
-                  waitUs);
-        }
-
-        if (waitUs > 0) {
-            usleep(waitUs);
-            waitUs = std::min(kWaitMaxUs, waitUs * 2);
-        } else {
-            waitUs = 1;
-        }
-
-        return drainCommands(connection, session, CommandType::CONTROL_ONLY);
-    };
+    // So, make sure we drain them before polling
 
     iovec iovs[]{
             {&command, sizeof(RpcWireHeader)},
             {&transaction, sizeof(RpcWireTransaction)},
             {const_cast<uint8_t*>(data.data()), data.dataSize()},
+            objectTableSpan.toIovec(),
     };
-    if (status_t status =
-                rpcSend(connection, session, "transaction", iovs, arraysize(iovs), drainRefs);
+    if (status_t status = rpcSend(
+                connection, session, "transaction", iovs, arraysize(iovs),
+                [&] {
+                    if (waitUs > kWaitLogUs) {
+                        ALOGE("Cannot send command, trying to process pending refcounts. Waiting "
+                              "%zuus. Too many oneway calls?",
+                              waitUs);
+                    }
+
+                    if (waitUs > 0) {
+                        usleep(waitUs);
+                        waitUs = std::min(kWaitMaxUs, waitUs * 2);
+                    } else {
+                        waitUs = 1;
+                    }
+
+                    return drainCommands(connection, session, CommandType::CONTROL_ONLY);
+                },
+                rpcFields->mFds.get());
         status != OK) {
         // TODO(b/167966510): need to undo onBinderLeaving - we know the
         // refcount isn't successfully transferred.
@@ -561,7 +581,7 @@
 static void cleanup_reply_data(Parcel* p, const uint8_t* data, size_t dataSize,
                                const binder_size_t* objects, size_t objectsCount) {
     (void)p;
-    delete[] const_cast<uint8_t*>(data - offsetof(RpcWireReply, data));
+    delete[] const_cast<uint8_t*>(data);
     (void)dataSize;
     LOG_ALWAYS_FATAL_IF(objects != nullptr);
     LOG_ALWAYS_FATAL_IF(objectsCount != 0, "%zu objects remaining", objectsCount);
@@ -583,29 +603,59 @@
             return status;
     }
 
-    CommandData data(command.bodySize);
-    if (!data.valid()) return NO_MEMORY;
+    const size_t rpcReplyWireSize = RpcWireReply::wireSize(session->getProtocolVersion().value());
 
-    iovec iov{data.data(), command.bodySize};
-    if (status_t status = rpcRec(connection, session, "reply body", &iov, 1); status != OK)
-        return status;
-
-    if (command.bodySize < sizeof(RpcWireReply)) {
+    if (command.bodySize < rpcReplyWireSize) {
         ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireReply. Terminating!",
               sizeof(RpcWireReply), command.bodySize);
         (void)session->shutdownAndWait(false);
         return BAD_VALUE;
     }
-    RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data.data());
-    if (rpcReply->status != OK) return rpcReply->status;
+
+    RpcWireReply rpcReply;
+    memset(&rpcReply, 0, sizeof(RpcWireReply)); // zero because of potential short read
+
+    CommandData data(command.bodySize - rpcReplyWireSize);
+    if (!data.valid()) return NO_MEMORY;
+
+    iovec iovs[]{
+            {&rpcReply, rpcReplyWireSize},
+            {data.data(), data.size()},
+    };
+    if (status_t status = rpcRec(connection, session, "reply body", iovs, arraysize(iovs));
+        status != OK)
+        return status;
+
+    // Check if the reply came with any ancillary data.
+    std::vector<base::unique_fd> pendingFds;
+    if (status_t status = connection->rpcTransport->consumePendingAncillaryData(&pendingFds);
+        status != OK) {
+        return status;
+    }
+
+    if (rpcReply.status != OK) return rpcReply.status;
+
+    Span<const uint8_t> parcelSpan = {data.data(), data.size()};
+    Span<const uint32_t> objectTableSpan;
+    if (session->getProtocolVersion().value() >=
+        RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
+        Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(rpcReply.parcelDataSize);
+        std::optional<Span<const uint32_t>> maybeSpan =
+                objectTableBytes.reinterpret<const uint32_t>();
+        if (!maybeSpan.has_value()) {
+            ALOGE("Bad object table size inferred from RpcWireReply. Saw bodySize=%" PRId32
+                  " sizeofHeader=%zu parcelSize=%" PRId32 " objectTableBytesSize=%zu. Terminating!",
+                  command.bodySize, rpcReplyWireSize, rpcReply.parcelDataSize,
+                  objectTableBytes.size);
+            return BAD_VALUE;
+        }
+        objectTableSpan = *maybeSpan;
+    }
 
     data.release();
-    reply->ipcSetDataReference(rpcReply->data, command.bodySize - offsetof(RpcWireReply, data),
-                               nullptr, 0, cleanup_reply_data);
-
-    reply->markForRpc(session);
-
-    return OK;
+    return reply->rpcSetDataReference(session, parcelSpan.data, parcelSpan.size,
+                                      objectTableSpan.data, objectTableSpan.size,
+                                      std::move(pendingFds), cleanup_reply_data);
 }
 
 status_t RpcState::sendDecStrongToTarget(const sp<RpcSession::RpcConnection>& connection,
@@ -641,7 +691,7 @@
             .bodySize = sizeof(RpcDecStrong),
     };
     iovec iovs[]{{&cmd, sizeof(cmd)}, {&body, sizeof(body)}};
-    return rpcSend(connection, session, "dec ref", iovs, arraysize(iovs));
+    return rpcSend(connection, session, "dec ref", iovs, arraysize(iovs), std::nullopt);
 }
 
 status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& connection,
@@ -659,9 +709,12 @@
 
 status_t RpcState::drainCommands(const sp<RpcSession::RpcConnection>& connection,
                                  const sp<RpcSession>& session, CommandType type) {
-    uint8_t buf;
-    while (connection->rpcTransport->peek(&buf, sizeof(buf)).value_or(0) > 0) {
-        status_t status = getAndExecuteCommand(connection, session, type);
+    while (true) {
+        status_t status = connection->rpcTransport->pollRead();
+        if (status == WOULD_BLOCK) break;
+        if (status != OK) return status;
+
+        status = getAndExecuteCommand(connection, session, type);
         if (status != OK) return status;
     }
     return OK;
@@ -816,54 +869,82 @@
     reply.markForRpc(session);
 
     if (replyStatus == OK) {
+        // Check if the transaction came with any ancillary data.
+        std::vector<base::unique_fd> pendingFds;
+        if (status_t status = connection->rpcTransport->consumePendingAncillaryData(&pendingFds);
+            status != OK) {
+            return status;
+        }
+
+        Span<const uint8_t> parcelSpan = {transaction->data,
+                                          transactionData.size() -
+                                                  offsetof(RpcWireTransaction, data)};
+        Span<const uint32_t> objectTableSpan;
+        if (session->getProtocolVersion().value() >
+            RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
+            Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(transaction->parcelDataSize);
+            std::optional<Span<const uint32_t>> maybeSpan =
+                    objectTableBytes.reinterpret<const uint32_t>();
+            if (!maybeSpan.has_value()) {
+                ALOGE("Bad object table size inferred from RpcWireTransaction. Saw bodySize=%zu "
+                      "sizeofHeader=%zu parcelSize=%" PRId32
+                      " objectTableBytesSize=%zu. Terminating!",
+                      transactionData.size(), sizeof(RpcWireTransaction),
+                      transaction->parcelDataSize, objectTableBytes.size);
+                return BAD_VALUE;
+            }
+            objectTableSpan = *maybeSpan;
+        }
+
         Parcel data;
         // transaction->data is owned by this function. Parcel borrows this data and
         // only holds onto it for the duration of this function call. Parcel will be
         // deleted before the 'transactionData' object.
-        data.ipcSetDataReference(transaction->data,
-                                 transactionData.size() - offsetof(RpcWireTransaction, data),
-                                 nullptr /*object*/, 0 /*objectCount*/,
-                                 do_nothing_to_transact_data);
-        data.markForRpc(session);
 
-        if (target) {
-            bool origAllowNested = connection->allowNested;
-            connection->allowNested = !oneway;
+        replyStatus = data.rpcSetDataReference(session, parcelSpan.data, parcelSpan.size,
+                                               objectTableSpan.data, objectTableSpan.size,
+                                               std::move(pendingFds), do_nothing_to_transact_data);
 
-            replyStatus = target->transact(transaction->code, data, &reply, transaction->flags);
+        if (replyStatus == OK) {
+            if (target) {
+                bool origAllowNested = connection->allowNested;
+                connection->allowNested = !oneway;
 
-            connection->allowNested = origAllowNested;
-        } else {
-            LOG_RPC_DETAIL("Got special transaction %u", transaction->code);
+                replyStatus = target->transact(transaction->code, data, &reply, transaction->flags);
 
-            switch (transaction->code) {
-                case RPC_SPECIAL_TRANSACT_GET_MAX_THREADS: {
-                    replyStatus = reply.writeInt32(session->getMaxIncomingThreads());
-                    break;
-                }
-                case RPC_SPECIAL_TRANSACT_GET_SESSION_ID: {
-                    // for client connections, this should always report the value
-                    // originally returned from the server, so this is asserting
-                    // that it exists
-                    replyStatus = reply.writeByteVector(session->mId);
-                    break;
-                }
-                default: {
-                    sp<RpcServer> server = session->server();
-                    if (server) {
-                        switch (transaction->code) {
-                            case RPC_SPECIAL_TRANSACT_GET_ROOT: {
-                                sp<IBinder> root = session->mSessionSpecificRootObject
-                                        ?: server->getRootObject();
-                                replyStatus = reply.writeStrongBinder(root);
-                                break;
+                connection->allowNested = origAllowNested;
+            } else {
+                LOG_RPC_DETAIL("Got special transaction %u", transaction->code);
+
+                switch (transaction->code) {
+                    case RPC_SPECIAL_TRANSACT_GET_MAX_THREADS: {
+                        replyStatus = reply.writeInt32(session->getMaxIncomingThreads());
+                        break;
+                    }
+                    case RPC_SPECIAL_TRANSACT_GET_SESSION_ID: {
+                        // for client connections, this should always report the value
+                        // originally returned from the server, so this is asserting
+                        // that it exists
+                        replyStatus = reply.writeByteVector(session->mId);
+                        break;
+                    }
+                    default: {
+                        sp<RpcServer> server = session->server();
+                        if (server) {
+                            switch (transaction->code) {
+                                case RPC_SPECIAL_TRANSACT_GET_ROOT: {
+                                    sp<IBinder> root = session->mSessionSpecificRootObject
+                                            ?: server->getRootObject();
+                                    replyStatus = reply.writeStrongBinder(root);
+                                    break;
+                                }
+                                default: {
+                                    replyStatus = UNKNOWN_TRANSACTION;
+                                }
                             }
-                            default: {
-                                replyStatus = UNKNOWN_TRANSACTION;
-                            }
+                        } else {
+                            ALOGE("Special command sent, but no server object attached.");
                         }
-                    } else {
-                        ALOGE("Special command sent, but no server object attached.");
                     }
                 }
             }
@@ -935,48 +1016,67 @@
         replyStatus = flushExcessBinderRefs(session, addr, target);
     }
 
-    LOG_ALWAYS_FATAL_IF(std::numeric_limits<int32_t>::max() - sizeof(RpcWireHeader) -
-                                        sizeof(RpcWireReply) <
-                                reply.dataSize(),
-                        "Too much data for reply %zu", reply.dataSize());
+    std::string errorMsg;
+    if (status_t status = validateParcel(session, reply, &errorMsg); status != OK) {
+        ALOGE("Reply Parcel failed validation: %s", errorMsg.c_str());
+        // Forward the error to the client of the transaction.
+        reply.freeData();
+        reply.markForRpc(session);
+        replyStatus = status;
+    }
 
+    auto* rpcFields = reply.maybeRpcFields();
+    LOG_ALWAYS_FATAL_IF(rpcFields == nullptr);
+
+    const size_t rpcReplyWireSize = RpcWireReply::wireSize(session->getProtocolVersion().value());
+
+    Span<const uint32_t> objectTableSpan = Span<const uint32_t>{rpcFields->mObjectPositions.data(),
+                                                                rpcFields->mObjectPositions.size()};
+
+    uint32_t bodySize;
+    LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(rpcReplyWireSize, reply.dataSize(), &bodySize) ||
+                                __builtin_add_overflow(objectTableSpan.byteSize(), bodySize,
+                                                       &bodySize),
+                        "Too much data for reply %zu", reply.dataSize());
     RpcWireHeader cmdReply{
             .command = RPC_COMMAND_REPLY,
-            .bodySize = static_cast<uint32_t>(sizeof(RpcWireReply) + reply.dataSize()),
+            .bodySize = bodySize,
     };
     RpcWireReply rpcReply{
             .status = replyStatus,
+            // NOTE: Not necessarily written to socket depending on session
+            // version.
+            // NOTE: bodySize didn't overflow => this cast is safe
+            .parcelDataSize = static_cast<uint32_t>(reply.dataSize()),
+            .reserved = {0, 0, 0},
     };
-
     iovec iovs[]{
             {&cmdReply, sizeof(RpcWireHeader)},
-            {&rpcReply, sizeof(RpcWireReply)},
+            {&rpcReply, rpcReplyWireSize},
             {const_cast<uint8_t*>(reply.data()), reply.dataSize()},
+            objectTableSpan.toIovec(),
     };
-    return rpcSend(connection, session, "reply", iovs, arraysize(iovs));
+    return rpcSend(connection, session, "reply", iovs, arraysize(iovs), std::nullopt,
+                   rpcFields->mFds.get());
 }
 
 status_t RpcState::processDecStrong(const sp<RpcSession::RpcConnection>& connection,
                                     const sp<RpcSession>& session, const RpcWireHeader& command) {
     LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_DEC_STRONG, "command: %d", command.command);
 
-    CommandData commandData(command.bodySize);
-    if (!commandData.valid()) {
-        return NO_MEMORY;
-    }
-    iovec iov{commandData.data(), commandData.size()};
-    if (status_t status = rpcRec(connection, session, "dec ref body", &iov, 1); status != OK)
-        return status;
-
     if (command.bodySize != sizeof(RpcDecStrong)) {
         ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcDecStrong. Terminating!",
               sizeof(RpcDecStrong), command.bodySize);
         (void)session->shutdownAndWait(false);
         return BAD_VALUE;
     }
-    RpcDecStrong* body = reinterpret_cast<RpcDecStrong*>(commandData.data());
 
-    uint64_t addr = RpcWireAddress::toRaw(body->address);
+    RpcDecStrong body;
+    iovec iov{&body, sizeof(RpcDecStrong)};
+    if (status_t status = rpcRec(connection, session, "dec ref body", &iov, 1); status != OK)
+        return status;
+
+    uint64_t addr = RpcWireAddress::toRaw(body.address);
     std::unique_lock<std::mutex> _l(mNodeMutex);
     auto it = mNodeForAddress.find(addr);
     if (it == mNodeForAddress.end()) {
@@ -994,19 +1094,19 @@
         return BAD_VALUE;
     }
 
-    if (it->second.timesSent < body->amount) {
+    if (it->second.timesSent < body.amount) {
         ALOGE("Record of sending binder %zu times, but requested decStrong for %" PRIu64 " of %u",
-              it->second.timesSent, addr, body->amount);
+              it->second.timesSent, addr, body.amount);
         return OK;
     }
 
     LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %" PRIu64,
                         addr);
 
-    LOG_RPC_DETAIL("Processing dec strong of %" PRIu64 " by %u from %zu", addr, body->amount,
+    LOG_RPC_DETAIL("Processing dec strong of %" PRIu64 " by %u from %zu", addr, body.amount,
                    it->second.timesSent);
 
-    it->second.timesSent -= body->amount;
+    it->second.timesSent -= body.amount;
     sp<IBinder> tempHold = tryEraseNode(it);
     _l.unlock();
     tempHold = nullptr; // destructor may make binder calls on this session
@@ -1014,6 +1114,50 @@
     return OK;
 }
 
+status_t RpcState::validateParcel(const sp<RpcSession>& session, const Parcel& parcel,
+                                  std::string* errorMsg) {
+    auto* rpcFields = parcel.maybeRpcFields();
+    if (rpcFields == nullptr) {
+        *errorMsg = "Parcel not crafted for RPC call";
+        return BAD_TYPE;
+    }
+
+    if (rpcFields->mSession != session) {
+        *errorMsg = "Parcel's session doesn't match";
+        return BAD_TYPE;
+    }
+
+    uint32_t protocolVersion = session->getProtocolVersion().value();
+    if (protocolVersion < RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE &&
+        !rpcFields->mObjectPositions.empty()) {
+        *errorMsg = StringPrintf("Parcel has attached objects but the session's protocol version "
+                                 "(%" PRIu32 ") is too old, must be at least %" PRIu32,
+                                 protocolVersion,
+                                 RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE);
+        return BAD_VALUE;
+    }
+
+    if (rpcFields->mFds && !rpcFields->mFds->empty()) {
+        switch (session->getFileDescriptorTransportMode()) {
+            case RpcSession::FileDescriptorTransportMode::NONE:
+                *errorMsg =
+                        "Parcel has file descriptors, but no file descriptor transport is enabled";
+                return FDS_NOT_ALLOWED;
+            case RpcSession::FileDescriptorTransportMode::UNIX: {
+                constexpr size_t kMaxFdsPerMsg = 253;
+                if (rpcFields->mFds->size() > kMaxFdsPerMsg) {
+                    *errorMsg = StringPrintf("Too many file descriptors in Parcel for unix "
+                                             "domain socket: %zu (max is %zu)",
+                                             rpcFields->mFds->size(), kMaxFdsPerMsg);
+                    return BAD_VALUE;
+                }
+            }
+        }
+    }
+
+    return OK;
+}
+
 sp<IBinder> RpcState::tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it) {
     sp<IBinder> ref;
 
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index f4a0894..08a314e 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -178,9 +178,12 @@
         size_t mSize;
     };
 
-    [[nodiscard]] status_t rpcSend(const sp<RpcSession::RpcConnection>& connection,
-                                   const sp<RpcSession>& session, const char* what, iovec* iovs,
-                                   int niovs, const std::function<status_t()>& altPoll = nullptr);
+    [[nodiscard]] status_t rpcSend(
+            const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+            const char* what, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds =
+                    nullptr);
     [[nodiscard]] status_t rpcRec(const sp<RpcSession::RpcConnection>& connection,
                                   const sp<RpcSession>& session, const char* what, iovec* iovs,
                                   int niovs);
@@ -200,6 +203,10 @@
                                             const sp<RpcSession>& session,
                                             const RpcWireHeader& command);
 
+    // Whether `parcel` is compatible with `session`.
+    [[nodiscard]] static status_t validateParcel(const sp<RpcSession>& session,
+                                                 const Parcel& parcel, std::string* errorMsg);
+
     struct BinderNode {
         // Two cases:
         // A - local binder we are serving
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 636e5d0..d9059e9 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -18,35 +18,48 @@
 #include <log/log.h>
 
 #include <poll.h>
+#include <stddef.h>
 
 #include <binder/RpcTransportRaw.h>
 
 #include "FdTrigger.h"
 #include "RpcState.h"
 
-using android::base::ErrnoError;
-using android::base::Result;
-
 namespace android {
 
 namespace {
 
+// Linux kernel supports up to 253 (from SCM_MAX_FD) for unix sockets.
+constexpr size_t kMaxFdsPerMsg = 253;
+
 // RpcTransport with TLS disabled.
 class RpcTransportRaw : public RpcTransport {
 public:
     explicit RpcTransportRaw(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
-    Result<size_t> peek(void *buf, size_t size) override {
-        ssize_t ret = TEMP_FAILURE_RETRY(::recv(mSocket.get(), buf, size, MSG_PEEK));
+    status_t pollRead(void) override {
+        uint8_t buf;
+        ssize_t ret = TEMP_FAILURE_RETRY(
+                ::recv(mSocket.get(), &buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT));
         if (ret < 0) {
-            return ErrnoError() << "recv(MSG_PEEK)";
+            int savedErrno = errno;
+            if (savedErrno == EAGAIN || savedErrno == EWOULDBLOCK) {
+                return WOULD_BLOCK;
+            }
+
+            LOG_RPC_DETAIL("RpcTransport poll(): %s", strerror(savedErrno));
+            return -savedErrno;
+        } else if (ret == 0) {
+            return DEAD_OBJECT;
         }
-        return ret;
+
+        return OK;
     }
 
     template <typename SendOrReceive>
-    status_t interruptableReadOrWrite(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                      SendOrReceive sendOrReceiveFun, const char* funName,
-                                      int16_t event, const std::function<status_t()>& altPoll) {
+    status_t interruptableReadOrWrite(
+            FdTrigger* fdTrigger, iovec* iovs, int niovs, SendOrReceive sendOrReceiveFun,
+            const char* funName, int16_t event,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll) {
         MAYBE_WAIT_IN_FLAKE_MODE;
 
         if (niovs < 0) {
@@ -76,15 +89,7 @@
 
         bool havePolled = false;
         while (true) {
-            msghdr msg{
-                    .msg_iov = iovs,
-                    // posix uses int, glibc uses size_t.  niovs is a
-                    // non-negative int and can be cast to either.
-                    .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
-            };
-            ssize_t processSize =
-                    TEMP_FAILURE_RETRY(sendOrReceiveFun(mSocket.get(), &msg, MSG_NOSIGNAL));
-
+            ssize_t processSize = sendOrReceiveFun(iovs, niovs);
             if (processSize < 0) {
                 int savedErrno = errno;
 
@@ -121,7 +126,7 @@
             }
 
             if (altPoll) {
-                if (status_t status = altPoll(); status != OK) return status;
+                if (status_t status = (*altPoll)(); status != OK) return status;
                 if (fdTrigger->isTriggered()) {
                     return DEAD_OBJECT;
                 }
@@ -134,20 +139,135 @@
         }
     }
 
-    status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                     const std::function<status_t()>& altPoll) override {
-        return interruptableReadOrWrite(fdTrigger, iovs, niovs, sendmsg, "sendmsg", POLLOUT,
-                                        altPoll);
+    status_t interruptableWriteFully(
+            FdTrigger* fdTrigger, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
+            override {
+        bool sentFds = false;
+        auto send = [&](iovec* iovs, int niovs) -> ssize_t {
+            if (ancillaryFds != nullptr && !ancillaryFds->empty() && !sentFds) {
+                if (ancillaryFds->size() > kMaxFdsPerMsg) {
+                    // This shouldn't happen because we check the FD count in RpcState.
+                    ALOGE("Saw too many file descriptors in RpcTransportCtxRaw: %zu (max is %zu). "
+                          "Aborting session.",
+                          ancillaryFds->size(), kMaxFdsPerMsg);
+                    errno = EINVAL;
+                    return -1;
+                }
+
+                // CMSG_DATA is not necessarily aligned, so we copy the FDs into a buffer and then
+                // use memcpy.
+                int fds[kMaxFdsPerMsg];
+                for (size_t i = 0; i < ancillaryFds->size(); i++) {
+                    fds[i] = std::visit([](const auto& fd) { return fd.get(); },
+                                        ancillaryFds->at(i));
+                }
+                const size_t fdsByteSize = sizeof(int) * ancillaryFds->size();
+
+                alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(int) * kMaxFdsPerMsg)];
+
+                msghdr msg{
+                        .msg_iov = iovs,
+                        .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+                        .msg_control = msgControlBuf,
+                        .msg_controllen = sizeof(msgControlBuf),
+                };
+
+                cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+                cmsg->cmsg_level = SOL_SOCKET;
+                cmsg->cmsg_type = SCM_RIGHTS;
+                cmsg->cmsg_len = CMSG_LEN(fdsByteSize);
+                memcpy(CMSG_DATA(cmsg), fds, fdsByteSize);
+
+                msg.msg_controllen = CMSG_SPACE(fdsByteSize);
+
+                ssize_t processedSize = TEMP_FAILURE_RETRY(
+                        sendmsg(mSocket.get(), &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC));
+                if (processedSize > 0) {
+                    sentFds = true;
+                }
+                return processedSize;
+            }
+
+            msghdr msg{
+                    .msg_iov = iovs,
+                    // posix uses int, glibc uses size_t.  niovs is a
+                    // non-negative int and can be cast to either.
+                    .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+            };
+            return TEMP_FAILURE_RETRY(sendmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
+        };
+        return interruptableReadOrWrite(fdTrigger, iovs, niovs, send, "sendmsg", POLLOUT, altPoll);
     }
 
-    status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                    const std::function<status_t()>& altPoll) override {
-        return interruptableReadOrWrite(fdTrigger, iovs, niovs, recvmsg, "recvmsg", POLLIN,
-                                        altPoll);
+    status_t interruptableReadFully(
+            FdTrigger* fdTrigger, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            bool enableAncillaryFds) override {
+        auto recv = [&](iovec* iovs, int niovs) -> ssize_t {
+            if (enableAncillaryFds) {
+                int fdBuffer[kMaxFdsPerMsg];
+                alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(fdBuffer))];
+
+                msghdr msg{
+                        .msg_iov = iovs,
+                        .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+                        .msg_control = msgControlBuf,
+                        .msg_controllen = sizeof(msgControlBuf),
+                };
+                ssize_t processSize =
+                        TEMP_FAILURE_RETRY(recvmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
+                if (processSize < 0) {
+                    return -1;
+                }
+
+                for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr;
+                     cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+                    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+                        // NOTE: It is tempting to reinterpret_cast, but cmsg(3) explicitly asks
+                        // application devs to memcpy the data to ensure memory alignment.
+                        size_t dataLen = cmsg->cmsg_len - CMSG_LEN(0);
+                        memcpy(fdBuffer, CMSG_DATA(cmsg), dataLen);
+                        size_t fdCount = dataLen / sizeof(int);
+                        for (size_t i = 0; i < fdCount; i++) {
+                            mFdsPendingRead.emplace_back(fdBuffer[i]);
+                        }
+                        break;
+                    }
+                }
+
+                if (msg.msg_flags & MSG_CTRUNC) {
+                    ALOGE("msg was truncated. Aborting session.");
+                    errno = EPIPE;
+                    return -1;
+                }
+
+                return processSize;
+            }
+            msghdr msg{
+                    .msg_iov = iovs,
+                    // posix uses int, glibc uses size_t.  niovs is a
+                    // non-negative int and can be cast to either.
+                    .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+            };
+            return TEMP_FAILURE_RETRY(recvmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
+        };
+        return interruptableReadOrWrite(fdTrigger, iovs, niovs, recv, "recvmsg", POLLIN, altPoll);
+    }
+
+    status_t consumePendingAncillaryData(std::vector<base::unique_fd>* fds) override {
+        fds->reserve(fds->size() + mFdsPendingRead.size());
+        for (auto& fd : mFdsPendingRead) {
+            fds->emplace_back(std::move(fd));
+        }
+        mFdsPendingRead.clear();
+        return OK;
     }
 
 private:
     base::unique_fd mSocket;
+    std::vector<base::unique_fd> mFdsPendingRead;
 };
 
 // RpcTransportCtx with TLS disabled.
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index 3936204..7783111 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -37,10 +37,6 @@
 #define LOG_TLS_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
 #endif
 
-using android::base::ErrnoError;
-using android::base::Error;
-using android::base::Result;
-
 namespace android {
 namespace {
 
@@ -165,17 +161,8 @@
         return ret;
     }
 
-    // |sslError| should be from Ssl::getError().
-    // If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
-    // return error. Also return error if |fdTrigger| is triggered before or during poll().
-    status_t pollForSslError(android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger,
-                             const char* fnString, int additionalEvent,
-                             const std::function<status_t()>& altPoll) {
+    status_t toStatus(int sslError, const char* fnString) {
         switch (sslError) {
-            case SSL_ERROR_WANT_READ:
-                return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString, altPoll);
-            case SSL_ERROR_WANT_WRITE:
-                return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString, altPoll);
             case SSL_ERROR_SYSCALL: {
                 auto queue = toString();
                 LOG_TLS_DETAIL("%s(): %s. Treating as DEAD_OBJECT. Error queue: %s", fnString,
@@ -191,14 +178,32 @@
         }
     }
 
+    // |sslError| should be from Ssl::getError().
+    // If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
+    // return error. Also return error if |fdTrigger| is triggered before or during poll().
+    status_t pollForSslError(
+            android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger, const char* fnString,
+            int additionalEvent,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll) {
+        switch (sslError) {
+            case SSL_ERROR_WANT_READ:
+                return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString, altPoll);
+            case SSL_ERROR_WANT_WRITE:
+                return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString, altPoll);
+            default:
+                return toStatus(sslError, fnString);
+        }
+    }
+
 private:
     bool mHandled = false;
 
     status_t handlePoll(int event, android::base::borrowed_fd fd, FdTrigger* fdTrigger,
-                        const char* fnString, const std::function<status_t()>& altPoll) {
+                        const char* fnString,
+                        const std::optional<android::base::function_ref<status_t()>>& altPoll) {
         status_t ret;
         if (altPoll) {
-            ret = altPoll();
+            ret = (*altPoll)();
             if (fdTrigger->isTriggered()) ret = DEAD_OBJECT;
         } else {
             ret = fdTrigger->triggerablePoll(fd, event);
@@ -274,11 +279,21 @@
 public:
     RpcTransportTls(android::base::unique_fd socket, Ssl ssl)
           : mSocket(std::move(socket)), mSsl(std::move(ssl)) {}
-    Result<size_t> peek(void* buf, size_t size) override;
-    status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                     const std::function<status_t()>& altPoll) override;
-    status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                    const std::function<status_t()>& altPoll) override;
+    status_t pollRead(void) override;
+    status_t interruptableWriteFully(
+            FdTrigger* fdTrigger, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
+            override;
+    status_t interruptableReadFully(
+            FdTrigger* fdTrigger, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            bool enableAncillaryFds) override;
+
+    status_t consumePendingAncillaryData(std::vector<base::unique_fd>* fds) override {
+        (void)fds;
+        return OK;
+    }
 
 private:
     android::base::unique_fd mSocket;
@@ -286,25 +301,30 @@
 };
 
 // Error code is errno.
-Result<size_t> RpcTransportTls::peek(void* buf, size_t size) {
-    size_t todo = std::min<size_t>(size, std::numeric_limits<int>::max());
-    auto [ret, errorQueue] = mSsl.call(SSL_peek, buf, static_cast<int>(todo));
+status_t RpcTransportTls::pollRead(void) {
+    uint8_t buf;
+    auto [ret, errorQueue] = mSsl.call(SSL_peek, &buf, sizeof(buf));
     if (ret < 0) {
         int err = mSsl.getError(ret);
         if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
             // Seen EAGAIN / EWOULDBLOCK on recv(2) / send(2).
             // Like RpcTransportRaw::peek(), don't handle it here.
-            return Error(EWOULDBLOCK) << "SSL_peek(): " << errorQueue.toString();
+            errorQueue.clear();
+            return WOULD_BLOCK;
         }
-        return Error() << "SSL_peek(): " << errorQueue.toString();
+        return errorQueue.toStatus(err, "SSL_peek");
     }
     errorQueue.clear();
     LOG_TLS_DETAIL("TLS: Peeked %d bytes!", ret);
-    return ret;
+    return OK;
 }
 
-status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                                  const std::function<status_t()>& altPoll) {
+status_t RpcTransportTls::interruptableWriteFully(
+        FdTrigger* fdTrigger, iovec* iovs, int niovs,
+        const std::optional<android::base::function_ref<status_t()>>& altPoll,
+        const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
+    (void)ancillaryFds;
+
     MAYBE_WAIT_IN_FLAKE_MODE;
 
     if (niovs < 0) return BAD_VALUE;
@@ -345,8 +365,12 @@
     return OK;
 }
 
-status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                                 const std::function<status_t()>& altPoll) {
+status_t RpcTransportTls::interruptableReadFully(
+        FdTrigger* fdTrigger, iovec* iovs, int niovs,
+        const std::optional<android::base::function_ref<status_t()>>& altPoll,
+        bool enableAncillaryFds) {
+    (void)enableAncillaryFds;
+
     MAYBE_WAIT_IN_FLAKE_MODE;
 
     if (niovs < 0) return BAD_VALUE;
@@ -411,8 +435,8 @@
             return false;
         }
         int sslError = ssl->getError(ret);
-        status_t pollStatus =
-                errorQueue.pollForSslError(fd, sslError, fdTrigger, "SSL_do_handshake", 0, {});
+        status_t pollStatus = errorQueue.pollForSslError(fd, sslError, fdTrigger,
+                                                         "SSL_do_handshake", 0, std::nullopt);
         if (pollStatus != OK) return false;
     }
 }
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index 171550e..13989e5 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -45,7 +45,8 @@
 struct RpcConnectionHeader {
     uint32_t version; // maximum supported by caller
     uint8_t options;
-    uint8_t reservered[9];
+    uint8_t fileDescriptorTransportMode;
+    uint8_t reservered[8];
     // Follows is sessionIdSize bytes.
     // if size is 0, this is requesting a new session.
     uint16_t sessionIdSize;
@@ -131,7 +132,10 @@
 
     uint64_t asyncNumber;
 
-    uint32_t reserved[4];
+    // The size of the Parcel data directly following RpcWireTransaction.
+    uint32_t parcelDataSize;
+
+    uint32_t reserved[3];
 
     uint8_t data[];
 };
@@ -139,9 +143,23 @@
 
 struct RpcWireReply {
     int32_t status; // transact return
-    uint8_t data[];
+
+    // -- Fields below only transmitted starting at protocol version 1 --
+
+    // The size of the Parcel data directly following RpcWireReply.
+    uint32_t parcelDataSize;
+
+    uint32_t reserved[3];
+
+    // Byte size of RpcWireReply in the wire protocol.
+    static size_t wireSize(uint32_t protocolVersion) {
+        if (protocolVersion == 0) {
+            return sizeof(int32_t);
+        }
+        return sizeof(RpcWireReply);
+    }
 };
-static_assert(sizeof(RpcWireReply) == 4);
+static_assert(sizeof(RpcWireReply) == 20);
 
 #pragma clang diagnostic pop
 
diff --git a/libs/binder/Static.h b/libs/binder/Static.h
index 83524e8..8444fe7 100644
--- a/libs/binder/Static.h
+++ b/libs/binder/Static.h
@@ -17,8 +17,6 @@
 // All static variables go here, to control initialization and
 // destruction order in the library.
 
-#include <utils/threads.h>
-
 #include <binder/IBinder.h>
 #include <binder/ProcessState.h>
 
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index 83b97d0..dba6587 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -139,6 +139,9 @@
     mMessage = String8(message.value_or(String16()));
 
     // Skip over the remote stack trace data
+    const size_t remote_start = parcel.dataPosition();
+    // Get available size before reading more
+    const size_t remote_avail = parcel.dataAvail();
     int32_t remote_stack_trace_header_size;
     status = parcel.readInt32(&remote_stack_trace_header_size);
     if (status != OK) {
@@ -146,13 +149,16 @@
         return status;
     }
     if (remote_stack_trace_header_size < 0 ||
-        static_cast<size_t>(remote_stack_trace_header_size) > parcel.dataAvail()) {
+        static_cast<size_t>(remote_stack_trace_header_size) > remote_avail) {
 
         android_errorWriteLog(0x534e4554, "132650049");
         setFromStatusT(UNKNOWN_ERROR);
         return UNKNOWN_ERROR;
     }
-    parcel.setDataPosition(parcel.dataPosition() + remote_stack_trace_header_size);
+
+    if (remote_stack_trace_header_size != 0) {
+        parcel.setDataPosition(remote_start + remote_stack_trace_header_size);
+    }
 
     if (mException == EX_SERVICE_SPECIFIC) {
         status = parcel.readInt32(&mErrorCode);
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index ebb0d27..0232f50 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -83,5 +83,10 @@
     {
       "name": "rustBinderSerializationTest"
     }
+  ],
+ "hwasan-presubmit": [
+    {
+      "name": "binderLibTest"
+    }
   ]
 }
diff --git a/libs/binder/Utils.cpp b/libs/binder/Utils.cpp
index d2a5be1..b0289a7 100644
--- a/libs/binder/Utils.cpp
+++ b/libs/binder/Utils.cpp
@@ -16,6 +16,7 @@
 
 #include "Utils.h"
 
+#include <android-base/file.h>
 #include <string.h>
 
 using android::base::ErrnoError;
@@ -38,4 +39,17 @@
     return {};
 }
 
+status_t getRandomBytes(uint8_t* data, size_t size) {
+    int ret = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+    if (ret == -1) {
+        return -errno;
+    }
+
+    base::unique_fd fd(ret);
+    if (!base::ReadFully(fd, data, size)) {
+        return -errno;
+    }
+    return OK;
+}
+
 } // namespace android
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index ff2fad8..37c1262 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -14,12 +14,14 @@
  * limitations under the License.
  */
 
-#include <cstdint>
 #include <stddef.h>
+#include <cstdint>
+#include <optional>
 
 #include <android-base/result.h>
 #include <android-base/unique_fd.h>
 #include <log/log.h>
+#include <utils/Errors.h>
 
 #define TEST_AND_RETURN(value, expr)            \
     do {                                        \
@@ -36,4 +38,39 @@
 
 android::base::Result<void> setNonBlocking(android::base::borrowed_fd fd);
 
+status_t getRandomBytes(uint8_t* data, size_t size);
+
+// View of contiguous sequence. Similar to std::span.
+template <typename T>
+struct Span {
+    T* data = nullptr;
+    size_t size = 0;
+
+    size_t byteSize() { return size * sizeof(T); }
+
+    iovec toIovec() { return {const_cast<std::remove_const_t<T>*>(data), byteSize()}; }
+
+    // Truncates `this` to a length of `offset` and returns a span with the
+    // remainder.
+    //
+    // Aborts if offset > size.
+    Span<T> splitOff(size_t offset) {
+        LOG_ALWAYS_FATAL_IF(offset > size);
+        Span<T> rest = {data + offset, size - offset};
+        size = offset;
+        return rest;
+    }
+
+    // Returns nullopt if the byte size of `this` isn't evenly divisible by sizeof(U).
+    template <typename U>
+    std::optional<Span<U>> reinterpret() const {
+        // Only allow casting from bytes for simplicity.
+        static_assert(std::is_same_v<std::remove_const_t<T>, uint8_t>);
+        if (size % sizeof(U) != 0) {
+            return std::nullopt;
+        }
+        return Span<U>{reinterpret_cast<U*>(data), size / sizeof(U)};
+    }
+};
+
 }   // namespace android
diff --git a/libs/binder/binder_module.h b/libs/binder/binder_module.h
index 793795e..7574c29 100644
--- a/libs/binder/binder_module.h
+++ b/libs/binder/binder_module.h
@@ -100,4 +100,23 @@
 #define BINDER_ENABLE_ONEWAY_SPAM_DETECTION _IOW('b', 16, __u32)
 #endif // BINDER_ENABLE_ONEWAY_SPAM_DETECTION
 
+#ifndef BINDER_GET_EXTENDED_ERROR
+/* struct binder_extened_error - extended error information
+ * @id:      identifier for the failed operation
+ * @command: command as defined by binder_driver_return_protocol
+ * @param:   parameter holding a negative errno value
+ *
+ * Used with BINDER_GET_EXTENDED_ERROR. This extends the error information
+ * returned by the driver upon a failed operation. Userspace can pull this
+ * data to properly handle specific error scenarios.
+ */
+struct binder_extended_error {
+    __u32 id;
+    __u32 command;
+    __s32 param;
+};
+
+#define BINDER_GET_EXTENDED_ERROR _IOWR('b', 17, struct binder_extended_error)
+#endif // BINDER_GET_EXTENDED_ERROR
+
 #endif // _BINDER_MODULE_H_
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 8deb2fe..19ad5e6 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -18,7 +18,6 @@
 
 #include <binder/IBinder.h>
 #include <utils/Mutex.h>
-#include <utils/threads.h>
 
 #include <map>
 #include <unordered_map>
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index f295417..e864f9e 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -72,9 +72,9 @@
 public:
     virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
     virtual const String16&     getInterfaceDescriptor() const;
+    typedef INTERFACE BaseInterface;
 
 protected:
-    typedef INTERFACE           BaseInterface;
     virtual IBinder*            onAsBinder();
 };
 
@@ -85,9 +85,9 @@
 {
 public:
     explicit                    BpInterface(const sp<IBinder>& remote);
+    typedef INTERFACE BaseInterface;
 
 protected:
-    typedef INTERFACE           BaseInterface;
     virtual IBinder*            onAsBinder();
 };
 
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index bf02099..cd6a274 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -216,6 +216,7 @@
     static  void                freeBuffer(Parcel* parcel,
                                            const uint8_t* data, size_t dataSize,
                                            const binder_size_t* objects, size_t objectsSize);
+    static  void                logExtendedError();
 
     const   sp<ProcessState>    mProcess;
             Vector<BBinder*>    mPendingStrongDerefs;
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index ea40db8..413c97f 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -56,8 +56,16 @@
     static const int DUMP_FLAG_PROTO = 1 << 4;
 
     /**
-     * Retrieve an existing service, blocking for a few seconds
-     * if it doesn't yet exist.
+     * Retrieve an existing service, blocking for a few seconds if it doesn't yet exist. This
+     * does polling. A more efficient way to make sure you unblock as soon as the service is
+     * available is to use waitForService or to use service notifications.
+     *
+     * Warning: when using this API, typically, you should call it in a loop. It's dangerous to
+     * assume that nullptr could mean that the service is not available. The service could just
+     * be starting. Generally, whether a service exists, this information should be declared
+     * externally (for instance, an Android feature might imply the existence of a service,
+     * a system property, or in the case of services in the VINTF manifest, it can be checked
+     * with isDeclared).
      */
     virtual sp<IBinder>         getService( const String16& name) const = 0;
 
@@ -126,6 +134,12 @@
 
     virtual status_t unregisterForNotifications(const String16& name,
                                                 const sp<LocalRegistrationCallback>& callback) = 0;
+
+    struct ServiceDebugInfo {
+        std::string name;
+        int pid;
+    };
+    virtual std::vector<ServiceDebugInfo> getServiceDebugInfo() = 0;
 };
 
 sp<IServiceManager> defaultServiceManager();
diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
index dd76943..c7177bd 100644
--- a/libs/binder/include/binder/MemoryHeapBase.h
+++ b/libs/binder/include/binder/MemoryHeapBase.h
@@ -26,15 +26,30 @@
 
 // ---------------------------------------------------------------------------
 
-class MemoryHeapBase : public virtual BnMemoryHeap
+class MemoryHeapBase : public BnMemoryHeap
 {
 public:
+    static constexpr auto MEMFD_ALLOW_SEALING_FLAG = 0x00000800;
     enum {
         READ_ONLY = IMemoryHeap::READ_ONLY,
         // memory won't be mapped locally, but will be mapped in the remote
         // process.
         DONT_MAP_LOCALLY = 0x00000100,
-        NO_CACHING = 0x00000200
+        NO_CACHING = 0x00000200,
+        // Bypass ashmem-libcutils to create a memfd shared region.
+        // Ashmem-libcutils will eventually migrate to memfd.
+        // Memfd has security benefits and supports file sealing.
+        // Calling process will need to modify selinux permissions to
+        // open access to tmpfs files. See audioserver for examples.
+        // This is only valid for size constructor.
+        // For host compilation targets, memfd is stubbed in favor of /tmp
+        // files so sealing is not enforced.
+        FORCE_MEMFD = 0x00000400,
+        // Default opt-out of sealing behavior in memfd to avoid potential DOS.
+        // Clients of shared files can seal at anytime via syscall, leading to
+        // TOC/TOU issues if additional seals prevent access from the creating
+        // process. Alternatively, seccomp fcntl().
+        MEMFD_ALLOW_SEALING = FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG
     };
 
     /*
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 450e388..68a4aef 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -20,6 +20,7 @@
 #include <map> // for legacy reasons
 #include <string>
 #include <type_traits>
+#include <variant>
 #include <vector>
 
 #include <android-base/unique_fd.h>
@@ -76,6 +77,11 @@
     size_t              dataCapacity() const;
 
     status_t            setDataSize(size_t size);
+
+    // this must only be used to set a data position that was previously returned from
+    // dataPosition(). If writes are made, the exact same types of writes must be made (e.g.
+    // auto i = p.dataPosition(); p.writeInt32(0); p.setDataPosition(i); p.writeInt32(1);).
+    // Writing over objects, such as file descriptors and binders, is not supported.
     void                setDataPosition(size_t pos) const;
     status_t            setDataCapacity(size_t size);
 
@@ -95,6 +101,12 @@
     bool                hasFileDescriptors() const;
     status_t hasFileDescriptorsInRange(size_t offset, size_t length, bool* result) const;
 
+    // returns all binder objects in the Parcel
+    std::vector<sp<IBinder>> debugReadAllStrongBinders() const;
+    // returns all file descriptors in the Parcel
+    // does not dup
+    std::vector<int> debugReadAllFileDescriptors() const;
+
     // Zeros data when reallocating. Other mitigations may be added
     // in the future.
     //
@@ -594,16 +606,24 @@
     size_t              ipcDataSize() const;
     uintptr_t           ipcObjects() const;
     size_t              ipcObjectsCount() const;
-    void                ipcSetDataReference(const uint8_t* data, size_t dataSize,
-                                            const binder_size_t* objects, size_t objectsCount,
-                                            release_func relFunc);
+    void ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
+                             size_t objectsCount, release_func relFunc);
+    // Takes ownership even when an error is returned.
+    status_t rpcSetDataReference(const sp<RpcSession>& session, const uint8_t* data,
+                                 size_t dataSize, const uint32_t* objectTable,
+                                 size_t objectTableSize, std::vector<base::unique_fd> ancillaryFds,
+                                 release_func relFunc);
 
     status_t            finishWrite(size_t len);
     void                releaseObjects();
     void                acquireObjects();
     status_t            growData(size_t len);
+    // Clear the Parcel and set the capacity to `desired`.
+    // Doesn't reset the RPC session association.
     status_t            restartWrite(size_t desired);
+    // Set the capacity to `desired`, truncating the Parcel if necessary.
     status_t            continueWrite(size_t desired);
+    status_t truncateRpcObjects(size_t newObjectsSize);
     status_t            writePointer(uintptr_t val);
     status_t            readPointer(uintptr_t *pArg) const;
     uintptr_t           readPointer() const;
@@ -1241,19 +1261,57 @@
     uint8_t*            mData;
     size_t              mDataSize;
     size_t              mDataCapacity;
-    mutable size_t      mDataPos;
-    binder_size_t*      mObjects;
-    size_t              mObjectsSize;
-    size_t              mObjectsCapacity;
-    mutable size_t      mNextObjectHint;
-    mutable bool        mObjectsSorted;
+    mutable size_t mDataPos;
 
-    mutable bool        mRequestHeaderPresent;
+    // Fields only needed when parcelling for "kernel Binder".
+    struct KernelFields {
+        binder_size_t* mObjects = nullptr;
+        size_t mObjectsSize = 0;
+        size_t mObjectsCapacity = 0;
+        mutable size_t mNextObjectHint = 0;
 
-    mutable size_t      mWorkSourceRequestHeaderPosition;
+        mutable size_t mWorkSourceRequestHeaderPosition = 0;
+        mutable bool mRequestHeaderPresent = false;
 
-    mutable bool        mFdsKnown;
-    mutable bool        mHasFds;
+        mutable bool mObjectsSorted = false;
+        mutable bool mFdsKnown = true;
+        mutable bool mHasFds = false;
+    };
+    // Fields only needed when parcelling for RPC Binder.
+    struct RpcFields {
+        RpcFields(const sp<RpcSession>& session);
+
+        // Should always be non-null.
+        const sp<RpcSession> mSession;
+
+        enum ObjectType : int32_t {
+            TYPE_BINDER_NULL = 0,
+            TYPE_BINDER = 1,
+            // FD to be passed via native transport (Trusty IPC or UNIX domain socket).
+            TYPE_NATIVE_FILE_DESCRIPTOR = 2,
+        };
+
+        // Sorted.
+        std::vector<uint32_t> mObjectPositions;
+
+        // File descriptors referenced by the parcel data. Should be indexed
+        // using the offsets in the parcel data. Don't assume the list is in the
+        // same order as `mObjectPositions`.
+        //
+        // Boxed to save space. Lazy allocated.
+        std::unique_ptr<std::vector<std::variant<base::unique_fd, base::borrowed_fd>>> mFds;
+    };
+    std::variant<KernelFields, RpcFields> mVariantFields;
+
+    // Pointer to KernelFields in mVariantFields if present.
+    KernelFields* maybeKernelFields() { return std::get_if<KernelFields>(&mVariantFields); }
+    const KernelFields* maybeKernelFields() const {
+        return std::get_if<KernelFields>(&mVariantFields);
+    }
+    // Pointer to RpcFields in mVariantFields if present.
+    RpcFields* maybeRpcFields() { return std::get_if<RpcFields>(&mVariantFields); }
+    const RpcFields* maybeRpcFields() const { return std::get_if<RpcFields>(&mVariantFields); }
+
     bool                mAllowFds;
 
     // if this parcelable is involved in a secure transaction, force the
@@ -1262,7 +1320,6 @@
 
     release_func        mOwner;
 
-    sp<RpcSession> mSession;
     size_t mReserved;
 
     class Blob {
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index 42c85f9..88790a8 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -86,7 +86,7 @@
                 *ret = nullptr;
                 return android::BAD_VALUE;
             }
-            *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+            *ret = std::static_pointer_cast<T>(mParcelable);
             return android::OK;
         }
         this->mParcelPtr->setDataPosition(0);
@@ -105,7 +105,7 @@
             return status;
         }
         this->mParcelPtr = nullptr;
-        *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+        *ret = std::static_pointer_cast<T>(mParcelable);
         return android::OK;
     }
 
diff --git a/libs/binder/include/binder/PermissionController.h b/libs/binder/include/binder/PermissionController.h
index e658574..6f9eb5e 100644
--- a/libs/binder/include/binder/PermissionController.h
+++ b/libs/binder/include/binder/PermissionController.h
@@ -19,8 +19,7 @@
 #ifndef __ANDROID_VNDK__
 
 #include <binder/IPermissionController.h>
-
-#include <utils/threads.h>
+#include <utils/Mutex.h>
 
 // ---------------------------------------------------------------------------
 namespace android {
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index cf8d8e4..e17a76c 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -18,11 +18,10 @@
 
 #include <binder/IBinder.h>
 #include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
 
-#include <utils/threads.h>
-
 #include <pthread.h>
 
 // ---------------------------------------------------------------------------
@@ -85,11 +84,18 @@
     void setCallRestriction(CallRestriction restriction);
 
     /**
-     * Get the max number of threads that the kernel can start.
-     *
-     * Note: this is the lower bound. Additional threads may be started.
+     * Get the max number of threads that have joined the thread pool.
+     * This includes kernel started threads, user joined threads and polling
+     * threads if used.
      */
-    size_t getThreadPoolMaxThreadCount() const;
+    size_t getThreadPoolMaxTotalThreadCount() const;
+
+    enum class DriverFeature {
+        ONEWAY_SPAM_DETECTION,
+        EXTENDED_ERROR,
+    };
+    // Determine whether a feature is supported by the binder driver.
+    static bool isDriverFeatureEnabled(const DriverFeature feature);
 
 private:
     static sp<ProcessState> init(const char* defaultDriver, bool requireDefault);
@@ -127,8 +133,12 @@
     size_t mExecutingThreadsCount;
     // Number of threads calling IPCThreadState::blockUntilThreadAvailable()
     size_t mWaitingForThreads;
-    // Maximum number for binder threads allowed for this process.
+    // Maximum number of lazy threads to be started in the threadpool by the kernel.
     size_t mMaxThreads;
+    // Current number of threads inside the thread pool.
+    size_t mCurrentThreads;
+    // Current number of pooled threads inside the thread pool.
+    size_t mKernelStartedThreads;
     // Time when thread pool was emptied
     int64_t mStarvationStartTimeMs;
 
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index aaa812b..7fea76e 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -77,7 +77,7 @@
      * have
      */
     [[nodiscard]] status_t setupInetServer(const char* address, unsigned int port,
-                                           unsigned int* assignedPort);
+                                           unsigned int* assignedPort = nullptr);
 
     /**
      * If setup*Server has been successful, return true. Otherwise return false.
@@ -114,6 +114,15 @@
     void setProtocolVersion(uint32_t version);
 
     /**
+     * Set the supported transports for sending and receiving file descriptors.
+     *
+     * Clients will propose a mode when connecting. If the mode is not in the
+     * provided list, the connection will be rejected.
+     */
+    void setSupportedFileDescriptorTransportModes(
+            const std::vector<RpcSession::FileDescriptorTransportMode>& modes);
+
+    /**
      * The root object can be retrieved by any client, without any
      * authentication. TODO(b/183988761)
      *
@@ -125,9 +134,17 @@
      */
     void setRootObjectWeak(const wp<IBinder>& binder);
     /**
-     * Allows a root object to be created for each session
+     * Allows a root object to be created for each session.
+     *
+     * Takes one argument: a callable that is invoked once per new session.
+     * The callable takes two arguments: a type-erased pointer to an OS- and
+     * transport-specific address structure, e.g., sockaddr_vm for vsock, and
+     * an integer representing the size in bytes of that structure. The
+     * callable should validate the size, then cast the type-erased pointer
+     * to a pointer to the actual type of the address, e.g., const void* to
+     * const sockaddr_vm*.
      */
-    void setPerSessionRootObject(std::function<sp<IBinder>(const sockaddr*, socklen_t)>&& object);
+    void setPerSessionRootObject(std::function<sp<IBinder>(const void*, size_t)>&& object);
     sp<IBinder> getRootObject();
 
     /**
@@ -177,13 +194,17 @@
     void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
     void onSessionIncomingThreadEnded() override;
 
+    static constexpr size_t kRpcAddressSize = 128;
     static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
-                                    const sockaddr_storage addr, socklen_t addrLen);
+                                    std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen);
     [[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address);
 
     const std::unique_ptr<RpcTransportCtx> mCtx;
     size_t mMaxThreads = 1;
     std::optional<uint32_t> mProtocolVersion;
+    // A mode is supported if the N'th bit is on, where N is the mode enum's value.
+    std::bitset<8> mSupportedFileDescriptorTransportModes = std::bitset<8>().set(
+            static_cast<size_t>(RpcSession::FileDescriptorTransportMode::NONE));
     base::unique_fd mServer; // socket we are accepting sessions on
 
     std::mutex mLock; // for below
@@ -192,7 +213,7 @@
     std::map<std::thread::id, std::thread> mConnectingThreads;
     sp<IBinder> mRootObject;
     wp<IBinder> mRootObjectWeak;
-    std::function<sp<IBinder>(const sockaddr*, socklen_t)> mRootObjectFactory;
+    std::function<sp<IBinder>(const void*, size_t)> mRootObjectFactory;
     std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions;
     std::unique_ptr<FdTrigger> mShutdownTrigger;
     std::condition_variable mShutdownCv;
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 1bc8464..b98b0eb 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -15,6 +15,7 @@
  */
 #pragma once
 
+#include <android-base/threads.h>
 #include <android-base/unique_fd.h>
 #include <binder/IBinder.h>
 #include <binder/RpcTransport.h>
@@ -35,10 +36,16 @@
 class RpcTransport;
 class FdTrigger;
 
-constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 0;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 1;
 constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL = 0xF0000000;
 constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL;
 
+// Starting with this version:
+//
+// * RpcWireReply is larger (4 bytes -> 20).
+// * RpcWireTransaction and RpcWireReplyV1 include the parcel data size.
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE = 1;
+
 /**
  * This represents a session (group of connections) between a client
  * and a server. Multiple connections are needed for multiple parallel "binder"
@@ -88,6 +95,18 @@
     [[nodiscard]] bool setProtocolVersion(uint32_t version);
     std::optional<uint32_t> getProtocolVersion();
 
+    enum class FileDescriptorTransportMode : uint8_t {
+        NONE = 0,
+        // Send file descriptors via unix domain socket ancillary data.
+        UNIX = 1,
+    };
+
+    /**
+     * Set the transport for sending and receiving file descriptors.
+     */
+    void setFileDescriptorTransportMode(FileDescriptorTransportMode mode);
+    FileDescriptorTransportMode getFileDescriptorTransportMode();
+
     /**
      * This should be called once per thread, matching 'join' in the remote
      * process.
@@ -211,7 +230,7 @@
 
         // whether this or another thread is currently using this fd to make
         // or receive transactions.
-        std::optional<pid_t> exclusiveTid;
+        std::optional<uint64_t> exclusiveTid;
 
         bool allowNested = false;
     };
@@ -257,6 +276,7 @@
     sp<RpcConnection> assignIncomingConnectionToThisThread(
             std::unique_ptr<RpcTransport> rpcTransport);
     [[nodiscard]] bool removeIncomingConnection(const sp<RpcConnection>& connection);
+    void clearConnectionTid(const sp<RpcConnection>& connection);
 
     [[nodiscard]] status_t initShutdownTrigger();
 
@@ -276,7 +296,7 @@
         const sp<RpcConnection>& get() { return mConnection; }
 
     private:
-        static void findConnection(pid_t tid, sp<RpcConnection>* exclusive,
+        static void findConnection(uint64_t tid, sp<RpcConnection>* exclusive,
                                    sp<RpcConnection>* available,
                                    std::vector<sp<RpcConnection>>& sockets,
                                    size_t socketsIndexHint);
@@ -306,7 +326,7 @@
     // For a more complicated case, the client might itself open up a thread to
     // serve calls to the server at all times (e.g. if it hosts a callback)
 
-    wp<RpcServer> mForServer; // maybe null, for client sessions
+    wp<RpcServer> mForServer;                      // maybe null, for client sessions
     sp<WaitForShutdownListener> mShutdownListener; // used for client sessions
     wp<EventListener> mEventListener; // mForServer if server, mShutdownListener if client
 
@@ -325,6 +345,7 @@
     size_t mMaxIncomingThreads = 0;
     size_t mMaxOutgoingThreads = kDefaultMaxOutgoingThreads;
     std::optional<uint32_t> mProtocolVersion;
+    FileDescriptorTransportMode mFileDescriptorTransportMode = FileDescriptorTransportMode::NONE;
 
     std::condition_variable mAvailableConnectionCv; // for mWaitingThreads
 
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index ade2d94..80f5a32 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -20,9 +20,12 @@
 
 #include <functional>
 #include <memory>
+#include <optional>
 #include <string>
+#include <variant>
+#include <vector>
 
-#include <android-base/result.h>
+#include <android-base/function_ref.h>
 #include <android-base/unique_fd.h>
 #include <utils/Errors.h>
 
@@ -40,8 +43,15 @@
 public:
     virtual ~RpcTransport() = default;
 
-    // replacement of ::recv(MSG_PEEK). Error code may not be set if TLS is enabled.
-    [[nodiscard]] virtual android::base::Result<size_t> peek(void *buf, size_t size) = 0;
+    /**
+     * Poll the transport to check whether there is any data ready to read.
+     *
+     * Return:
+     *   OK - There is data available on this transport
+     *   WOULDBLOCK - No data is available
+     *   error - any other error
+     */
+    [[nodiscard]] virtual status_t pollRead(void) = 0;
 
     /**
      * Read (or write), but allow to be interrupted by a trigger.
@@ -53,16 +63,31 @@
      * to read/write data. If this returns an error, that error is returned from
      * this function.
      *
+     * ancillaryFds - FDs to be sent via UNIX domain dockets or Trusty IPC.
+     *
+     * enableAncillaryFds - Whether to check for FDs in the ancillary data and
+     * queue for them for use in `consumePendingAncillaryData`. If false and FDs
+     * are received, they will be silently dropped (and closed) by the operating
+     * system.
+     *
      * Return:
      *   OK - succeeded in completely processing 'size'
      *   error - interrupted (failure or trigger)
      */
     [[nodiscard]] virtual status_t interruptableWriteFully(
             FdTrigger *fdTrigger, iovec *iovs, int niovs,
-            const std::function<status_t()> &altPoll) = 0;
+            const std::optional<android::base::function_ref<status_t()>> &altPoll,
+            const std::vector<std::variant<base::unique_fd, base::borrowed_fd>> *ancillaryFds) = 0;
     [[nodiscard]] virtual status_t interruptableReadFully(
             FdTrigger *fdTrigger, iovec *iovs, int niovs,
-            const std::function<status_t()> &altPoll) = 0;
+            const std::optional<android::base::function_ref<status_t()>> &altPoll,
+            bool enableAncillaryFds) = 0;
+
+    // Consume the ancillary data that was accumulated from previous
+    // `interruptableReadFully` calls.
+    //
+    // Appends to `fds`.
+    virtual status_t consumePendingAncillaryData(std::vector<base::unique_fd> *fds) = 0;
 
 protected:
     RpcTransport() = default;
diff --git a/libs/binder/include_activitymanager/binder/ActivityManager.h b/libs/binder/include_activitymanager/binder/ActivityManager.h
index b772b80..abc7f1d 100644
--- a/libs/binder/include_activitymanager/binder/ActivityManager.h
+++ b/libs/binder/include_activitymanager/binder/ActivityManager.h
@@ -18,10 +18,9 @@
 
 #ifndef __ANDROID_VNDK__
 
-#include <binder/IActivityManager.h>
 #include <android/app/ProcessStateEnum.h>
-
-#include <utils/threads.h>
+#include <binder/IActivityManager.h>
+#include <utils/Mutex.h>
 
 // ---------------------------------------------------------------------------
 namespace android {
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index bf2b25b..a3d42b7 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -38,10 +38,10 @@
                    << " error: " << statusToString(status).c_str();
         return false;
     }
-    server->setPerSessionRootObject([=](const sockaddr* addr, socklen_t addrlen) {
-        LOG_ALWAYS_FATAL_IF(addr->sa_family != AF_VSOCK, "address is not a vsock");
+    server->setPerSessionRootObject([=](const void* addr, size_t addrlen) {
         LOG_ALWAYS_FATAL_IF(addrlen < sizeof(sockaddr_vm), "sockaddr is truncated");
         const sockaddr_vm* vaddr = reinterpret_cast<const sockaddr_vm*>(addr);
+        LOG_ALWAYS_FATAL_IF(vaddr->svm_family != AF_VSOCK, "address is not a vsock");
         return AIBinder_toPlatformBinder(factory(vaddr->svm_cid, factoryContext));
     });
 
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 79c8c8f..32e018d 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -113,6 +113,7 @@
         "abseil-*",
         "android-*",
         "bugprone-*",
+        "-bugprone-branch-clone", // b/155034972
         "cert-*",
         "clang-analyzer-*",
         "-clang-analyzer-core.CallAndMessage",
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 28e3ff4..b21a7e9 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -36,6 +36,7 @@
 using ::android::Parcel;
 using ::android::sp;
 using ::android::status_t;
+using ::android::statusToString;
 using ::android::String16;
 using ::android::String8;
 using ::android::wp;
@@ -133,7 +134,8 @@
         } else {
             // b/155793159
             LOG(ERROR) << __func__ << ": Cannot associate class '" << newDescriptor
-                       << "' to dead binder.";
+                       << "' to dead binder with cached descriptor '" << SanitizeString(descriptor)
+                       << "'.";
         }
         return false;
     }
@@ -458,7 +460,8 @@
             status_t status = binder->unlinkToDeath(recipient, cookie, 0 /*flags*/);
             if (status != ::android::OK) {
                 LOG(ERROR) << __func__
-                           << ": removed reference to death recipient but unlink failed.";
+                           << ": removed reference to death recipient but unlink failed: "
+                           << statusToString(status);
             }
             return PruneStatusT(status);
         }
@@ -539,7 +542,8 @@
 binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                      void* cookie) {
     if (binder == nullptr || recipient == nullptr) {
-        LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
+        LOG(ERROR) << __func__ << ": Must provide binder (" << binder << ") and recipient ("
+                   << recipient << ")";
         return STATUS_UNEXPECTED_NULL;
     }
 
@@ -550,7 +554,8 @@
 binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                        void* cookie) {
     if (binder == nullptr || recipient == nullptr) {
-        LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
+        LOG(ERROR) << __func__ << ": Must provide binder (" << binder << ") and recipient ("
+                   << recipient << ")";
         return STATUS_UNEXPECTED_NULL;
     }
 
@@ -625,7 +630,8 @@
 
 binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) {
     if (binder == nullptr || in == nullptr) {
-        LOG(ERROR) << __func__ << ": requires non-null parameters.";
+        LOG(ERROR) << __func__ << ": requires non-null parameters binder (" << binder
+                   << ") and in (" << in << ").";
         return STATUS_UNEXPECTED_NULL;
     }
     const AIBinder_Class* clazz = binder->getClass();
@@ -671,7 +677,9 @@
     AutoParcelDestroyer forIn(in, DestroyParcel);
 
     if (!isUserCommand(code)) {
-        LOG(ERROR) << __func__ << ": Only user-defined transactions can be made from the NDK.";
+        LOG(ERROR) << __func__
+                   << ": Only user-defined transactions can be made from the NDK, but requested: "
+                   << code;
         return STATUS_UNKNOWN_TRANSACTION;
     }
 
@@ -682,7 +690,8 @@
     }
 
     if (binder == nullptr || *in == nullptr || out == nullptr) {
-        LOG(ERROR) << __func__ << ": requires non-null parameters.";
+        LOG(ERROR) << __func__ << ": requires non-null parameters binder (" << binder << "), in ("
+                   << in << "), and out (" << out << ").";
         return STATUS_UNEXPECTED_NULL;
     }
 
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index b3bc7f4..766df16 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -43,10 +43,12 @@
 namespace ndk {
 
 /**
- * analog using std::shared_ptr for internally held refcount
+ * Binder analog to using std::shared_ptr for an internally held refcount.
  *
  * ref must be called at least one time during the lifetime of this object. The recommended way to
  * construct this object is with SharedRefBase::make.
+ *
+ * If you need a "this" shared reference analogous to shared_from_this, use this->ref().
  */
 class SharedRefBase {
    public:
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 28819bb..f45aa76 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -101,7 +101,12 @@
             return STATUS_INVALID_OPERATION;
         }
 
-        RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability));
+        parcelable_stability_t wireStability;
+        RETURN_ON_FAILURE(AParcel_readInt32(parcel, &wireStability));
+        if (this->mStability != wireStability) {
+            return STATUS_BAD_VALUE;
+        }
+
         int32_t dataSize;
         binder_status_t status = AParcel_readInt32(parcel, &dataSize);
 
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 6880d86..8e288b3 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -56,6 +56,12 @@
  * If the binder is null, null is returned. If this binder object was originally an IBinder object,
  * the original java object will be returned.
  *
+ * WARNING: this function returns global and local references. This can be
+ * figured out using GetObjectRefType. Though, when this function is called
+ * from within a Java context, the local ref will automatically be cleaned
+ * up. If this is called outside of a Java frame,
+ * PushObjectFrame/PopObjectFrame can simulate this automatic cleanup.
+ *
  * Available since API level 29.
  *
  * \param env Java environment. Must not be null.
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 8457581..f68612c 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -59,6 +59,11 @@
 /**
  * Sets the position within the parcel.
  *
+ * This must be called with a position that has been previously returned from
+ * AParcel_getDataPosition. If writes are made after setting the data position, they must
+ * be made in the exact same sequence used before resetting data position. Writing over
+ * objects such as binders or file descriptors is not supported.
+ *
  * Available since API level 29.
  *
  * \param parcel The parcel of which to set the position.
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 2a66941..dfa8ea2 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -53,11 +53,19 @@
 /**
  * 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).
+ * for calling AIBinder_decStrong). This does polling. A more efficient way to make sure you
+ * unblock as soon as the service is available is to use AIBinder_waitForService.
  *
  * WARNING: when using this API across an APEX boundary, do not use with unstable
  * AIDL services. TODO(b/139325195)
  *
+ * WARNING: when using this API, typically, you should call it in a loop. It's dangerous to
+ * assume that nullptr could mean that the service is not available. The service could just
+ * be starting. Generally, whether a service exists, this information should be declared
+ * externally (for instance, an Android feature might imply the existence of a service,
+ * a system property, or in the case of services in the VINTF manifest, it can be checked
+ * with AServiceManager_isDeclared).
+ *
  * \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_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index f113ba8..683a433 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -97,6 +97,10 @@
  *
  * This interface has system<->vendor stability
  */
+// b/227835797 - can't use __INTRODUCED_IN(30) because old targets load this code
+#if defined(__ANDROID_MIN_SDK_VERSION__) && __ANDROID_MIN_SDK_VERSION__ < 30
+__attribute__((weak))
+#endif  // defined(__ANDROID_MIN_SDK_VERSION__) && __ANDROID_MIN_SDK_VERSION__ < 30
 void AIBinder_markVintfStability(AIBinder* binder);
 
 __END_DECLS
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 467e51e..5d6206d 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -1086,7 +1086,7 @@
     {
         $( #[$attr:meta] )*
         $enum:ident : [$backing:ty; $size:expr] {
-            $( $name:ident = $value:expr, )*
+            $( $( #[$value_attr:meta] )* $name:ident = $value:expr, )*
         }
     } => {
         $( #[$attr] )*
@@ -1094,7 +1094,7 @@
         #[allow(missing_docs)]
         pub struct $enum(pub $backing);
         impl $enum {
-            $( #[allow(missing_docs)] pub const $name: Self = Self($value); )*
+            $( $( #[$value_attr] )* #[allow(missing_docs)] pub const $name: Self = Self($value); )*
 
             #[inline(always)]
             #[allow(missing_docs)]
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index b7c7ae4..3edeebf 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -335,11 +335,16 @@
         // We don't own this file, so we need to be careful not to drop it.
         let file = ManuallyDrop::new(File::from_raw_fd(fd));
 
-        if args.is_null() {
+        if args.is_null() && num_args != 0 {
             return StatusCode::UNEXPECTED_NULL as status_t;
         }
-        let args = slice::from_raw_parts(args, num_args as usize);
-        let args: Vec<_> = args.iter().map(|s| CStr::from_ptr(*s)).collect();
+
+        let args = if args.is_null() || num_args == 0 {
+            vec![]
+        } else {
+            slice::from_raw_parts(args, num_args as usize)
+                .iter().map(|s| CStr::from_ptr(*s)).collect()
+        };
 
         let object = sys::AIBinder_getUserData(binder);
         let binder: &T = &*(object as *const T);
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index d58e839..432da5d 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -233,7 +233,9 @@
     }
 
     fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<(), StatusCode> {
-        self.stability = parcel.read()?;
+        if self.stability != parcel.read()? {
+            return Err(StatusCode::BAD_VALUE);
+        }
 
         let data_size: i32 = parcel.read()?;
         if data_size < 0 {
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index e3e4730..4df557b 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -575,6 +575,20 @@
     cookie_decr_refcount: unsafe extern "C" fn(*mut c_void),
 }
 
+/// # Safety
+///
+/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
+/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
+unsafe impl Send for DeathRecipient {}
+
+/// # Safety
+///
+/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
+/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
+unsafe impl Sync for DeathRecipient {}
+
 impl DeathRecipient {
     /// Create a new death recipient that will call the given callback when its
     /// associated object dies.
diff --git a/libs/binder/rust/tests/serialization.cpp b/libs/binder/rust/tests/serialization.cpp
index ec780f2..3f59dab 100644
--- a/libs/binder/rust/tests/serialization.cpp
+++ b/libs/binder/rust/tests/serialization.cpp
@@ -381,7 +381,7 @@
     string expected = "TestingFileDescriptors";
     vector<char> buf(expected.length());
     base::ReadFully(file_descriptors[0].release(), buf.data(), buf.size());
-    ASSERT_EQ(expected, string(buf.data()));
+    ASSERT_EQ(expected, string(buf.data(), expected.length()));
 }
 
 TEST_F(SerializationTest, SerializeIBinder) {
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index b62da7b..f6bdf5c 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -117,8 +117,8 @@
 ) -> Result<(), StatusCode> {
     match code {
         bindings::Transaction_TEST_BOOL => {
-            assert_eq!(parcel.read::<bool>()?, true);
-            assert_eq!(parcel.read::<bool>()?, false);
+            assert!(parcel.read::<bool>()?);
+            assert!(!parcel.read::<bool>()?);
             assert_eq!(parcel.read::<Vec<bool>>()?, unsafe {
                 bindings::TESTDATA_BOOL
             });
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index ff55d6e..2f96d0e 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -99,6 +99,7 @@
         "binderParcelUnitTest.cpp",
         "binderBinderUnitTest.cpp",
         "binderStatusUnitTest.cpp",
+        "binderMemoryHeapBaseUnitTest.cpp",
     ],
     shared_libs: [
         "libbinder",
@@ -318,7 +319,6 @@
         "libbinder",
         "libutils",
     ],
-    clang: true,
     cflags: [
         "-g",
         "-Wno-missing-field-initializers",
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index fdd02a4..b15a225 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -24,6 +24,9 @@
     // number of known RPC binders to process, RpcState::countBinders by session
     int[] countBinders();
 
+    // Return a null binder with a non-nullable return type.
+    IBinder getNullBinder();
+
     // Caller sends server, callee pings caller's server and returns error code.
     int pingMe(IBinder binder);
     @nullable IBinder repeatBinder(@nullable IBinder binder);
@@ -64,4 +67,8 @@
     void scheduleShutdown();
 
     void useKernelBinderCallingId();
+
+    ParcelFileDescriptor echoAsFile(@utf8InCpp String content);
+
+    ParcelFileDescriptor concatFiles(in List<ParcelFileDescriptor> files);
 }
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
index e1f5ed5..60b3c94 100644
--- a/libs/binder/tests/binderAllocationLimits.cpp
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -15,8 +15,11 @@
  */
 
 #include <android-base/logging.h>
-#include <binder/Parcel.h>
+#include <binder/Binder.h>
 #include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
 #include <gtest/gtest.h>
 #include <utils/CallStack.h>
 
@@ -124,12 +127,18 @@
     });
 }
 
-using android::IBinder;
-using android::Parcel;
-using android::String16;
+using android::BBinder;
 using android::defaultServiceManager;
-using android::sp;
+using android::IBinder;
 using android::IServiceManager;
+using android::OK;
+using android::Parcel;
+using android::RpcServer;
+using android::RpcSession;
+using android::sp;
+using android::status_t;
+using android::statusToString;
+using android::String16;
 
 static sp<IBinder> GetRemoteBinder() {
     // This gets binder representing the service manager
@@ -175,6 +184,36 @@
     EXPECT_EQ(mallocs, 1);
 }
 
+TEST(RpcBinderAllocation, SetupRpcServer) {
+    std::string tmp = getenv("TMPDIR") ?: "/tmp";
+    std::string addr = tmp + "/binderRpcBenchmark";
+    (void)unlink(addr.c_str());
+    auto server = RpcServer::make();
+    server->setRootObject(sp<BBinder>::make());
+
+    CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
+
+    std::thread([server]() { server->join(); }).detach();
+
+    status_t status;
+    auto session = RpcSession::make();
+    status = session->setupUnixDomainClient(addr.c_str());
+    CHECK_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str();
+
+    auto remoteBinder = session->getRootObject();
+
+    size_t mallocs = 0, totalBytes = 0;
+    {
+        const auto on_malloc = OnMalloc([&](size_t bytes) {
+            mallocs++;
+            totalBytes += bytes;
+        });
+        CHECK_EQ(OK, remoteBinder->pingBinder());
+    }
+    EXPECT_EQ(mallocs, 1);
+    EXPECT_EQ(totalBytes, 40);
+}
+
 int main(int argc, char** argv) {
     if (getenv("LIBC_HOOKS_ENABLE") == nullptr) {
         CHECK(0 == setenv("LIBC_HOOKS_ENABLE", "1", true /*overwrite*/));
diff --git a/libs/binder/tests/binderBinderUnitTest.cpp b/libs/binder/tests/binderBinderUnitTest.cpp
index 1be0c59..ce2770f 100644
--- a/libs/binder/tests/binderBinderUnitTest.cpp
+++ b/libs/binder/tests/binderBinderUnitTest.cpp
@@ -41,3 +41,10 @@
     EXPECT_EQ(kObject1, binder->detachObject(kObjectId1));
     EXPECT_EQ(nullptr, binder->attachObject(kObjectId1, kObject2, nullptr, nullptr));
 }
+
+TEST(Binder, AttachExtension) {
+    auto binder = sp<BBinder>::make();
+    auto ext = sp<BBinder>::make();
+    binder->setExtension(ext);
+    EXPECT_EQ(ext, binder->getExtension());
+}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index b1e17b7..4ed3309 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -30,6 +30,7 @@
 #include <android-base/properties.h>
 #include <android-base/result-gmock.h>
 #include <android-base/result.h>
+#include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <binder/Binder.h>
@@ -82,6 +83,7 @@
 static constexpr int kSchedPolicy = SCHED_RR;
 static constexpr int kSchedPriority = 7;
 static constexpr int kSchedPriorityMore = 8;
+static constexpr int kKernelThreads = 15;
 
 static String16 binderLibTestServiceName = String16("test.binderLib");
 
@@ -115,6 +117,12 @@
     BINDER_LIB_TEST_ECHO_VECTOR,
     BINDER_LIB_TEST_REJECT_OBJECTS,
     BINDER_LIB_TEST_CAN_GET_SID,
+    BINDER_LIB_TEST_GET_MAX_THREAD_COUNT,
+    BINDER_LIB_TEST_SET_MAX_THREAD_COUNT,
+    BINDER_LIB_TEST_LOCK_UNLOCK,
+    BINDER_LIB_TEST_PROCESS_LOCK,
+    BINDER_LIB_TEST_UNLOCK_AFTER_MS,
+    BINDER_LIB_TEST_PROCESS_TEMPORARY_LOCK
 };
 
 pid_t start_server_process(int arg2, bool usePoll = false)
@@ -247,13 +255,11 @@
         {
             int32_t id;
             Parcel data, reply;
-            sp<IBinder> binder;
 
             EXPECT_THAT(m_server->transact(code, data, &reply), StatusEq(NO_ERROR));
 
-            EXPECT_FALSE(binder != nullptr);
-            binder = reply.readStrongBinder();
-            EXPECT_TRUE(binder != nullptr);
+            sp<IBinder> binder = reply.readStrongBinder();
+            EXPECT_NE(nullptr, binder);
             EXPECT_THAT(reply.readInt32(&id), StatusEq(NO_ERROR));
             if (idPtr)
                 *idPtr = id;
@@ -442,6 +448,12 @@
     EXPECT_DEATH({ ProcessState::self(); }, "libbinder ProcessState can not be used after fork");
 }
 
+TEST_F(BinderLibTest, AddManagerToManager) {
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = IInterface::asBinder(sm);
+    EXPECT_EQ(NO_ERROR, sm->addService(String16("binderLibTest-manager"), binder));
+}
+
 TEST_F(BinderLibTest, WasParceled) {
     auto binder = sp<BBinder>::make();
     EXPECT_FALSE(binder->wasParceled());
@@ -1221,6 +1233,53 @@
     EXPECT_THAT(server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr), StatusEq(OK));
 }
 
+struct TooManyFdsFlattenable : Flattenable<TooManyFdsFlattenable> {
+    TooManyFdsFlattenable(size_t fdCount) : mFdCount(fdCount) {}
+
+    // Flattenable protocol
+    size_t getFlattenedSize() const {
+        // Return a valid non-zero size here so we don't get an unintended
+        // BAD_VALUE from Parcel::write
+        return 16;
+    }
+    size_t getFdCount() const { return mFdCount; }
+    status_t flatten(void *& /*buffer*/, size_t & /*size*/, int *&fds, size_t &count) const {
+        for (size_t i = 0; i < count; i++) {
+            fds[i] = STDIN_FILENO;
+        }
+        return NO_ERROR;
+    }
+    status_t unflatten(void const *& /*buffer*/, size_t & /*size*/, int const *& /*fds*/,
+                       size_t & /*count*/) {
+        /* This doesn't get called */
+        return NO_ERROR;
+    }
+
+    size_t mFdCount;
+};
+
+TEST_F(BinderLibTest, TooManyFdsFlattenable) {
+    rlimit origNofile;
+    int ret = getrlimit(RLIMIT_NOFILE, &origNofile);
+    ASSERT_EQ(0, ret);
+
+    // Restore the original file limits when the test finishes
+    base::ScopeGuard guardUnguard([&]() { setrlimit(RLIMIT_NOFILE, &origNofile); });
+
+    rlimit testNofile = {1024, 1024};
+    ret = setrlimit(RLIMIT_NOFILE, &testNofile);
+    ASSERT_EQ(0, ret);
+
+    Parcel parcel;
+    // Try to write more file descriptors than supported by the OS
+    TooManyFdsFlattenable tooManyFds1(1024);
+    EXPECT_THAT(parcel.write(tooManyFds1), StatusEq(-EMFILE));
+
+    // Try to write more file descriptors than the internal limit
+    TooManyFdsFlattenable tooManyFds2(1025);
+    EXPECT_THAT(parcel.write(tooManyFds2), StatusEq(BAD_VALUE));
+}
+
 TEST(ServiceNotifications, Unregister) {
     auto sm = defaultServiceManager();
     using LocalRegistrationCallback = IServiceManager::LocalRegistrationCallback;
@@ -1234,6 +1293,80 @@
     EXPECT_EQ(sm->unregisterForNotifications(String16("RogerRafa"), cb), OK);
 }
 
+TEST_F(BinderLibTest, ThreadPoolAvailableThreads) {
+    Parcel data, reply;
+    sp<IBinder> server = addServer();
+    ASSERT_TRUE(server != nullptr);
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_MAX_THREAD_COUNT, data, &reply),
+                StatusEq(NO_ERROR));
+    int32_t replyi = reply.readInt32();
+    // Expect 16 threads: kKernelThreads = 15 + Pool thread == 16
+    EXPECT_TRUE(replyi == kKernelThreads || replyi == kKernelThreads + 1);
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_PROCESS_LOCK, data, &reply), NO_ERROR);
+
+    /*
+     * This will use all threads in the pool expect the main pool thread.
+     * The service should run fine without locking, and the thread count should
+     * not exceed 16 (15 Max + pool thread).
+     */
+    std::vector<std::thread> ts;
+    for (size_t i = 0; i < kKernelThreads - 1; i++) {
+        ts.push_back(std::thread([&] {
+            Parcel local_reply;
+            EXPECT_THAT(server->transact(BINDER_LIB_TEST_LOCK_UNLOCK, data, &local_reply),
+                        NO_ERROR);
+        }));
+    }
+
+    data.writeInt32(1);
+    // Give a chance for all threads to be used
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_UNLOCK_AFTER_MS, data, &reply), NO_ERROR);
+
+    for (auto &t : ts) {
+        t.join();
+    }
+
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_MAX_THREAD_COUNT, data, &reply),
+                StatusEq(NO_ERROR));
+    replyi = reply.readInt32();
+    // No more than 16 threads should exist.
+    EXPECT_TRUE(replyi == kKernelThreads || replyi == kKernelThreads + 1);
+}
+
+size_t epochMillis() {
+    using std::chrono::duration_cast;
+    using std::chrono::milliseconds;
+    using std::chrono::seconds;
+    using std::chrono::system_clock;
+    return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+}
+
+TEST_F(BinderLibTest, HangingServices) {
+    Parcel data, reply;
+    sp<IBinder> server = addServer();
+    ASSERT_TRUE(server != nullptr);
+    int32_t delay = 1000; // ms
+    data.writeInt32(delay);
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_PROCESS_TEMPORARY_LOCK, data, &reply), NO_ERROR);
+    std::vector<std::thread> ts;
+    size_t epochMsBefore = epochMillis();
+    for (size_t i = 0; i < kKernelThreads + 1; i++) {
+        ts.push_back(std::thread([&] {
+            Parcel local_reply;
+            EXPECT_THAT(server->transact(BINDER_LIB_TEST_LOCK_UNLOCK, data, &local_reply),
+                        NO_ERROR);
+        }));
+    }
+
+    for (auto &t : ts) {
+        t.join();
+    }
+    size_t epochMsAfter = epochMillis();
+
+    // deadlock occurred and threads only finished after 1s passed.
+    EXPECT_GE(epochMsAfter, epochMsBefore + delay);
+}
+
 class BinderLibRpcTestBase : public BinderLibTest {
 public:
     void SetUp() override {
@@ -1640,11 +1773,42 @@
             case BINDER_LIB_TEST_CAN_GET_SID: {
                 return IPCThreadState::self()->getCallingSid() == nullptr ? BAD_VALUE : NO_ERROR;
             }
+            case BINDER_LIB_TEST_GET_MAX_THREAD_COUNT: {
+                reply->writeInt32(ProcessState::self()->getThreadPoolMaxTotalThreadCount());
+                return NO_ERROR;
+            }
+            case BINDER_LIB_TEST_PROCESS_LOCK: {
+                m_blockMutex.lock();
+                return NO_ERROR;
+            }
+            case BINDER_LIB_TEST_LOCK_UNLOCK: {
+                std::lock_guard<std::mutex> _l(m_blockMutex);
+                return NO_ERROR;
+            }
+            case BINDER_LIB_TEST_UNLOCK_AFTER_MS: {
+                int32_t ms = data.readInt32();
+                return unlockInMs(ms);
+            }
+            case BINDER_LIB_TEST_PROCESS_TEMPORARY_LOCK: {
+                m_blockMutex.lock();
+                sp<BinderLibTestService> thisService = this;
+                int32_t value = data.readInt32();
+                // start local thread to unlock in 1s
+                std::thread t([=] { thisService->unlockInMs(value); });
+                t.detach();
+                return NO_ERROR;
+            }
             default:
                 return UNKNOWN_TRANSACTION;
         };
     }
 
+    status_t unlockInMs(int32_t ms) {
+        usleep(ms * 1000);
+        m_blockMutex.unlock();
+        return NO_ERROR;
+    }
+
 private:
     int32_t m_id;
     int32_t m_nextServerId;
@@ -1655,6 +1819,7 @@
     sp<IBinder> m_strongRef;
     sp<IBinder> m_callback;
     bool m_exitOnDestroy;
+    std::mutex m_blockMutex;
 };
 
 int run_server(int index, int readypipefd, bool usePoll)
@@ -1756,6 +1921,7 @@
              }
         }
     } else {
+        ProcessState::self()->setThreadPoolMaxThreadCount(kKernelThreads);
         ProcessState::self()->startThreadPool();
         IPCThreadState::self()->joinThreadPool();
     }
diff --git a/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp
new file mode 100644
index 0000000..278dd2b
--- /dev/null
+++ b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/MemoryHeapBase.h>
+#include <cutils/ashmem.h>
+#include <fcntl.h>
+
+#include <gtest/gtest.h>
+using namespace android;
+#ifdef __BIONIC__
+TEST(MemoryHeapBase, ForceMemfdRespected) {
+    auto mHeap = sp<MemoryHeapBase>::make(10, MemoryHeapBase::FORCE_MEMFD, "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
+    int fd = mHeap->getHeapID();
+    EXPECT_NE(fd, -1);
+    EXPECT_FALSE(ashmem_valid(fd));
+    EXPECT_NE(fcntl(fd, F_GET_SEALS), -1);
+}
+
+TEST(MemoryHeapBase, MemfdSealed) {
+    auto mHeap = sp<MemoryHeapBase>::make(8192,
+                                          MemoryHeapBase::FORCE_MEMFD,
+                                          "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
+    int fd = mHeap->getHeapID();
+    EXPECT_NE(fd, -1);
+    EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL);
+}
+
+TEST(MemoryHeapBase, MemfdUnsealed) {
+    auto mHeap = sp<MemoryHeapBase>::make(8192,
+                                          MemoryHeapBase::FORCE_MEMFD |
+                                          MemoryHeapBase::MEMFD_ALLOW_SEALING,
+                                          "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
+    int fd = mHeap->getHeapID();
+    EXPECT_NE(fd, -1);
+    EXPECT_EQ(fcntl(fd, F_GET_SEALS), 0);
+}
+
+TEST(MemoryHeapBase, MemfdSealedProtected) {
+    auto mHeap = sp<MemoryHeapBase>::make(8192,
+                                          MemoryHeapBase::FORCE_MEMFD |
+                                          MemoryHeapBase::READ_ONLY,
+                                          "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
+    int fd = mHeap->getHeapID();
+    EXPECT_NE(fd, -1);
+    EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL | F_SEAL_FUTURE_WRITE);
+}
+
+TEST(MemoryHeapBase, MemfdUnsealedProtected) {
+    auto mHeap = sp<MemoryHeapBase>::make(8192,
+                                          MemoryHeapBase::FORCE_MEMFD |
+                                          MemoryHeapBase::READ_ONLY |
+                                          MemoryHeapBase::MEMFD_ALLOW_SEALING,
+                                          "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
+    int fd = mHeap->getHeapID();
+    EXPECT_NE(fd, -1);
+    EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_FUTURE_WRITE);
+}
+
+#else
+TEST(MemoryHeapBase, HostMemfdExpected) {
+    auto mHeap = sp<MemoryHeapBase>::make(8192,
+                                          MemoryHeapBase::READ_ONLY,
+                                          "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
+    int fd = mHeap->getHeapID();
+    void* ptr = mHeap->getBase();
+    EXPECT_NE(ptr, MAP_FAILED);
+    EXPECT_TRUE(ashmem_valid(fd));
+    EXPECT_EQ(mHeap->getFlags(), MemoryHeapBase::READ_ONLY);
+}
+
+TEST(MemoryHeapBase,HostMemfdException) {
+    auto mHeap = sp<MemoryHeapBase>::make(8192,
+                                          MemoryHeapBase::FORCE_MEMFD |
+                                          MemoryHeapBase::READ_ONLY |
+                                          MemoryHeapBase::MEMFD_ALLOW_SEALING,
+                                          "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
+    int fd = mHeap->getHeapID();
+    void* ptr = mHeap->getBase();
+    EXPECT_EQ(mHeap->getFlags(), MemoryHeapBase::READ_ONLY);
+    EXPECT_TRUE(ashmem_valid(fd));
+    EXPECT_NE(ptr, MAP_FAILED);
+}
+
+#endif
diff --git a/libs/binder/tests/binderParcelUnitTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp
index aee15d8..359c783 100644
--- a/libs/binder/tests/binderParcelUnitTest.cpp
+++ b/libs/binder/tests/binderParcelUnitTest.cpp
@@ -20,9 +20,12 @@
 #include <cutils/ashmem.h>
 #include <gtest/gtest.h>
 
+using android::BBinder;
+using android::IBinder;
 using android::IPCThreadState;
 using android::OK;
 using android::Parcel;
+using android::sp;
 using android::status_t;
 using android::String16;
 using android::String8;
@@ -75,6 +78,40 @@
     EXPECT_EQ(p.enforceNoDataAvail().exceptionCode(), Status::Exception::EX_NONE);
 }
 
+TEST(Parcel, DebugReadAllBinders) {
+    sp<IBinder> binder1 = sp<BBinder>::make();
+    sp<IBinder> binder2 = sp<BBinder>::make();
+
+    Parcel p;
+    p.writeInt32(4);
+    p.writeStrongBinder(binder1);
+    p.writeStrongBinder(nullptr);
+    p.writeInt32(4);
+    p.writeStrongBinder(binder2);
+    p.writeInt32(4);
+
+    auto ret = p.debugReadAllStrongBinders();
+
+    ASSERT_EQ(ret.size(), 2);
+    EXPECT_EQ(ret[0], binder1);
+    EXPECT_EQ(ret[1], binder2);
+}
+
+TEST(Parcel, DebugReadAllFds) {
+    Parcel p;
+    p.writeInt32(4);
+    p.writeFileDescriptor(STDOUT_FILENO, false /*takeOwnership*/);
+    p.writeInt32(4);
+    p.writeFileDescriptor(STDIN_FILENO, false /*takeOwnership*/);
+    p.writeInt32(4);
+
+    auto ret = p.debugReadAllFileDescriptors();
+
+    ASSERT_EQ(ret.size(), 2);
+    EXPECT_EQ(ret[0], STDOUT_FILENO);
+    EXPECT_EQ(ret[1], STDIN_FILENO);
+}
+
 // Tests a second operation results in a parcel at the same location as it
 // started.
 void parcelOpSameLength(const std::function<void(Parcel*)>& a, const std::function<void(Parcel*)>& b) {
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index c2639e7..3b1fc82 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -23,6 +23,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 #include <android/binder_auto_utils.h>
 #include <android/binder_libbinder.h>
 #include <binder/Binder.h>
@@ -53,6 +54,7 @@
 #include "../RpcSocketAddress.h" // for testing preconnected clients
 #include "../RpcState.h"         // for debugging
 #include "../vm_sockets.h"       // for VMADDR_*
+#include "utils/Errors.h"
 
 using namespace std::chrono_literals;
 using namespace std::placeholders;
@@ -92,6 +94,21 @@
     }
 }
 
+// Create an FD that returns `contents` when read.
+static base::unique_fd mockFileDescriptor(std::string contents) {
+    android::base::unique_fd readFd, writeFd;
+    CHECK(android::base::Pipe(&readFd, &writeFd)) << strerror(errno);
+    std::thread([writeFd = std::move(writeFd), contents = std::move(contents)]() {
+        signal(SIGPIPE, SIG_IGN); // ignore possible SIGPIPE from the write
+        if (!WriteStringToFd(contents, writeFd)) {
+            int savedErrno = errno;
+            EXPECT_EQ(EPIPE, savedErrno)
+                    << "mockFileDescriptor write failed: " << strerror(savedErrno);
+        }
+    }).detach();
+    return readFd;
+}
+
 TEST(BinderRpcParcel, EntireParcelFormatted) {
     Parcel p;
     p.writeInt32(3);
@@ -99,17 +116,19 @@
     EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
 }
 
-class BinderRpcSimple : public ::testing::TestWithParam<RpcSecurity> {
+class BinderRpcServerOnly : public ::testing::TestWithParam<std::tuple<RpcSecurity, uint32_t>> {
 public:
     static std::string PrintTestParam(const ::testing::TestParamInfo<ParamType>& info) {
-        return newFactory(info.param)->toCString();
+        return std::string(newFactory(std::get<0>(info.param))->toCString()) + "_serverV" +
+                std::to_string(std::get<1>(info.param));
     }
 };
 
-TEST_P(BinderRpcSimple, SetExternalServerTest) {
+TEST_P(BinderRpcServerOnly, SetExternalServerTest) {
     base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
     int sinkFd = sink.get();
-    auto server = RpcServer::make(newFactory(GetParam()));
+    auto server = RpcServer::make(newFactory(std::get<0>(GetParam())));
+    server->setProtocolVersion(std::get<1>(GetParam()));
     ASSERT_FALSE(server->hasServer());
     ASSERT_EQ(OK, server->setupExternalServer(std::move(sink)));
     ASSERT_TRUE(server->hasServer());
@@ -200,6 +219,10 @@
         }
         return Status::ok();
     }
+    Status getNullBinder(sp<IBinder>* out) override {
+        out->clear();
+        return Status::ok();
+    }
     Status pingMe(const sp<IBinder>& binder, int32_t* out) override {
         if (binder == nullptr) {
             std::cout << "Received null binder!" << std::endl;
@@ -322,9 +345,36 @@
         (void)IPCThreadState::self()->getCallingPid();
         return Status::ok();
     }
+
+    Status echoAsFile(const std::string& content, android::os::ParcelFileDescriptor* out) override {
+        out->reset(mockFileDescriptor(content));
+        return Status::ok();
+    }
+
+    Status concatFiles(const std::vector<android::os::ParcelFileDescriptor>& files,
+                       android::os::ParcelFileDescriptor* out) override {
+        std::string acc;
+        for (const auto& file : files) {
+            std::string result;
+            CHECK(android::base::ReadFdToString(file.get(), &result));
+            acc.append(result);
+        }
+        out->reset(mockFileDescriptor(acc));
+        return Status::ok();
+    }
 };
 sp<IBinder> MyBinderRpcTest::mHeldBinder;
 
+static std::string WaitStatusToString(int wstatus) {
+    if (WIFEXITED(wstatus)) {
+        return base::StringPrintf("exit status %d", WEXITSTATUS(wstatus));
+    }
+    if (WIFSIGNALED(wstatus)) {
+        return base::StringPrintf("term signal %d", WTERMSIG(wstatus));
+    }
+    return base::StringPrintf("unexpected state %d", wstatus);
+}
+
 class Process {
 public:
     Process(Process&&) = default;
@@ -345,13 +395,28 @@
     }
     ~Process() {
         if (mPid != 0) {
-            waitpid(mPid, nullptr, 0);
+            int wstatus;
+            waitpid(mPid, &wstatus, 0);
+            if (mCustomExitStatusCheck) {
+                mCustomExitStatusCheck(wstatus);
+            } else {
+                EXPECT_TRUE(WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0)
+                        << "server process failed: " << WaitStatusToString(wstatus);
+            }
         }
     }
     android::base::borrowed_fd readEnd() { return mReadEnd; }
     android::base::borrowed_fd writeEnd() { return mWriteEnd; }
 
+    void setCustomExitStatusCheck(std::function<void(int wstatus)> f) {
+        mCustomExitStatusCheck = std::move(f);
+    }
+
+    // Kill the process. Avoid if possible. Shutdown gracefully via an RPC instead.
+    void terminate() { kill(mPid, SIGTERM); }
+
 private:
+    std::function<void(int wstatus)> mCustomExitStatusCheck;
     pid_t mPid = 0;
     android::base::unique_fd mReadEnd;
     android::base::unique_fd mWriteEnd;
@@ -419,10 +484,10 @@
 
     BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default;
     ~BinderRpcTestProcessSession() {
-        EXPECT_NE(nullptr, rootIface);
-        if (rootIface == nullptr) return;
-
         if (!expectAlreadyShutdown) {
+            EXPECT_NE(nullptr, rootIface);
+            if (rootIface == nullptr) return;
+
             std::vector<int32_t> remoteCounts;
             // calling over any sessions counts across all sessions
             EXPECT_OK(rootIface->countBinders(&remoteCounts));
@@ -480,18 +545,40 @@
     return serverFd;
 }
 
-class BinderRpc : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity>> {
+class BinderRpc
+      : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t>> {
 public:
     struct Options {
         size_t numThreads = 1;
         size_t numSessions = 1;
         size_t numIncomingConnections = 0;
         size_t numOutgoingConnections = SIZE_MAX;
+        RpcSession::FileDescriptorTransportMode clientFileDescriptorTransportMode =
+                RpcSession::FileDescriptorTransportMode::NONE;
+        std::vector<RpcSession::FileDescriptorTransportMode>
+                serverSupportedFileDescriptorTransportModes = {
+                        RpcSession::FileDescriptorTransportMode::NONE};
+
+        // If true, connection failures will result in `ProcessSession::sessions` being empty
+        // instead of a fatal error.
+        bool allowConnectFailure = false;
     };
 
+    SocketType socketType() const { return std::get<0>(GetParam()); }
+    RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); }
+    uint32_t clientVersion() const { return std::get<2>(GetParam()); }
+    uint32_t serverVersion() const { return std::get<3>(GetParam()); }
+
+    // Whether the test params support sending FDs in parcels.
+    bool supportsFdTransport() const {
+        return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS &&
+                (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX);
+    }
+
     static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
-        auto [type, security] = info.param;
-        return PrintToString(type) + "_" + newFactory(security)->toCString();
+        auto [type, security, clientVersion, serverVersion] = info.param;
+        return PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
+                std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
     }
 
     static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
@@ -533,17 +620,22 @@
 
         SocketType socketType = std::get<0>(GetParam());
         RpcSecurity rpcSecurity = std::get<1>(GetParam());
+        uint32_t clientVersion = std::get<2>(GetParam());
+        uint32_t serverVersion = std::get<3>(GetParam());
 
         unsigned int vsockPort = allocateVsockPort();
         std::string addr = allocateSocketAddress();
 
         auto ret = ProcessSession{
-                .host = Process([&](android::base::borrowed_fd writeEnd,
+                .host = Process([=](android::base::borrowed_fd writeEnd,
                                     android::base::borrowed_fd readEnd) {
                     auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
                     sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
 
+                    server->setProtocolVersion(serverVersion);
                     server->setMaxThreads(options.numThreads);
+                    server->setSupportedFileDescriptorTransportModes(
+                            options.serverSupportedFileDescriptorTransportModes);
 
                     unsigned int outPort = 0;
 
@@ -618,8 +710,10 @@
         status_t status;
 
         for (const auto& session : sessions) {
+            CHECK(session->setProtocolVersion(clientVersion));
             session->setMaxIncomingThreads(options.numIncomingConnections);
             session->setMaxOutgoingThreads(options.numOutgoingConnections);
+            session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode);
 
             switch (socketType) {
                 case SocketType::PRECONNECTED:
@@ -639,6 +733,10 @@
                 default:
                     LOG_ALWAYS_FATAL("Unknown socket type");
             }
+            if (options.allowConnectFailure && status != OK) {
+                ret.sessions.clear();
+                break;
+            }
             CHECK_EQ(status, OK) << "Could not connect: " << statusToString(status);
             ret.sessions.push_back({session, session->getRootObject()});
         }
@@ -650,8 +748,11 @@
                 .proc = createRpcTestSocketServerProcess(
                         options,
                         [&](const sp<RpcServer>& server) {
-                            server->setPerSessionRootObject([&](const sockaddr* addr,
-                                                                socklen_t len) {
+                            server->setPerSessionRootObject([&](const void* addrPtr, size_t len) {
+                                // UNIX sockets with abstract addresses return
+                                // sizeof(sa_family_t)==2 in addrlen
+                                CHECK_GE(len, sizeof(sa_family_t));
+                                const sockaddr* addr = reinterpret_cast<const sockaddr*>(addrPtr);
                                 sp<MyBinderRpcTest> service = sp<MyBinderRpcTest>::make();
                                 switch (addr->sa_family) {
                                     case AF_UNIX:
@@ -684,7 +785,7 @@
                         }),
         };
 
-        ret.rootBinder = ret.proc.sessions.at(0).root;
+        ret.rootBinder = ret.proc.sessions.empty() ? nullptr : ret.proc.sessions.at(0).root;
         ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
 
         return ret;
@@ -752,7 +853,7 @@
     p1.markForBinder(proc1.rootBinder);
     p1.writeInt32(3);
 
-    EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, p1.dataSize()));
+    EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, pRaw.dataSize()));
     EXPECT_EQ(BAD_TYPE, pRaw.appendFrom(&p1, 0, p1.dataSize()));
 
     Parcel p2;
@@ -791,6 +892,13 @@
     EXPECT_EQ(single + single, doubled);
 }
 
+TEST_P(BinderRpc, InvalidNullBinderReturn) {
+    auto proc = createRpcTestSocketServerProcess({});
+
+    sp<IBinder> outBinder;
+    EXPECT_EQ(proc.rootIface->getNullBinder(&outBinder).transactionError(), UNEXPECTED_NULL);
+}
+
 TEST_P(BinderRpc, CallMeBack) {
     auto proc = createRpcTestSocketServerProcess({});
 
@@ -928,7 +1036,13 @@
 }
 
 TEST_P(BinderRpc, NestedTransactions) {
-    auto proc = createRpcTestSocketServerProcess({});
+    auto proc = createRpcTestSocketServerProcess({
+            // Enable FD support because it uses more stack space and so represents
+            // something closer to a worst case scenario.
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::UNIX},
+    });
 
     auto nastyNester = sp<MyBinderRpcTest>::make();
     EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
@@ -1248,9 +1362,14 @@
                             proc.rootIface->doCallback(cb, callbackIsOneway, delayed, kTestString));
                 }
 
-                using std::literals::chrono_literals::operator""s;
-                std::unique_lock<std::mutex> _l(cb->mMutex);
-                cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
+                // if both transactions are synchronous and the response is sent back on the
+                // same thread, everything should have happened in a nested call. Otherwise,
+                // the callback will be processed on another thread.
+                if (callIsOneway || callbackIsOneway || delayed) {
+                    using std::literals::chrono_literals::operator""s;
+                    std::unique_lock<std::mutex> _l(cb->mMutex);
+                    cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
+                }
 
                 EXPECT_EQ(cb->mValues.size(), 1)
                         << "callIsOneway: " << callIsOneway
@@ -1270,6 +1389,12 @@
                 // need to manually shut it down
                 EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
 
+                proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+                    // Flaky. Sometimes gets SIGABRT.
+                    EXPECT_TRUE((WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) ||
+                                (WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT))
+                            << "server process failed: " << WaitStatusToString(wstatus);
+                });
                 proc.expectAlreadyShutdown = true;
             }
         }
@@ -1299,6 +1424,10 @@
         EXPECT_EQ(DEAD_OBJECT, proc.rootIface->die(doDeathCleanup).transactionError())
                 << "Do death cleanup: " << doDeathCleanup;
 
+        proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+            EXPECT_TRUE(WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 1)
+                    << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+        });
         proc.expectAlreadyShutdown = true;
     }
 }
@@ -1322,9 +1451,150 @@
     // second time! we catch the error :)
     EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError());
 
+    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+        EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT)
+                << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+    });
     proc.expectAlreadyShutdown = true;
 }
 
+TEST_P(BinderRpc, FileDescriptorTransportRejectNone) {
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::NONE,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::UNIX},
+            .allowConnectFailure = true,
+    });
+    EXPECT_TRUE(proc.proc.sessions.empty()) << "session connections should have failed";
+    proc.proc.host.terminate();
+    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+        EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
+                << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+    });
+    proc.expectAlreadyShutdown = true;
+}
+
+TEST_P(BinderRpc, FileDescriptorTransportRejectUnix) {
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::NONE},
+            .allowConnectFailure = true,
+    });
+    EXPECT_TRUE(proc.proc.sessions.empty()) << "session connections should have failed";
+    proc.proc.host.terminate();
+    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+        EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
+                << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+    });
+    proc.expectAlreadyShutdown = true;
+}
+
+TEST_P(BinderRpc, FileDescriptorTransportOptionalUnix) {
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::NONE,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::NONE,
+                     RpcSession::FileDescriptorTransportMode::UNIX},
+    });
+
+    android::os::ParcelFileDescriptor out;
+    auto status = proc.rootIface->echoAsFile("hello", &out);
+    EXPECT_EQ(status.transactionError(), FDS_NOT_ALLOWED) << status;
+}
+
+TEST_P(BinderRpc, ReceiveFile) {
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::UNIX},
+    });
+
+    android::os::ParcelFileDescriptor out;
+    auto status = proc.rootIface->echoAsFile("hello", &out);
+    if (!supportsFdTransport()) {
+        EXPECT_EQ(status.transactionError(), BAD_VALUE) << status;
+        return;
+    }
+    ASSERT_TRUE(status.isOk()) << status;
+
+    std::string result;
+    CHECK(android::base::ReadFdToString(out.get(), &result));
+    EXPECT_EQ(result, "hello");
+}
+
+TEST_P(BinderRpc, SendFiles) {
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::UNIX},
+    });
+
+    std::vector<android::os::ParcelFileDescriptor> files;
+    files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("123")));
+    files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("a")));
+    files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("b")));
+    files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("cd")));
+
+    android::os::ParcelFileDescriptor out;
+    auto status = proc.rootIface->concatFiles(files, &out);
+    if (!supportsFdTransport()) {
+        EXPECT_EQ(status.transactionError(), BAD_VALUE) << status;
+        return;
+    }
+    ASSERT_TRUE(status.isOk()) << status;
+
+    std::string result;
+    CHECK(android::base::ReadFdToString(out.get(), &result));
+    EXPECT_EQ(result, "123abcd");
+}
+
+TEST_P(BinderRpc, SendMaxFiles) {
+    if (!supportsFdTransport()) {
+        GTEST_SKIP() << "Would fail trivially (which is tested by BinderRpc::SendFiles)";
+    }
+
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::UNIX},
+    });
+
+    std::vector<android::os::ParcelFileDescriptor> files;
+    for (int i = 0; i < 253; i++) {
+        files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("a")));
+    }
+
+    android::os::ParcelFileDescriptor out;
+    auto status = proc.rootIface->concatFiles(files, &out);
+    ASSERT_TRUE(status.isOk()) << status;
+
+    std::string result;
+    CHECK(android::base::ReadFdToString(out.get(), &result));
+    EXPECT_EQ(result, std::string(253, 'a'));
+}
+
+TEST_P(BinderRpc, SendTooManyFiles) {
+    if (!supportsFdTransport()) {
+        GTEST_SKIP() << "Would fail trivially (which is tested by BinderRpc::SendFiles)";
+    }
+
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::UNIX},
+    });
+
+    std::vector<android::os::ParcelFileDescriptor> files;
+    for (int i = 0; i < 254; i++) {
+        files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("a")));
+    }
+
+    android::os::ParcelFileDescriptor out;
+    auto status = proc.rootIface->concatFiles(files, &out);
+    EXPECT_EQ(status.transactionError(), BAD_VALUE) << status;
+}
+
 TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
     auto proc = createRpcTestSocketServerProcess({});
 
@@ -1412,9 +1682,20 @@
     return ret;
 }
 
+static std::vector<uint32_t> testVersions() {
+    std::vector<uint32_t> versions;
+    for (size_t i = 0; i < RPC_WIRE_PROTOCOL_VERSION_NEXT; i++) {
+        versions.push_back(i);
+    }
+    versions.push_back(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
+    return versions;
+}
+
 INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
                         ::testing::Combine(::testing::ValuesIn(testSocketTypes()),
-                                           ::testing::ValuesIn(RpcSecurityValues())),
+                                           ::testing::ValuesIn(RpcSecurityValues()),
+                                           ::testing::ValuesIn(testVersions()),
+                                           ::testing::ValuesIn(testVersions())),
                         BinderRpc::PrintParamInfo);
 
 class BinderRpcServerRootObject
@@ -1468,9 +1749,10 @@
     bool mValue = false;
 };
 
-TEST_P(BinderRpcSimple, Shutdown) {
+TEST_P(BinderRpcServerOnly, Shutdown) {
     auto addr = allocateSocketAddress();
-    auto server = RpcServer::make(newFactory(GetParam()));
+    auto server = RpcServer::make(newFactory(std::get<0>(GetParam())));
+    server->setProtocolVersion(std::get<1>(GetParam()));
     ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
     auto joinEnds = std::make_shared<OneOffSignal>();
 
@@ -1540,12 +1822,17 @@
     ASSERT_EQ(OK, rpcBinder->pingBinder());
 }
 
-INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
-                        BinderRpcSimple::PrintTestParam);
+INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcServerOnly,
+                        ::testing::Combine(::testing::ValuesIn(RpcSecurityValues()),
+                                           ::testing::ValuesIn(testVersions())),
+                        BinderRpcServerOnly::PrintTestParam);
 
 class RpcTransportTestUtils {
 public:
-    using Param = std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>>;
+    // Only parameterized only server version because `RpcSession` is bypassed
+    // in the client half of the tests.
+    using Param =
+            std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>, uint32_t>;
     using ConnectToServer = std::function<base::unique_fd()>;
 
     // A server that handles client socket connections.
@@ -1557,8 +1844,9 @@
         [[nodiscard]] AssertionResult setUp(
                 const Param& param,
                 std::unique_ptr<RpcAuth> auth = std::make_unique<RpcAuthSelfSigned>()) {
-            auto [socketType, rpcSecurity, certificateFormat] = param;
+            auto [socketType, rpcSecurity, certificateFormat, serverVersion] = param;
             auto rpcServer = RpcServer::make(newFactory(rpcSecurity));
+            rpcServer->setProtocolVersion(serverVersion);
             switch (socketType) {
                 case SocketType::PRECONNECTED: {
                     return AssertionFailure() << "Not supported by this test";
@@ -1676,7 +1964,8 @@
                                                   FdTrigger* fdTrigger) {
             std::string message(kMessage);
             iovec messageIov{message.data(), message.size()};
-            auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1, {});
+            auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1,
+                                                                   std::nullopt, nullptr);
             if (status != OK) return AssertionFailure() << statusToString(status);
             return AssertionSuccess();
         }
@@ -1687,7 +1976,8 @@
         explicit Client(ConnectToServer connectToServer) : mConnectToServer(connectToServer) {}
         Client(Client&&) = default;
         [[nodiscard]] AssertionResult setUp(const Param& param) {
-            auto [socketType, rpcSecurity, certificateFormat] = param;
+            auto [socketType, rpcSecurity, certificateFormat, serverVersion] = param;
+            (void)serverVersion;
             mFdTrigger = FdTrigger::make();
             mCtx = newFactory(rpcSecurity, mCertVerifier)->newClientCtx();
             if (mCtx == nullptr) return AssertionFailure() << "newClientCtx";
@@ -1708,8 +1998,9 @@
             LOG_ALWAYS_FATAL_IF(mClientTransport == nullptr, "setUpTransport not called or failed");
             std::string readMessage(expectedMessage.size(), '\0');
             iovec readMessageIov{readMessage.data(), readMessage.size()};
-            status_t readStatus = mClientTransport->interruptableReadFully(mFdTrigger.get(),
-                                                                           &readMessageIov, 1, {});
+            status_t readStatus =
+                    mClientTransport->interruptableReadFully(mFdTrigger.get(), &readMessageIov, 1,
+                                                             std::nullopt, false);
             if (readStatus != OK) {
                 return AssertionFailure() << statusToString(readStatus);
             }
@@ -1757,23 +2048,28 @@
     using Server = RpcTransportTestUtils::Server;
     using Client = RpcTransportTestUtils::Client;
     static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
-        auto [socketType, rpcSecurity, certificateFormat] = info.param;
+        auto [socketType, rpcSecurity, certificateFormat, serverVersion] = info.param;
         auto ret = PrintToString(socketType) + "_" + newFactory(rpcSecurity)->toCString();
         if (certificateFormat.has_value()) ret += "_" + PrintToString(*certificateFormat);
+        ret += "_serverV" + std::to_string(serverVersion);
         return ret;
     }
     static std::vector<ParamType> getRpcTranportTestParams() {
         std::vector<ParamType> ret;
-        for (auto socketType : testSocketTypes(false /* hasPreconnected */)) {
-            for (auto rpcSecurity : RpcSecurityValues()) {
-                switch (rpcSecurity) {
-                    case RpcSecurity::RAW: {
-                        ret.emplace_back(socketType, rpcSecurity, std::nullopt);
-                    } break;
-                    case RpcSecurity::TLS: {
-                        ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM);
-                        ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER);
-                    } break;
+        for (auto serverVersion : testVersions()) {
+            for (auto socketType : testSocketTypes(false /* hasPreconnected */)) {
+                for (auto rpcSecurity : RpcSecurityValues()) {
+                    switch (rpcSecurity) {
+                        case RpcSecurity::RAW: {
+                            ret.emplace_back(socketType, rpcSecurity, std::nullopt, serverVersion);
+                        } break;
+                        case RpcSecurity::TLS: {
+                            ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM,
+                                             serverVersion);
+                            ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER,
+                                             serverVersion);
+                        } break;
+                    }
                 }
             }
         }
@@ -1781,7 +2077,8 @@
     }
     template <typename A, typename B>
     status_t trust(const A& a, const B& b) {
-        auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+        auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+        (void)serverVersion;
         return RpcTransportTestUtils::trust(rpcSecurity, certificateFormat, a, b);
     }
 };
@@ -1817,7 +2114,8 @@
 }
 
 TEST_P(RpcTransportTest, UntrustedServer) {
-    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+    auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+    (void)serverVersion;
 
     auto untrustedServer = std::make_unique<Server>();
     ASSERT_TRUE(untrustedServer->setUp(GetParam()));
@@ -1835,7 +2133,9 @@
     client.run(handshakeOk);
 }
 TEST_P(RpcTransportTest, MaliciousServer) {
-    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+    auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+    (void)serverVersion;
+
     auto validServer = std::make_unique<Server>();
     ASSERT_TRUE(validServer->setUp(GetParam()));
 
@@ -1858,7 +2158,9 @@
 }
 
 TEST_P(RpcTransportTest, UntrustedClient) {
-    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+    auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+    (void)serverVersion;
+
     auto server = std::make_unique<Server>();
     ASSERT_TRUE(server->setUp(GetParam()));
 
@@ -1877,7 +2179,9 @@
 }
 
 TEST_P(RpcTransportTest, MaliciousClient) {
-    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+    auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+    (void)serverVersion;
+
     auto server = std::make_unique<Server>();
     ASSERT_TRUE(server->setUp(GetParam()));
 
@@ -1904,7 +2208,8 @@
     auto serverPostConnect = [&](RpcTransport* serverTransport, FdTrigger* fdTrigger) {
         std::string message(RpcTransportTestUtils::kMessage);
         iovec messageIov{message.data(), message.size()};
-        auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1, {});
+        auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1,
+                                                               std::nullopt, nullptr);
         if (status != OK) return AssertionFailure() << statusToString(status);
 
         {
@@ -1915,7 +2220,8 @@
         }
 
         iovec msg2Iov{msg2.data(), msg2.size()};
-        status = serverTransport->interruptableWriteFully(fdTrigger, &msg2Iov, 1, {});
+        status = serverTransport->interruptableWriteFully(fdTrigger, &msg2Iov, 1, std::nullopt,
+                                                          nullptr);
         if (status != DEAD_OBJECT)
             return AssertionFailure() << "When FdTrigger is shut down, interruptableWriteFully "
                                          "should return DEAD_OBJECT, but it is "
@@ -1962,23 +2268,24 @@
                         RpcTransportTest::PrintParamInfo);
 
 class RpcTransportTlsKeyTest
-      : public testing::TestWithParam<std::tuple<SocketType, RpcCertificateFormat, RpcKeyFormat>> {
+      : public testing::TestWithParam<
+                std::tuple<SocketType, RpcCertificateFormat, RpcKeyFormat, uint32_t>> {
 public:
     template <typename A, typename B>
     status_t trust(const A& a, const B& b) {
-        auto [socketType, certificateFormat, keyFormat] = GetParam();
+        auto [socketType, certificateFormat, keyFormat, serverVersion] = GetParam();
+        (void)serverVersion;
         return RpcTransportTestUtils::trust(RpcSecurity::TLS, certificateFormat, a, b);
     }
     static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
-        auto [socketType, certificateFormat, keyFormat] = info.param;
-        auto ret = PrintToString(socketType) + "_certificate_" + PrintToString(certificateFormat) +
-                "_key_" + PrintToString(keyFormat);
-        return ret;
+        auto [socketType, certificateFormat, keyFormat, serverVersion] = info.param;
+        return PrintToString(socketType) + "_certificate_" + PrintToString(certificateFormat) +
+                "_key_" + PrintToString(keyFormat) + "_serverV" + std::to_string(serverVersion);
     };
 };
 
 TEST_P(RpcTransportTlsKeyTest, PreSignedCertificate) {
-    auto [socketType, certificateFormat, keyFormat] = GetParam();
+    auto [socketType, certificateFormat, keyFormat, serverVersion] = GetParam();
 
     std::vector<uint8_t> pkeyData, certData;
     {
@@ -1993,8 +2300,8 @@
     auto desPkey = deserializeUnencryptedPrivatekey(pkeyData, keyFormat);
     auto desCert = deserializeCertificate(certData, certificateFormat);
     auto auth = std::make_unique<RpcAuthPreSigned>(std::move(desPkey), std::move(desCert));
-    auto utilsParam =
-            std::make_tuple(socketType, RpcSecurity::TLS, std::make_optional(certificateFormat));
+    auto utilsParam = std::make_tuple(socketType, RpcSecurity::TLS,
+                                      std::make_optional(certificateFormat), serverVersion);
 
     auto server = std::make_unique<RpcTransportTestUtils::Server>();
     ASSERT_TRUE(server->setUp(utilsParam, std::move(auth)));
@@ -2013,7 +2320,8 @@
         BinderRpc, RpcTransportTlsKeyTest,
         testing::Combine(testing::ValuesIn(testSocketTypes(false /* hasPreconnected*/)),
                          testing::Values(RpcCertificateFormat::PEM, RpcCertificateFormat::DER),
-                         testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER)),
+                         testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER),
+                         testing::ValuesIn(testVersions())),
         RpcTransportTlsKeyTest::PrintParamInfo);
 
 } // namespace android
diff --git a/libs/binder/tests/binderRpcWireProtocolTest.cpp b/libs/binder/tests/binderRpcWireProtocolTest.cpp
index a807afa..3dab2c7 100644
--- a/libs/binder/tests/binderRpcWireProtocolTest.cpp
+++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp
@@ -233,12 +233,17 @@
         "0100000025000000|03000000|00000000|ffffffff|03000000|00000000|00000000|"
         "07000000020000003a0044000000000000000000|f8ffffff020000003a002f00000000000000000008000000";
 
+TEST(RpcWire, V0) {
+    checkRepr(kCurrentRepr, 0);
+}
+
 TEST(RpcWire, CurrentVersion) {
     checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION);
 }
 
 static_assert(RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL,
-              "you better update this test!");
+              "If the binder wire protocol is updated, this test should test additional versions. "
+              "The binder wire protocol should only be updated on upstream AOSP.");
 
 TEST(RpcWire, ReleaseBranchHasFrozenRpcWireProtocol) {
     if (RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
diff --git a/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
index 094addd..50d12c4 100644
--- a/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
+++ b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
@@ -18,6 +18,7 @@
 
 #include <memory>
 #include <mutex>
+#include <vector>
 
 #include <binder/RpcAuth.h>
 #include <binder/RpcCertificateFormat.h>
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 38bde3a..2ca6ebd 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -29,7 +29,6 @@
         "libcutils",
         "libhidlbase",
         "liblog",
-        "libutils",
     ],
 
     target: {
@@ -37,12 +36,14 @@
             shared_libs: [
                 "libbinder_ndk",
                 "libbinder",
+                "libutils",
             ],
         },
         host: {
             static_libs: [
                 "libbinder_ndk",
                 "libbinder",
+                "libutils",
             ],
         },
         darwin: {
@@ -58,6 +59,7 @@
 cc_library_static {
     name: "libbinder_random_parcel",
     host_supported: true,
+    vendor_available: true,
     target: {
         darwin: {
             enabled: false,
@@ -66,10 +68,13 @@
     srcs: [
         "random_fd.cpp",
         "random_parcel.cpp",
+        "libbinder_driver.cpp",
+        "libbinder_ndk_driver.cpp",
     ],
     shared_libs: [
         "libbase",
         "libbinder",
+        "libbinder_ndk",
         "libcutils",
         "libutils",
     ],
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 13f7195..7059d30 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -73,20 +73,20 @@
     uint8_t data[1337];
 };
 
-#define PARCEL_READ_WITH_STATUS(T, FUN) \
-    [] (const ::android::Parcel& p, uint8_t /*data*/) {\
-        FUZZ_LOG() << "about to read " #T " using " #FUN " with status";\
-        T t{};\
-        status_t status = p.FUN(&t);\
-        FUZZ_LOG() << #T " status: " << status /* << " value: " << t*/;\
+#define PARCEL_READ_WITH_STATUS(T, FUN)                                  \
+    [](const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {   \
+        FUZZ_LOG() << "about to read " #T " using " #FUN " with status"; \
+        T t{};                                                           \
+        status_t status = p.FUN(&t);                                     \
+        FUZZ_LOG() << #T " status: " << status /* << " value: " << t*/;  \
     }
 
-#define PARCEL_READ_NO_STATUS(T, FUN) \
-    [] (const ::android::Parcel& p, uint8_t /*data*/) {\
-        FUZZ_LOG() << "about to read " #T " using " #FUN " with no status";\
-        T t = p.FUN();\
-        (void) t;\
-        FUZZ_LOG() << #T " done " /* << " value: " << t*/;\
+#define PARCEL_READ_NO_STATUS(T, FUN)                                       \
+    [](const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {      \
+        FUZZ_LOG() << "about to read " #T " using " #FUN " with no status"; \
+        T t = p.FUN();                                                      \
+        (void)t;                                                            \
+        FUZZ_LOG() << #T " done " /* << " value: " << t*/;                  \
     }
 
 #define PARCEL_READ_OPT_STATUS(T, FUN) \
@@ -102,20 +102,24 @@
     PARCEL_READ_NO_STATUS(size_t, dataPosition),
     PARCEL_READ_NO_STATUS(size_t, dataCapacity),
     PARCEL_READ_NO_STATUS(::android::binder::Status, enforceNoDataAvail),
-    [] (const ::android::Parcel& p, uint8_t pos) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
+        // aborts on larger values
+        size_t pos = provider.ConsumeIntegralInRange<size_t>(0, INT32_MAX);
         FUZZ_LOG() << "about to setDataPosition: " << pos;
         p.setDataPosition(pos);
         FUZZ_LOG() << "setDataPosition done";
     },
     PARCEL_READ_NO_STATUS(size_t, allowFds),
     PARCEL_READ_NO_STATUS(size_t, hasFileDescriptors),
-    [] (const ::android::Parcel& p, uint8_t len) {
-        std::string interface(len, 'a');
+    PARCEL_READ_NO_STATUS(std::vector<android::sp<android::IBinder>>, debugReadAllStrongBinders),
+    PARCEL_READ_NO_STATUS(std::vector<int>, debugReadAllFileDescriptors),
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
+        std::string interface = provider.ConsumeRandomLengthString();
         FUZZ_LOG() << "about to enforceInterface: " << interface;
         bool b = p.enforceInterface(::android::String16(interface.c_str()));
         FUZZ_LOG() << "enforced interface: " << b;
     },
-    [] (const ::android::Parcel& p, uint8_t /*len*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to checkInterface";
         android::sp<android::IBinder> aBinder = new android::BBinder();
         bool b = p.checkInterface(aBinder.get());
@@ -123,13 +127,16 @@
     },
     PARCEL_READ_NO_STATUS(size_t, objectsCount),
     PARCEL_READ_NO_STATUS(status_t, errorCheck),
-    [] (const ::android::Parcel& p, uint8_t len) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
+        // Read at least a bit. Unbounded allocation would OOM.
+        size_t len = provider.ConsumeIntegralInRange<size_t>(0, 1024);
         FUZZ_LOG() << "about to read void*";
         std::vector<uint8_t> data(len);
         status_t status = p.read(data.data(), len);
         FUZZ_LOG() << "read status: " << status;
     },
-    [] (const ::android::Parcel& p, uint8_t len) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
+        size_t len = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to readInplace";
         const void* r = p.readInplace(len);
         FUZZ_LOG() << "readInplace done. pointer: " << r << " bytes: " << (r ? HexString(r, len) : "null");
@@ -147,13 +154,13 @@
     PARCEL_READ_WITH_STATUS(std::string, readUtf8FromUtf16),
     PARCEL_READ_WITH_STATUS(std::unique_ptr<std::string>, readUtf8FromUtf16),
     PARCEL_READ_WITH_STATUS(std::optional<std::string>, readUtf8FromUtf16),
-    [] (const ::android::Parcel& p, uint8_t /*data*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to read c-str";
         const char* str = p.readCString();
         FUZZ_LOG() << "read c-str: " << (str ? str : "<empty string>");
     },
     PARCEL_READ_OPT_STATUS(android::String8, readString8),
-    [] (const ::android::Parcel& p, uint8_t /*data*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to readString8Inplace";
         size_t outLen = 0;
         const char* str = p.readString8Inplace(&outLen);
@@ -163,7 +170,7 @@
     PARCEL_READ_OPT_STATUS(android::String16, readString16),
     PARCEL_READ_WITH_STATUS(std::unique_ptr<android::String16>, readString16),
     PARCEL_READ_WITH_STATUS(std::optional<android::String16>, readString16),
-    [] (const ::android::Parcel& p, uint8_t /*data*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to readString16Inplace";
         size_t outLen = 0;
         const char16_t* str = p.readString16Inplace(&outLen);
@@ -261,13 +268,13 @@
     PARCEL_READ_WITH_STATUS(std::optional<std::array<std::array<std::optional<ExampleParcelable> COMMA 3> COMMA 4>>, readFixedArray),
 #undef COMMA
 
-    [] (const android::Parcel& p, uint8_t /*len*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to read flattenable";
         ExampleFlattenable f;
         status_t status = p.read(f);
         FUZZ_LOG() << "read flattenable: " << status;
     },
-    [] (const android::Parcel& p, uint8_t /*len*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to read lite flattenable";
         ExampleLightFlattenable f;
         status_t status = p.read(f);
@@ -282,7 +289,7 @@
     PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<BigStruct>>, resizeOutVector),
 
     PARCEL_READ_NO_STATUS(int32_t, readExceptionCode),
-    [] (const android::Parcel& p, uint8_t /*len*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to readNativeHandle";
         native_handle_t* t = p.readNativeHandle();
         FUZZ_LOG() << "readNativeHandle: " << t;
@@ -301,15 +308,16 @@
     PARCEL_READ_WITH_STATUS(std::optional<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector),
     PARCEL_READ_WITH_STATUS(std::vector<android::base::unique_fd>, readUniqueFileDescriptorVector),
 
-    [] (const android::Parcel& p, uint8_t len) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
+        size_t len = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to readBlob";
         ::android::Parcel::ReadableBlob blob;
         status_t status = p.readBlob(len, &blob);
         FUZZ_LOG() << "readBlob status: " << status;
     },
-    [] (const android::Parcel& p, uint8_t options) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
         FUZZ_LOG() << "about to readObject";
-        bool nullMetaData = options & 0x1;
+        bool nullMetaData = provider.ConsumeBool();
         const void* obj = static_cast<const void*>(p.readObject(nullMetaData));
         FUZZ_LOG() << "readObject: " << obj;
     },
@@ -317,20 +325,19 @@
     PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),
 
     // additional parcelable objects defined in libbinder
-    [] (const ::android::Parcel& p, uint8_t data) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
         using ::android::os::ParcelableHolder;
         using ::android::Parcelable;
         FUZZ_LOG() << "about to read ParcelableHolder using readParcelable with status";
-        Parcelable::Stability stability = Parcelable::Stability::STABILITY_LOCAL;
-        if ( (data & 1) == 1 ) {
-            stability = Parcelable::Stability::STABILITY_VINTF;
-        }
+        Parcelable::Stability stability = provider.ConsumeBool()
+            ? Parcelable::Stability::STABILITY_LOCAL
+            : Parcelable::Stability::STABILITY_VINTF;
         ParcelableHolder t = ParcelableHolder(stability);
         status_t status = p.readParcelable(&t);
         FUZZ_LOG() << "ParcelableHolder status: " << status;
     },
     PARCEL_READ_WITH_STATUS(android::os::PersistableBundle, readParcelable),
-    [] (const ::android::Parcel& p, uint8_t /* data */) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to call hasFileDescriptorsInRange() with status";
         size_t offset = p.readUint32();
         size_t length = p.readUint32();
@@ -338,7 +345,7 @@
         status_t status = p.hasFileDescriptorsInRange(offset, length, &result);
         FUZZ_LOG() << " status: " << status  << " result: " << result;
     },
-    [] (const ::android::Parcel& p, uint8_t /* data */) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to call compareDataInRange() with status";
         size_t thisOffset = p.readUint32();
         size_t otherOffset = p.readUint32();
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 5aeb5cc..26d6770 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -70,7 +70,7 @@
 }
 
 #define PARCEL_READ(T, FUN)                                              \
-    [](const NdkParcelAdapter& p, uint8_t /*data*/) {                    \
+    [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {    \
         FUZZ_LOG() << "about to read " #T " using " #FUN " with status"; \
         T t{};                                                           \
         binder_status_t status = FUN(p.aParcel(), &t);                   \
@@ -80,32 +80,37 @@
 // clang-format off
 std::vector<ParcelRead<NdkParcelAdapter>> BINDER_NDK_PARCEL_READ_FUNCTIONS{
         // methods from binder_parcel.h
-        [](const NdkParcelAdapter& p, uint8_t pos) {
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& provider) {
+            // aborts on larger values
+            size_t pos = provider.ConsumeIntegralInRange<size_t>(0, INT32_MAX);
             FUZZ_LOG() << "about to set data position to " << pos;
             binder_status_t status = AParcel_setDataPosition(p.aParcel(), pos);
             FUZZ_LOG() << "set data position: " << status;
         },
-        [](const NdkParcelAdapter& p, uint8_t /*data*/) {
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
             FUZZ_LOG() << "about to read status header";
             ndk::ScopedAStatus t;
             binder_status_t status = AParcel_readStatusHeader(p.aParcel(), t.getR());
             FUZZ_LOG() << "read status header: " << status;
         },
-        [](const NdkParcelAdapter& p, uint8_t /*data*/) {
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
             FUZZ_LOG() << "about to getDataSize the parcel";
             AParcel_getDataSize(p.aParcel());
             FUZZ_LOG() << "getDataSize done";
         },
-        [](const NdkParcelAdapter& p, uint8_t data) {
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& provider) {
             FUZZ_LOG() << "about to read a ParcelableHolder";
-            ndk::AParcelableHolder ph {(data % 2 == 1) ? ndk::STABILITY_LOCAL : ndk::STABILITY_VINTF};
+            ndk::AParcelableHolder ph {provider.ConsumeBool() ? ndk::STABILITY_LOCAL : ndk::STABILITY_VINTF};
             binder_status_t status = AParcel_readParcelable(p.aParcel(), &ph);
             FUZZ_LOG() << "read the ParcelableHolder: " << status;
         },
-        [](const NdkParcelAdapter& p, uint8_t data) {
-            FUZZ_LOG() << "about to appendFrom";
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& provider) {
+            size_t offset = provider.ConsumeIntegral<size_t>();
+            size_t pos = provider.ConsumeIntegral<size_t>();
+            FUZZ_LOG() << "about to appendFrom " << pos;
+            // TODO: create random parcel
             AParcel* parcel = AParcel_create();
-            binder_status_t status = AParcel_appendFrom(p.aParcel(), parcel, 0, data);
+            binder_status_t status = AParcel_appendFrom(p.aParcel(), parcel, offset, pos);
             AParcel_delete(parcel);
             FUZZ_LOG() << "appendFrom: " << status;
         },
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.h b/libs/binder/tests/parcel_fuzzer/binder_ndk.h
index cf24ab9..81e79b5 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.h
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.h
@@ -43,6 +43,10 @@
         return aParcel()->get()->setData(buffer, len);
     }
 
+    android::status_t appendFrom(const NdkParcelAdapter* parcel, int32_t start, int32_t len) {
+        return AParcel_appendFrom(parcel->aParcel(), aParcel(), start, len);
+    }
+
 private:
     ndk::ScopedAParcel mParcel;
 };
diff --git a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
index ee9840f..438e8ae 100644
--- a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
@@ -35,19 +35,19 @@
 #define PARCEL_READ_OPT_STATUS(T, FUN) \
     PARCEL_READ_NO_STATUS(T, FUN), PARCEL_READ_WITH_STATUS(T, FUN)
 
-#define PARCEL_READ_NO_STATUS(T, FUN) \
-    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {\
-        FUZZ_LOG() << "about to read " #T " using " #FUN " with no status";\
-        T t = p.FUN();\
-        FUZZ_LOG() << #T " value: " << t;\
+#define PARCEL_READ_NO_STATUS(T, FUN)                                            \
+    [](const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) { \
+        FUZZ_LOG() << "about to read " #T " using " #FUN " with no status";      \
+        T t = p.FUN();                                                           \
+        FUZZ_LOG() << #T " value: " << t;                                        \
     }
 
-#define PARCEL_READ_WITH_STATUS(T, FUN) \
-    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {\
-        FUZZ_LOG() << "about to read " #T " using " #FUN " with status";\
-        T t;\
-        status_t status = p.FUN(&t);\
-        FUZZ_LOG() << #T " status: " << status << " value: " << t;\
+#define PARCEL_READ_WITH_STATUS(T, FUN)                                          \
+    [](const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) { \
+        FUZZ_LOG() << "about to read " #T " using " #FUN " with status";         \
+        T t;                                                                     \
+        status_t status = p.FUN(&t);                                             \
+        FUZZ_LOG() << #T " status: " << status << " value: " << t;               \
     }
 
 // clang-format off
@@ -56,27 +56,30 @@
     PARCEL_READ_NO_STATUS(size_t, dataAvail),
     PARCEL_READ_NO_STATUS(size_t, dataPosition),
     PARCEL_READ_NO_STATUS(size_t, dataCapacity),
-    [] (const ::android::hardware::Parcel& p, uint8_t pos) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        // aborts on larger values
+        size_t pos = provider.ConsumeIntegralInRange<size_t>(0, INT32_MAX);
         FUZZ_LOG() << "about to setDataPosition: " << pos;
         p.setDataPosition(pos);
         FUZZ_LOG() << "setDataPosition done";
     },
-    [] (const ::android::hardware::Parcel& p, uint8_t length) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
         FUZZ_LOG() << "about to enforceInterface";
-        std::string interfaceName(length, 'a');
-        bool okay = p.enforceInterface(interfaceName.c_str());
+        bool okay = p.enforceInterface(provider.ConsumeRandomLengthString().c_str());
         FUZZ_LOG() << "enforceInterface status: " << okay;
     },
     PARCEL_READ_NO_STATUS(size_t, objectsCount),
-    [] (const ::android::hardware::Parcel& p, uint8_t length) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        // Read at least a bit. Unbounded allocation would OOM.
+        size_t length = provider.ConsumeIntegralInRange<size_t>(0, 1024);
         FUZZ_LOG() << "about to read";
         std::vector<uint8_t> data (length);
         status_t status = p.read(data.data(), length);
         FUZZ_LOG() << "read status: " << status << " data: " << HexString(data.data(), data.size());
     },
-    [] (const ::android::hardware::Parcel& p, uint8_t length) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        size_t length = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to read";
-        std::vector<uint8_t> data (length);
         const void* inplace = p.readInplace(length);
         FUZZ_LOG() << "read status: " << (inplace ? HexString(inplace, length) : "null");
     },
@@ -91,14 +94,14 @@
     PARCEL_READ_OPT_STATUS(float, readFloat),
     PARCEL_READ_OPT_STATUS(double, readDouble),
     PARCEL_READ_OPT_STATUS(bool, readBool),
-    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to readCString";
         const char* str = p.readCString();
         FUZZ_LOG() << "readCString " << (str ? str : "<null>");
     },
     PARCEL_READ_OPT_STATUS(::android::String16, readString16),
     PARCEL_READ_WITH_STATUS(std::unique_ptr<::android::String16>, readString16),
-    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to readString16Inplace";
         size_t outSize = 0;
         const char16_t* str = p.readString16Inplace(&outSize);
@@ -106,7 +109,8 @@
     },
     PARCEL_READ_OPT_STATUS(::android::sp<::android::hardware::IBinder>, readStrongBinder),
     PARCEL_READ_WITH_STATUS(::android::sp<::android::hardware::IBinder>, readNullableStrongBinder),
-    [] (const ::android::hardware::Parcel& p, uint8_t size) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        size_t size = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to readBuffer";
         size_t handle = 0;
         const void* data = nullptr;
@@ -116,7 +120,8 @@
         // should be null since we don't create any IPC objects
         CHECK(data == nullptr) << data;
     },
-    [] (const ::android::hardware::Parcel& p, uint8_t size) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        size_t size = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to readNullableBuffer";
         size_t handle = 0;
         const void* data = nullptr;
@@ -126,7 +131,8 @@
         // should be null since we don't create any IPC objects
         CHECK(data == nullptr) << data;
     },
-    [] (const ::android::hardware::Parcel& p, uint8_t size) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        size_t size = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to readEmbeddedBuffer";
         size_t handle = 0;
         size_t parent_buffer_handle = 0;
@@ -138,7 +144,8 @@
         // should be null since we don't create any IPC objects
         CHECK(data == nullptr) << data;
     },
-    [] (const ::android::hardware::Parcel& p, uint8_t size) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        size_t size = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to readNullableEmbeddedBuffer";
         size_t handle = 0;
         size_t parent_buffer_handle = 0;
@@ -150,7 +157,7 @@
         // should be null since we don't create any IPC objects
         CHECK(data == nullptr) << data;
     },
-    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to readNativeHandleNoDup";
         const native_handle_t* handle = nullptr;
         status_t status = p.readNativeHandleNoDup(&handle);
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h
new file mode 100644
index 0000000..a9a6197
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IBinder.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+/**
+ * Based on the random data in provider, construct an arbitrary number of
+ * Parcel objects and send them to the service in serial.
+ *
+ * Usage:
+ *
+ *   extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ *       FuzzedDataProvider provider = FuzzedDataProvider(data, size);
+ *       // can use provider here to create a service with different options
+ *       sp<IFoo> myService = sp<IFoo>::make(...);
+ *       fuzzService(myService, std::move(provider));
+ *   }
+ */
+void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider);
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h
new file mode 100644
index 0000000..f2b7823
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_parcel.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+/**
+ * Based on the random data in provider, construct an arbitrary number of
+ * Parcel objects and send them to the service in serial.
+ *
+ * Usage:
+ *
+ *   extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ *       FuzzedDataProvider provider = FuzzedDataProvider(data, size);
+ *       // can use provider here to create a service with different options
+ *       std::shared_ptr<IFoo> myService = ndk::SharedRefBase<IFoo>::make(...);
+ *       fuzzService(myService->asBinder().get(), std::move(provider));
+ *   }
+ */
+void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider);
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
index 0a083d7..843b6e3 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
@@ -16,12 +16,13 @@
 
 #pragma once
 
+#include <android-base/unique_fd.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
 namespace android {
 
-// ownership to callee, always valid or aborts
+// always valid or aborts
 // get a random FD for use in fuzzing, of a few different specific types
-int getRandomFd(FuzzedDataProvider* provider);
+base::unique_fd getRandomFd(FuzzedDataProvider* provider);
 
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index 749bf21..459fb12 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -19,13 +19,24 @@
 #include <binder/Parcel.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
+#include <functional>
+#include <vector>
+
 namespace android {
+
+struct RandomParcelOptions {
+    std::function<void(Parcel* p, FuzzedDataProvider& provider)> writeHeader;
+    std::vector<sp<IBinder>> extraBinders;
+    std::vector<base::unique_fd> extraFds;
+};
+
 /**
  * Fill parcel data, including some random binder objects and FDs
+ *
+ * p - the Parcel to fill
+ * provider - takes ownership and completely consumes provider
+ * writeHeader - optional function to write a specific header once the format of the parcel is
+ *     picked (for instance, to write an interface header)
  */
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
-/**
- * Fill parcel data, but don't fill any objects.
- */
-void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider);
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, const RandomParcelOptions& = {});
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
new file mode 100644
index 0000000..d5aa353
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 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 <fuzzbinder/libbinder_driver.h>
+
+#include <fuzzbinder/random_parcel.h>
+
+namespace android {
+
+void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) {
+    sp<IBinder> target;
+
+    RandomParcelOptions options{
+            .extraBinders = {binder},
+            .extraFds = {},
+    };
+
+    while (provider.remaining_bytes() > 0) {
+        uint32_t code = provider.ConsumeIntegral<uint32_t>();
+        uint32_t flags = provider.ConsumeIntegral<uint32_t>();
+        Parcel data;
+
+        sp<IBinder> target = options.extraBinders.at(
+                provider.ConsumeIntegralInRange<size_t>(0, options.extraBinders.size() - 1));
+        options.writeHeader = [&target](Parcel* p, FuzzedDataProvider& provider) {
+            // most code will be behind checks that the head of the Parcel
+            // is exactly this, so make it easier for fuzzers to reach this
+            if (provider.ConsumeBool()) {
+                p->writeInterfaceToken(target->getInterfaceDescriptor());
+            }
+        };
+
+        std::vector<uint8_t> subData = provider.ConsumeBytes<uint8_t>(
+                provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
+        fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), options);
+
+        Parcel reply;
+        (void)target->transact(code, data, &reply, flags);
+
+        // feed back in binders and fds that are returned from the service, so that
+        // we can fuzz those binders, and use the fds and binders to feed back into
+        // the binders
+        auto retBinders = reply.debugReadAllStrongBinders();
+        options.extraBinders.insert(options.extraBinders.end(), retBinders.begin(),
+                                    retBinders.end());
+        auto retFds = reply.debugReadAllFileDescriptors();
+        for (size_t i = 0; i < retFds.size(); i++) {
+            options.extraFds.push_back(base::unique_fd(dup(retFds[i])));
+        }
+    }
+}
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
new file mode 100644
index 0000000..462ef9a
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 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 <fuzzbinder/libbinder_ndk_driver.h>
+
+#include <fuzzbinder/libbinder_driver.h>
+#include <fuzzbinder/random_parcel.h>
+
+// libbinder_ndk doesn't export this header which breaks down its API for NDK
+// and APEX users, but we need access to it to fuzz.
+#include "../../ndk/ibinder_internal.h"
+
+namespace android {
+
+void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider) {
+    fuzzService(binder->getBinder(), std::move(provider));
+}
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp
index f435dae..180a177 100644
--- a/libs/binder/tests/parcel_fuzzer/main.cpp
+++ b/libs/binder/tests/parcel_fuzzer/main.cpp
@@ -83,22 +83,36 @@
     FUZZ_LOG() << "input: " << HexString(p.data(), p.dataSize());
     FUZZ_LOG() << "instructions: " << HexString(instructions.data(), instructions.size());
 
-    for (size_t i = 0; i + 1 < instructions.size(); i += 2) {
-        uint8_t a = instructions[i];
-        uint8_t readIdx = a % reads.size();
+    FuzzedDataProvider instructionsProvider(instructions.data(), instructions.size());
+    while (instructionsProvider.remaining_bytes() > 0) {
+        uint8_t idx = instructionsProvider.ConsumeIntegralInRange<uint8_t>(0, reads.size() - 1);
 
-        uint8_t b = instructions[i + 1];
+        FUZZ_LOG() << "Instruction " << idx << " avail: " << p.dataAvail()
+                   << " pos: " << p.dataPosition() << " cap: " << p.dataCapacity();
 
-        FUZZ_LOG() << "Instruction: " << (i / 2) + 1 << "/" << instructions.size() / 2
-                   << " cmd: " << static_cast<size_t>(a) << " (" << static_cast<size_t>(readIdx)
-                   << ") arg: " << static_cast<size_t>(b) << " size: " << p.dataSize()
-                   << " avail: " << p.dataAvail() << " pos: " << p.dataPosition()
-                   << " cap: " << p.dataCapacity();
-
-        reads[readIdx](p, b);
+        reads[idx](p, instructionsProvider);
     }
 }
 
+// Append two random parcels.
+template <typename P>
+void doAppendFuzz(const char* backend, FuzzedDataProvider&& provider) {
+    int32_t start = provider.ConsumeIntegral<int32_t>();
+    int32_t len = provider.ConsumeIntegral<int32_t>();
+
+    std::vector<uint8_t> bytes = provider.ConsumeBytes<uint8_t>(
+            provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
+
+    P p0, p1;
+    fillRandomParcel(&p0, FuzzedDataProvider(bytes.data(), bytes.size()));
+    fillRandomParcel(&p1, std::move(provider));
+
+    FUZZ_LOG() << "backend: " << backend;
+    FUZZ_LOG() << "start: " << start << " len: " << len;
+
+    p0.appendFrom(&p1, start, len);
+}
+
 void* NothingClass_onCreate(void* args) {
     return args;
 }
@@ -148,6 +162,12 @@
                 doReadFuzz<NdkParcelAdapter>("binder_ndk", BINDER_NDK_PARCEL_READ_FUNCTIONS,
                                              std::move(provider));
             },
+            [](FuzzedDataProvider&& provider) {
+                doAppendFuzz<::android::Parcel>("binder", std::move(provider));
+            },
+            [](FuzzedDataProvider&& provider) {
+                doAppendFuzz<NdkParcelAdapter>("binder_ndk", std::move(provider));
+            },
     };
 
     provider.PickValueInArray(fuzzBackend)(std::move(provider));
diff --git a/libs/binder/tests/parcel_fuzzer/parcel_fuzzer.h b/libs/binder/tests/parcel_fuzzer/parcel_fuzzer.h
index b68a8a9..765a93e 100644
--- a/libs/binder/tests/parcel_fuzzer/parcel_fuzzer.h
+++ b/libs/binder/tests/parcel_fuzzer/parcel_fuzzer.h
@@ -15,5 +15,9 @@
  */
 #pragma once
 
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <functional>
+
 template <typename P>
-using ParcelRead = std::function<void(const P& p, uint8_t data)>;
+using ParcelRead = std::function<void(const P& p, FuzzedDataProvider& provider)>;
diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
index cef6adb..ab0b7e3 100644
--- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
@@ -23,13 +23,13 @@
 
 namespace android {
 
-int getRandomFd(FuzzedDataProvider* provider) {
+base::unique_fd getRandomFd(FuzzedDataProvider* provider) {
     int fd = provider->PickValueInArray<std::function<int()>>({
             []() { return ashmem_create_region("binder test region", 1024); },
             []() { return open("/dev/null", O_RDWR); },
     })();
     CHECK(fd >= 0);
-    return fd;
+    return base::unique_fd(fd);
 }
 
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 8bf04cc..0204f5e 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -34,15 +34,30 @@
     String16 mDescriptor;
 };
 
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
+static void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) {
+    std::vector<uint8_t> data = provider.ConsumeBytes<uint8_t>(provider.remaining_bytes());
+    CHECK(OK == p->write(data.data(), data.size()));
+}
+
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider,
+                      const RandomParcelOptions& options) {
     if (provider.ConsumeBool()) {
         auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
         CHECK_EQ(OK, session->addNullDebuggingClient());
         p->markForRpc(session);
+
+        if (options.writeHeader) {
+            options.writeHeader(p, provider);
+        }
+
         fillRandomParcelData(p, std::move(provider));
         return;
     }
 
+    if (options.writeHeader) {
+        options.writeHeader(p, provider);
+    }
+
     while (provider.remaining_bytes() > 0) {
         auto fillFunc = provider.PickValueInArray<const std::function<void()>>({
                 // write data
@@ -54,8 +69,16 @@
                 },
                 // write FD
                 [&]() {
-                    int fd = getRandomFd(&provider);
-                    CHECK(OK == p->writeFileDescriptor(fd, true /*takeOwnership*/));
+                    if (options.extraFds.size() > 0 && provider.ConsumeBool()) {
+                        const base::unique_fd& fd = options.extraFds.at(
+                                provider.ConsumeIntegralInRange<size_t>(0,
+                                                                        options.extraFds.size() -
+                                                                                1));
+                        CHECK(OK == p->writeFileDescriptor(fd.get(), false /*takeOwnership*/));
+                    } else {
+                        base::unique_fd fd = getRandomFd(&provider);
+                        CHECK(OK == p->writeFileDescriptor(fd.release(), true /*takeOwnership*/));
+                    }
                 },
                 // write binder
                 [&]() {
@@ -74,7 +97,15 @@
                                 // candidate for checking usage of an actual BpBinder
                                 return IInterface::asBinder(defaultServiceManager());
                             },
-                            []() { return nullptr; },
+                            [&]() -> sp<IBinder> {
+                                if (options.extraBinders.size() > 0 && provider.ConsumeBool()) {
+                                    return options.extraBinders.at(
+                                            provider.ConsumeIntegralInRange<
+                                                    size_t>(0, options.extraBinders.size() - 1));
+                                } else {
+                                    return nullptr;
+                                }
+                            },
                     });
                     sp<IBinder> binder = makeFunc();
                     CHECK(OK == p->writeStrongBinder(binder));
@@ -85,9 +116,4 @@
     }
 }
 
-void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) {
-    std::vector<uint8_t> data = provider.ConsumeBytes<uint8_t>(provider.remaining_bytes());
-    CHECK(OK == p->write(data.data(), data.size()));
-}
-
 } // namespace android
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
index 741987f..5079431 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
@@ -30,7 +30,6 @@
 #include <utils/KeyedVector.h>
 #include <utils/Log.h>
 #include <utils/Mutex.h>
-#include <utils/threads.h>
 
 #include <stdio.h>
 
diff --git a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
index 4a0aeba..bf7c613 100644
--- a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
@@ -27,7 +27,6 @@
 #include <utils/KeyedVector.h>
 #include <utils/Log.h>
 #include <utils/Mutex.h>
-#include <utils/threads.h>
 
 namespace android {
 
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 7e9bb7d..d169043 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -300,11 +300,11 @@
     }
 
     std::vector<tis_val_t> vals(gNCpus);
-    time_key_t key = {.uid = uid};
     for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) {
-        key.bucket = i;
+        const time_key_t key = {.uid = uid, .bucket = i};
         if (findMapEntry(gTisMapFd, &key, vals.data())) {
-            if (errno != ENOENT || getFirstMapKey(gTisMapFd, &key)) return {};
+            time_key_t tmpKey;
+            if (errno != ENOENT || getFirstMapKey(gTisMapFd, &tmpKey)) return {};
             continue;
         }
 
@@ -412,10 +412,11 @@
     concurrent_time_t ret = {.active = std::vector<uint64_t>(gNCpus, 0)};
     for (const auto &cpuList : gPolicyCpus) ret.policy.emplace_back(cpuList.size(), 0);
     std::vector<concurrent_val_t> vals(gNCpus);
-    time_key_t key = {.uid = uid};
-    for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) {
+    for (uint32_t i = 0; i <= (gNCpus - 1) / CPUS_PER_ENTRY; ++i) {
+        const time_key_t key = {.uid = uid, .bucket = i};
         if (findMapEntry(gConcurrentMapFd, &key, vals.data())) {
-            if (errno != ENOENT || getFirstMapKey(gConcurrentMapFd, &key)) return {};
+            time_key_t tmpKey;
+            if (errno != ENOENT || getFirstMapKey(gConcurrentMapFd, &tmpKey)) return {};
             continue;
         }
         auto offset = key.bucket * CPUS_PER_ENTRY;
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 1513eca..45a6d47 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -31,6 +31,7 @@
 #include <android-base/unique_fd.h>
 #include <bpf/BpfMap.h>
 #include <cputimeinstate.h>
+#include <cutils/android_filesystem_config.h>
 #include <libbpf.h>
 
 namespace android {
@@ -219,6 +220,7 @@
         uint32_t totalFreqsCount = totalTimes.size();
         std::vector<uint64_t> allUidTimes(totalFreqsCount, 0);
         for (auto const &[uid, uidTimes]: *allUid) {
+            if (uid == AID_SDK_SANDBOX) continue;
             for (uint32_t freqIdx = 0; freqIdx < uidTimes[policyIdx].size(); ++freqIdx) {
                 allUidTimes[std::min(freqIdx, totalFreqsCount - 1)] += uidTimes[policyIdx][freqIdx];
             }
@@ -646,5 +648,55 @@
     }
 }
 
+void *forceSwitchWithUid(void *uidPtr) {
+    if (!uidPtr) return nullptr;
+    setuid(*(uint32_t *)uidPtr);
+
+    // Sleep briefly to trigger a context switch, ensuring we see at least one update.
+    struct timespec ts;
+    ts.tv_sec = 0;
+    ts.tv_nsec = 1000000;
+    nanosleep(&ts, NULL);
+    return nullptr;
+}
+
+TEST_F(TimeInStateTest, SdkSandboxUid) {
+    // Find an unused app UID and its corresponding SDK sandbox uid.
+    uint32_t appUid = AID_APP_START, sandboxUid;
+    {
+        auto times = getUidsCpuFreqTimes();
+        ASSERT_TRUE(times.has_value());
+        ASSERT_FALSE(times->empty());
+        for (const auto &kv : *times) {
+            if (kv.first > AID_APP_END) break;
+            appUid = std::max(appUid, kv.first);
+        }
+        appUid++;
+        sandboxUid = appUid + (AID_SDK_SANDBOX_PROCESS_START - AID_APP_START);
+    }
+
+    // Create a thread to run with the fake sandbox uid.
+    pthread_t thread;
+    ASSERT_EQ(pthread_create(&thread, NULL, &forceSwitchWithUid, &sandboxUid), 0);
+    pthread_join(thread, NULL);
+
+    // Confirm we recorded stats for appUid and AID_SDK_SANDBOX but not sandboxUid
+    auto allTimes = getUidsCpuFreqTimes();
+    ASSERT_TRUE(allTimes.has_value());
+    ASSERT_FALSE(allTimes->empty());
+    ASSERT_NE(allTimes->find(appUid), allTimes->end());
+    ASSERT_NE(allTimes->find(AID_SDK_SANDBOX), allTimes->end());
+    ASSERT_EQ(allTimes->find(sandboxUid), allTimes->end());
+
+    auto allConcurrentTimes = getUidsConcurrentTimes();
+    ASSERT_TRUE(allConcurrentTimes.has_value());
+    ASSERT_FALSE(allConcurrentTimes->empty());
+    ASSERT_NE(allConcurrentTimes->find(appUid), allConcurrentTimes->end());
+    ASSERT_NE(allConcurrentTimes->find(AID_SDK_SANDBOX), allConcurrentTimes->end());
+    ASSERT_EQ(allConcurrentTimes->find(sandboxUid), allConcurrentTimes->end());
+
+    ASSERT_TRUE(clearUidTimes(appUid));
+}
+
 } // namespace bpf
 } // namespace android
diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp
index acda402..09fbdea 100644
--- a/libs/dumputils/Android.bp
+++ b/libs/dumputils/Android.bp
@@ -26,6 +26,7 @@
 
     shared_libs: [
         "libbase",
+        "libbinder",
         "libhidlbase",
         "liblog",
         "libutils",
@@ -33,7 +34,10 @@
 
     srcs: ["dump_utils.cpp"],
 
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 
     export_include_dirs: [
         "include",
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 29c788b..e543917 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -20,6 +20,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
+#include <binder/IServiceManager.h>
 #include <dumputils/dump_utils.h>
 #include <log/log.h>
 
@@ -52,8 +53,8 @@
         NULL,
 };
 
-/* list of hal interface to dump containing process during native dumps */
-static const char* hal_interfaces_to_dump[] {
+/* list of hidl hal interface to dump containing process during native dumps */
+static const char* hidl_hal_interfaces_to_dump[] {
         "android.hardware.audio@4.0::IDevicesFactory",
         "android.hardware.audio@5.0::IDevicesFactory",
         "android.hardware.audio@6.0::IDevicesFactory",
@@ -82,6 +83,23 @@
         NULL,
 };
 
+/* list of hal interface to dump containing process during native dumps */
+static const std::vector<std::string> aidl_interfaces_to_dump {
+        "android.hardware.automotive.audiocontrol.IAudioControl",
+        "android.hardware.automotive.evs.IEvsEnumerator",
+        "android.hardware.biometrics.face.IBiometricsFace",
+        "android.hardware.biometrics.fingerprint.IBiometricsFingerprint",
+        "android.hardware.camera.provider.ICameraProvider",
+        "android.hardware.drm.IDrmFactory",
+        "android.hardware.graphics.allocator.IAllocator",
+        "android.hardware.graphics.composer3.IComposer",
+        "android.hardware.health.IHealth",
+        "android.hardware.neuralnetworks.IDevice",
+        "android.hardware.power.IPower",
+        "android.hardware.power.stats.IPowerStats",
+        "android.hardware.sensors.ISensors",
+};
+
 /* list of extra hal interfaces to dump containing process during native dumps */
 // This is filled when dumpstate is called.
 static std::set<const std::string> extra_hal_interfaces_to_dump;
@@ -104,7 +122,7 @@
 
 // check if interface is included in either default hal list or extra hal list
 bool should_dump_hal_interface(const std::string& interface) {
-    for (const char** i = hal_interfaces_to_dump; *i; i++) {
+    for (const char** i = hidl_hal_interfaces_to_dump; *i; i++) {
         if (interface == *i) {
             return true;
         }
@@ -130,14 +148,26 @@
     return false;
 }
 
-std::set<int> get_interesting_hal_pids() {
+static void get_interesting_aidl_pids(std::set<int> &pids) {
+    using ServiceDebugInfo = android::IServiceManager::ServiceDebugInfo;
+    auto sm = android::defaultServiceManager();
+    std::vector<ServiceDebugInfo> serviceDebugInfos = sm->getServiceDebugInfo();
+    for (const auto & serviceDebugInfo : serviceDebugInfos) {
+        for (const auto &aidl_prefix : aidl_interfaces_to_dump) {
+            // Check for prefix match with aidl interface to dump
+            if (serviceDebugInfo.name.rfind(aidl_prefix, 0) == 0) {
+                pids.insert(serviceDebugInfo.pid);
+            }
+        }
+    }
+}
+
+static void get_interesting_hidl_pids(std::set<int> &pids) {
     using android::hidl::manager::V1_0::IServiceManager;
     using android::sp;
     using android::hardware::Return;
 
     sp<IServiceManager> manager = IServiceManager::getService();
-    std::set<int> pids;
-
     read_extra_hals_to_dump_from_property();
 
     Return<void> ret = manager->debugDump([&](auto& hals) {
@@ -146,11 +176,9 @@
                 continue;
             }
 
-            if (!should_dump_hal_interface(info.interfaceName)) {
-                continue;
+            if (should_dump_hal_interface(info.interfaceName)) {
+                pids.insert(info.pid);
             }
-
-            pids.insert(info.pid);
         }
     });
 
@@ -158,7 +186,14 @@
         ALOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
     }
 
-    return pids; // whether it was okay or not
+    return;
+}
+
+std::set<int> get_interesting_pids() {
+    std::set<int> interesting_pids;
+    get_interesting_hidl_pids(interesting_pids);
+    get_interesting_aidl_pids(interesting_pids);
+    return interesting_pids;
 }
 
 bool IsZygote(int pid) {
diff --git a/libs/dumputils/include/dumputils/dump_utils.h b/libs/dumputils/include/dumputils/dump_utils.h
index 25f7127..7c5329d 100644
--- a/libs/dumputils/include/dumputils/dump_utils.h
+++ b/libs/dumputils/include/dumputils/dump_utils.h
@@ -21,7 +21,7 @@
 
 bool should_dump_native_traces(const char* path);
 
-std::set<int> get_interesting_hal_pids();
+std::set<int> get_interesting_pids();
 
 bool IsZygote(int pid);
 
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 61e4a98..6c6d7f3 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -94,4 +94,8 @@
     return INVALID_OPERATION;
 }
 
+std::vector<IServiceManager::ServiceDebugInfo> ServiceManager::getServiceDebugInfo() {
+    std::vector<IServiceManager::ServiceDebugInfo> ret;
+    return ret;
+}
 }  // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index 6d6e008..e0af5d4 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -20,6 +20,7 @@
 
 #include <map>
 #include <optional>
+#include <vector>
 
 namespace android {
 
@@ -58,6 +59,9 @@
 
     status_t unregisterForNotifications(const String16& name,
                                         const sp<LocalRegistrationCallback>& callback) override;
+
+    std::vector<IServiceManager::ServiceDebugInfo> getServiceDebugInfo() override;
+
 private:
     std::map<String16, sp<IBinder>> mNameToService;
 };
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index 81a529d..e2f072a 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -196,35 +196,6 @@
 status_t validateMetadataType(InputHidlVec* input, const MetadataType& expectedMetadataType);
 
 /**
- * Private helper functions
- */
-template <class T>
-status_t encodeInteger(const T& input, OutputHidlVec* output) {
-    static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
-                  std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
-                  std::is_same<T, float>::value || std::is_same<T, double>::value);
-    if (!output) {
-        return BAD_VALUE;
-    }
-
-    const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
-    return output->encode(tmp, sizeof(input));
-}
-
-template <class T>
-status_t decodeInteger(InputHidlVec* input, T* output) {
-    static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
-                  std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
-                  std::is_same<T, float>::value || std::is_same<T, double>::value);
-    if (!output) {
-        return BAD_VALUE;
-    }
-
-    uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
-    return input->decode(tmp, sizeof(*output));
-}
-
-/**
  * encode/encodeMetadata are the main encoding functions. They take in T and uses the encodeHelper
  * function to turn T into the hidl_vec byte stream.
  *
@@ -280,45 +251,10 @@
 template <class T>
 status_t encodeOptionalMetadata(const MetadataType& metadataType, const std::optional<T>& input,
                         hidl_vec<uint8_t>* output, EncodeHelper<T> encodeHelper) {
-    OutputHidlVec outputHidlVec{output};
-
-    status_t err = encodeMetadataType(metadataType, &outputHidlVec);
-    if (err) {
-        return err;
+    if (!input) {
+        return NO_ERROR;
     }
-
-    err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
-    if (err) {
-        return err;
-    }
-
-    if (input) {
-        err = encodeHelper(*input, &outputHidlVec);
-        if (err) {
-            return err;
-        }
-    }
-
-    err = outputHidlVec.resize();
-    if (err) {
-        return err;
-    }
-
-    err = encodeMetadataType(metadataType, &outputHidlVec);
-    if (err) {
-        return err;
-    }
-
-    err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
-    if (err) {
-        return err;
-    }
-
-    if (input) {
-        return encodeHelper(*input, &outputHidlVec);
-    }
-
-    return NO_ERROR;
+    return encodeMetadata(metadataType, *input, output, encodeHelper);
 }
 
 /**
@@ -379,36 +315,45 @@
     if (!output) {
         return BAD_VALUE;
     }
-
-    InputHidlVec inputHidlVec{&input};
-
-    status_t err = validateMetadataType(&inputHidlVec, metadataType);
-    if (err) {
-        return err;
+    if (input.size() <= 0) {
+        output->reset();
+        return NO_ERROR;
     }
-
-    uint32_t present = 0;
-    err = decodeInteger<uint32_t>(&inputHidlVec, &present);
-    if (err) {
-        return err;
-    }
-
-    if (present) {
-        T tmp;
-        err = decodeHelper(&inputHidlVec, &tmp);
-        if (err) {
-            return err;
-        }
-
+    T tmp;
+    status_t err = decodeMetadata(metadataType, input, &tmp, decodeHelper);
+    if (!err) {
         *output = tmp;
     }
+    return err;
+}
 
-    err = inputHidlVec.hasRemainingData();
-    if (err) {
+/**
+ * Private helper functions
+ */
+template <class T>
+status_t encodeInteger(const T& input, OutputHidlVec* output) {
+    static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+                  std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+                  std::is_same<T, float>::value || std::is_same<T, double>::value);
+    if (!output) {
         return BAD_VALUE;
     }
 
-    return NO_ERROR;
+    const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
+    return output->encode(tmp, sizeof(input));
+}
+
+template <class T>
+status_t decodeInteger(InputHidlVec* input, T* output) {
+    static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+                  std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+                  std::is_same<T, float>::value || std::is_same<T, double>::value);
+    if (!output) {
+        return BAD_VALUE;
+    }
+
+    uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
+    return input->decode(tmp, sizeof(*output));
 }
 
 status_t encodeString(const std::string& input, OutputHidlVec* output) {
diff --git a/libs/graphicsenv/OWNERS b/libs/graphicsenv/OWNERS
index 8c28464..347c4e0 100644
--- a/libs/graphicsenv/OWNERS
+++ b/libs/graphicsenv/OWNERS
@@ -1,4 +1,10 @@
+abdolrashidi@google.com
+cclao@google.com
 chrisforbes@google.com
 cnorthrop@google.com
+ianelliott@google.com
+lfy@google.com
 lpy@google.com
-timvp@google.com
+romanl@google.com
+vantablack@google.com
+yuxinhu@google.com
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index bd9abc1..6641b77 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -91,7 +91,7 @@
     ],
 
     aidl: {
-        export_aidl_headers: true
+        export_aidl_headers: true,
     },
 
     include_dirs: [
@@ -308,7 +308,6 @@
 cc_defaults {
     name: "libgui_bufferqueue-defaults",
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 77a883b..bf275a5 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -391,6 +391,71 @@
     }
 }
 
+void layer_state_t::sanitize(int32_t permissions) {
+    // 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 its 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 arbitrary rotation is used in limited use cases, for instance:
+    // - WindowManager only uses rotation in one case, which is on a top level layer in which
+    //   cropping is not an issue.
+    // - Launcher, as a privileged app, uses this to transition an application to PiP
+    //   (picture-in-picture) mode.
+    //
+    // 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 nor ROTATE_SURFACE_FLINGER
+    // (a.k.a. everyone except WindowManager / tests / Launcher) from setting non rectangle
+    // preserving transformations.
+    if (what & eMatrixChanged) {
+        if (!(permissions & Permission::ROTATE_SURFACE_FLINGER)) {
+            ui::Transform t;
+            t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+            if (!t.preserveRects()) {
+                what &= ~eMatrixChanged;
+                ALOGE("Stripped non rect preserving matrix in sanitize");
+            }
+        }
+    }
+
+    if (what & layer_state_t::eInputInfoChanged) {
+        if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+            what &= ~eInputInfoChanged;
+            ALOGE("Stripped attempt to set eInputInfoChanged in sanitize");
+        }
+    }
+    if (what & layer_state_t::eTrustedOverlayChanged) {
+        if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+            what &= ~eTrustedOverlayChanged;
+            ALOGE("Stripped attempt to set eTrustedOverlay in sanitize");
+        }
+    }
+    if (what & layer_state_t::eDropInputModeChanged) {
+        if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+            what &= ~eDropInputModeChanged;
+            ALOGE("Stripped attempt to set eDropInputModeChanged in sanitize");
+        }
+    }
+    if (what & layer_state_t::eFrameRateSelectionPriority) {
+        if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+            what &= ~eFrameRateSelectionPriority;
+            ALOGE("Stripped attempt to set eFrameRateSelectionPriority in sanitize");
+        }
+    }
+    if (what & layer_state_t::eFrameRateChanged) {
+        if (!ValidateFrameRate(frameRate, frameRateCompatibility,
+                               changeFrameRateStrategy,
+                               "layer_state_t::sanitize",
+                               permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+            what &= ~eFrameRateChanged; // logged in ValidateFrameRate
+        }
+    }
+}
+
 void layer_state_t::merge(const layer_state_t& other) {
     if (other.what & ePositionChanged) {
         what |= ePositionChanged;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 725ea65..4bcc9d5 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -551,6 +551,13 @@
     mListenerCallbacks = other.mListenerCallbacks;
 }
 
+void SurfaceComposerClient::Transaction::sanitize() {
+    for (auto & [handle, composerState] : mComposerStates) {
+        composerState.state.sanitize(0 /* permissionMask */);
+    }
+    mInputWindowCommands.clear();
+}
+
 std::unique_ptr<SurfaceComposerClient::Transaction>
 SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) {
     auto transaction = std::make_unique<Transaction>();
@@ -635,7 +642,6 @@
         if (composerState.read(*parcel) == BAD_VALUE) {
             return BAD_VALUE;
         }
-
         composerStates[surfaceControlHandle] = composerState;
     }
 
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 03e4aac..2a8d30d 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -61,6 +61,12 @@
  * Used to communicate layer information between SurfaceFlinger and its clients.
  */
 struct layer_state_t {
+    enum Permission {
+        ACCESS_SURFACE_FLINGER = 0x1,
+        ROTATE_SURFACE_FLINGER = 0x2,
+        INTERNAL_SYSTEM_WINDOW = 0x4,
+    };
+
     enum {
         eLayerHidden = 0x01,         // SURFACE_HIDDEN in SurfaceControl.java
         eLayerOpaque = 0x02,         // SURFACE_OPAQUE
@@ -128,6 +134,7 @@
     status_t read(const Parcel& input);
     bool hasBufferChanges() const;
     bool hasValidBuffer() const;
+    void sanitize(int32_t permissions);
 
     struct matrix22_t {
         float dsdx{0};
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0d1d1a3..76b6d44 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -590,6 +590,14 @@
         void setAnimationTransaction();
         void setEarlyWakeupStart();
         void setEarlyWakeupEnd();
+
+        /**
+         * Strip the transaction of all permissioned requests, required when
+         * accepting transactions across process boundaries.
+         *
+         * TODO (b/213644870): Remove all permissioned things from Transaction
+         */
+        void sanitize();
     };
 
     status_t clearLayerFrameStats(const sp<IBinder>& token) const;
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 3d26c3d..abdbaa5 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -15,7 +15,6 @@
     name: "libgui_test",
     test_suites: ["device-tests"],
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -62,7 +61,7 @@
         "libinput",
         "libui",
         "libutils",
-        "libnativewindow"
+        "libnativewindow",
     ],
 
     header_libs: ["libsurfaceflinger_headers"],
@@ -73,7 +72,6 @@
     name: "libgui_multilib_test",
     test_suites: ["device-tests"],
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -100,7 +98,6 @@
     name: "SurfaceParcelable_test",
     test_suites: ["device-tests"],
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -117,7 +114,7 @@
         "libgui",
         "libui",
         "libutils",
-        "libbufferhubqueue",  // TODO(b/70046255): Remove these once BufferHub is integrated into libgui.
+        "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui.
         "libpdx_default_transport",
     ],
 
@@ -129,7 +126,6 @@
 cc_test {
     name: "SamplingDemo",
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -146,5 +142,5 @@
         "liblog",
         "libui",
         "libutils",
-    ]
+    ],
 }
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index e73c3b8..cdcdaab 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -55,8 +55,6 @@
         "VirtualKeyMap.cpp",
     ],
 
-    clang: true,
-
     header_libs: ["jni_headers"],
     export_header_lib_headers: ["jni_headers"],
 
@@ -64,6 +62,7 @@
         "libbase",
         "liblog",
         "libcutils",
+        "libvintf",
     ],
 
     static_libs: [
@@ -113,7 +112,7 @@
                 "frameworks/native/libs/arect/include",
             ],
         },
-        linux_glibc: {
+        host_linux: {
             srcs: [
                 "InputTransport.cpp",
                 "android/os/IInputConstants.aidl",
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 1aec477..18cd474 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -53,33 +53,39 @@
 }
 
 std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
-        const InputDeviceIdentifier& deviceIdentifier,
-        InputDeviceConfigurationFileType type) {
+        const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type,
+        const char* suffix) {
     if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
         if (deviceIdentifier.version != 0) {
             // Try vendor product version.
-            std::string versionPath = getInputDeviceConfigurationFilePathByName(
-                    StringPrintf("Vendor_%04x_Product_%04x_Version_%04x",
-                            deviceIdentifier.vendor, deviceIdentifier.product,
-                            deviceIdentifier.version),
-                    type);
+            std::string versionPath =
+                    getInputDeviceConfigurationFilePathByName(StringPrintf("Vendor_%04x_Product_%"
+                                                                           "04x_Version_%04x%s",
+                                                                           deviceIdentifier.vendor,
+                                                                           deviceIdentifier.product,
+                                                                           deviceIdentifier.version,
+                                                                           suffix),
+                                                              type);
             if (!versionPath.empty()) {
                 return versionPath;
             }
         }
 
         // Try vendor product.
-        std::string productPath = getInputDeviceConfigurationFilePathByName(
-                StringPrintf("Vendor_%04x_Product_%04x",
-                        deviceIdentifier.vendor, deviceIdentifier.product),
-                type);
+        std::string productPath =
+                getInputDeviceConfigurationFilePathByName(StringPrintf("Vendor_%04x_Product_%04x%s",
+                                                                       deviceIdentifier.vendor,
+                                                                       deviceIdentifier.product,
+                                                                       suffix),
+                                                          type);
         if (!productPath.empty()) {
             return productPath;
         }
     }
 
     // Try device name.
-    return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName(), type);
+    return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName() + suffix,
+                                                     type);
 }
 
 std::string getInputDeviceConfigurationFilePathByName(
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index c365ab0..84a8ab4 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -23,20 +23,33 @@
 #include <input/InputEventLabels.h>
 #include <input/KeyLayoutMap.h>
 #include <input/Keyboard.h>
+#include <log/log.h>
 #include <utils/Errors.h>
-#include <utils/Log.h>
 #include <utils/Timers.h>
 #include <utils/Tokenizer.h>
+#include <vintf/RuntimeInfo.h>
+#include <vintf/VintfObject.h>
 
-// Enables debug output for the parser.
-#define DEBUG_PARSER 0
+#include <cstdlib>
+#include <string_view>
+#include <unordered_map>
+
+/**
+ * Log debug output for the parser.
+ * Enable this via "adb shell setprop log.tag.KeyLayoutMapParser DEBUG" (requires restart)
+ */
+const bool DEBUG_PARSER =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Parser", ANDROID_LOG_INFO);
 
 // Enables debug output for parser performance.
 #define DEBUG_PARSER_PERFORMANCE 0
 
-// Enables debug output for mapping.
-#define DEBUG_MAPPING 0
-
+/**
+ * Log debug output for mapping.
+ * Enable this via "adb shell setprop log.tag.KeyLayoutMapMapping DEBUG" (requires restart)
+ */
+const bool DEBUG_MAPPING =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Mapping", ANDROID_LOG_INFO);
 
 namespace android {
 
@@ -62,6 +75,29 @@
          {SENSOR_ENTRY(InputDeviceSensorType::GYROSCOPE_UNCALIBRATED)},
          {SENSOR_ENTRY(InputDeviceSensorType::SIGNIFICANT_MOTION)}};
 
+bool kernelConfigsArePresent(const std::set<std::string>& configs) {
+    std::shared_ptr<const android::vintf::RuntimeInfo> runtimeInfo =
+            android::vintf::VintfObject::GetInstance()->getRuntimeInfo(
+                    vintf::RuntimeInfo::FetchFlag::CONFIG_GZ);
+    LOG_ALWAYS_FATAL_IF(runtimeInfo == nullptr, "Kernel configs could not be fetched");
+
+    const std::map<std::string, std::string>& kernelConfigs = runtimeInfo->kernelConfigs();
+    for (const std::string& requiredConfig : configs) {
+        const auto configIt = kernelConfigs.find(requiredConfig);
+        if (configIt == kernelConfigs.end()) {
+            ALOGI("Required kernel config %s is not found", requiredConfig.c_str());
+            return false;
+        }
+        const std::string& option = configIt->second;
+        if (option != "y" && option != "m") {
+            ALOGI("Required kernel config %s has option %s", requiredConfig.c_str(),
+                  option.c_str());
+            return false;
+        }
+    }
+    return true;
+}
+
 // --- KeyLayoutMap ---
 
 KeyLayoutMap::KeyLayoutMap() {
@@ -72,32 +108,34 @@
 
 base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::loadContents(const std::string& filename,
                                                                        const char* contents) {
-    Tokenizer* tokenizer;
-    status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
-    if (status) {
-        ALOGE("Error %d opening key layout map.", status);
-        return Errorf("Error {} opening key layout map file {}.", status, filename.c_str());
-    }
-    std::unique_ptr<Tokenizer> t(tokenizer);
-    auto ret = load(t.get());
-    if (ret.ok()) {
-        (*ret)->mLoadFileName = filename;
-    }
-    return ret;
+    return load(filename, contents);
 }
 
-base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(const std::string& filename) {
+base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(const std::string& filename,
+                                                               const char* contents) {
     Tokenizer* tokenizer;
-    status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
+    status_t status;
+    if (contents == nullptr) {
+        status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
+    } else {
+        status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
+    }
     if (status) {
         ALOGE("Error %d opening key layout map file %s.", status, filename.c_str());
         return Errorf("Error {} opening key layout map file {}.", status, filename.c_str());
     }
     std::unique_ptr<Tokenizer> t(tokenizer);
     auto ret = load(t.get());
-    if (ret.ok()) {
-        (*ret)->mLoadFileName = filename;
+    if (!ret.ok()) {
+        return ret;
     }
+    const std::shared_ptr<KeyLayoutMap>& map = *ret;
+    LOG_ALWAYS_FATAL_IF(map == nullptr, "Returned map should not be null if there's no error");
+    if (!kernelConfigsArePresent(map->mRequiredKernelConfigs)) {
+        ALOGI("Not loading %s because the required kernel configs are not set", filename.c_str());
+        return Errorf("Missing kernel config");
+    }
+    map->mLoadFileName = filename;
     return ret;
 }
 
@@ -130,9 +168,8 @@
         int32_t* outKeyCode, uint32_t* outFlags) const {
     const Key* key = getKey(scanCode, usageCode);
     if (!key) {
-#if DEBUG_MAPPING
-        ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
-#endif
+        ALOGD_IF(DEBUG_MAPPING, "mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode,
+                 usageCode);
         *outKeyCode = AKEYCODE_UNKNOWN;
         *outFlags = 0;
         return NAME_NOT_FOUND;
@@ -141,10 +178,9 @@
     *outKeyCode = key->keyCode;
     *outFlags = key->flags;
 
-#if DEBUG_MAPPING
-    ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.",
-            scanCode, usageCode, *outKeyCode, *outFlags);
-#endif
+    ALOGD_IF(DEBUG_MAPPING,
+             "mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.",
+             scanCode, usageCode, *outKeyCode, *outFlags);
     return NO_ERROR;
 }
 
@@ -152,103 +188,79 @@
 base::Result<std::pair<InputDeviceSensorType, int32_t>> KeyLayoutMap::mapSensor(int32_t absCode) {
     auto it = mSensorsByAbsCode.find(absCode);
     if (it == mSensorsByAbsCode.end()) {
-#if DEBUG_MAPPING
-        ALOGD("mapSensor: absCode=%d, ~ Failed.", absCode);
-#endif
+        ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, ~ Failed.", absCode);
         return Errorf("Can't find abs code {}.", absCode);
     }
     const Sensor& sensor = it->second;
-
-#if DEBUG_MAPPING
-    ALOGD("mapSensor: absCode=%d, sensorType=0x%0x, sensorDataIndex=0x%x.", absCode,
-          NamedEnum::string(sensor.sensorType), sensor.sensorDataIndex);
-#endif
+    ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, sensorType=%s, sensorDataIndex=0x%x.", absCode,
+             NamedEnum::string(sensor.sensorType).c_str(), sensor.sensorDataIndex);
     return std::make_pair(sensor.sensorType, sensor.sensorDataIndex);
 }
 
 const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
     if (usageCode) {
-        ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
-        if (index >= 0) {
-            return &mKeysByUsageCode.valueAt(index);
+        auto it = mKeysByUsageCode.find(usageCode);
+        if (it != mKeysByUsageCode.end()) {
+            return &it->second;
         }
     }
     if (scanCode) {
-        ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
-        if (index >= 0) {
-            return &mKeysByScanCode.valueAt(index);
+        auto it = mKeysByScanCode.find(scanCode);
+        if (it != mKeysByScanCode.end()) {
+            return &it->second;
         }
     }
     return nullptr;
 }
 
-status_t KeyLayoutMap::findScanCodesForKey(
-        int32_t keyCode, std::vector<int32_t>* outScanCodes) const {
-    const size_t N = mKeysByScanCode.size();
-    for (size_t i=0; i<N; i++) {
-        if (mKeysByScanCode.valueAt(i).keyCode == keyCode) {
-            outScanCodes->push_back(mKeysByScanCode.keyAt(i));
+std::vector<int32_t> KeyLayoutMap::findScanCodesForKey(int32_t keyCode) const {
+    std::vector<int32_t> scanCodes;
+    for (const auto& [scanCode, key] : mKeysByScanCode) {
+        if (keyCode == key.keyCode) {
+            scanCodes.push_back(scanCode);
         }
     }
-    return NO_ERROR;
+    return scanCodes;
 }
 
-status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
-    ssize_t index = mAxes.indexOfKey(scanCode);
-    if (index < 0) {
-#if DEBUG_MAPPING
-        ALOGD("mapAxis: scanCode=%d ~ Failed.", scanCode);
-#endif
-        return NAME_NOT_FOUND;
+std::optional<AxisInfo> KeyLayoutMap::mapAxis(int32_t scanCode) const {
+    auto it = mAxes.find(scanCode);
+    if (it == mAxes.end()) {
+        ALOGD_IF(DEBUG_MAPPING, "mapAxis: scanCode=%d ~ Failed.", scanCode);
+        return std::nullopt;
     }
 
-    *outAxisInfo = mAxes.valueAt(index);
-
-#if DEBUG_MAPPING
-    ALOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
-            "splitValue=%d, flatOverride=%d.",
-            scanCode,
-            outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis,
-            outAxisInfo->splitValue, outAxisInfo->flatOverride);
-#endif
-    return NO_ERROR;
+    const AxisInfo& axisInfo = it->second;
+    ALOGD_IF(DEBUG_MAPPING,
+             "mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
+             "splitValue=%d, flatOverride=%d.",
+             scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
+             axisInfo.flatOverride);
+    return axisInfo;
 }
 
-status_t KeyLayoutMap::findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const {
-    const size_t N = mLedsByScanCode.size();
-    for (size_t i = 0; i < N; i++) {
-        if (mLedsByScanCode.valueAt(i).ledCode == ledCode) {
-            *outScanCode = mLedsByScanCode.keyAt(i);
-#if DEBUG_MAPPING
-            ALOGD("findScanCodeForLed: ledCode=%d, scanCode=%d.", ledCode, *outScanCode);
-#endif
-            return NO_ERROR;
+std::optional<int32_t> KeyLayoutMap::findScanCodeForLed(int32_t ledCode) const {
+    for (const auto& [scanCode, led] : mLedsByScanCode) {
+        if (led.ledCode == ledCode) {
+            ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, scanCode=%d.", __func__, ledCode, scanCode);
+            return scanCode;
         }
     }
-#if DEBUG_MAPPING
-            ALOGD("findScanCodeForLed: ledCode=%d ~ Not found.", ledCode);
-#endif
-    return NAME_NOT_FOUND;
+    ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
+    return std::nullopt;
 }
 
-status_t KeyLayoutMap::findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const {
-    const size_t N = mLedsByUsageCode.size();
-    for (size_t i = 0; i < N; i++) {
-        if (mLedsByUsageCode.valueAt(i).ledCode == ledCode) {
-            *outUsageCode = mLedsByUsageCode.keyAt(i);
-#if DEBUG_MAPPING
-            ALOGD("findUsageForLed: ledCode=%d, usage=%x.", ledCode, *outUsageCode);
-#endif
-            return NO_ERROR;
+std::optional<int32_t> KeyLayoutMap::findUsageCodeForLed(int32_t ledCode) const {
+    for (const auto& [usageCode, led] : mLedsByUsageCode) {
+        if (led.ledCode == ledCode) {
+            ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, usage=%x.", __func__, ledCode, usageCode);
+            return usageCode;
         }
     }
-#if DEBUG_MAPPING
-            ALOGD("findUsageForLed: ledCode=%d ~ Not found.", ledCode);
-#endif
-    return NAME_NOT_FOUND;
+    ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
+    return std::nullopt;
 }
 
-
 // --- KeyLayoutMap::Parser ---
 
 KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
@@ -260,10 +272,8 @@
 
 status_t KeyLayoutMap::Parser::parse() {
     while (!mTokenizer->isEof()) {
-#if DEBUG_PARSER
-        ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
-                mTokenizer->peekRemainderOfLine().string());
-#endif
+        ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().string(),
+                 mTokenizer->peekRemainderOfLine().string());
 
         mTokenizer->skipDelimiters(WHITESPACE);
 
@@ -285,6 +295,10 @@
                 mTokenizer->skipDelimiters(WHITESPACE);
                 status_t status = parseSensor();
                 if (status) return status;
+            } else if (keywordToken == "requires_kernel_config") {
+                mTokenizer->skipDelimiters(WHITESPACE);
+                status_t status = parseRequiredKernelConfig();
+                if (status) return status;
             } else {
                 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
                         keywordToken.string());
@@ -321,8 +335,9 @@
                 mapUsage ? "usage" : "scan code", codeToken.string());
         return BAD_VALUE;
     }
-    KeyedVector<int32_t, Key>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
-    if (map.indexOfKey(code) >= 0) {
+    std::unordered_map<int32_t, Key>& map =
+            mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
+    if (map.find(code) != map.end()) {
         ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
                 mapUsage ? "usage" : "scan code", codeToken.string());
         return BAD_VALUE;
@@ -357,14 +372,13 @@
         flags |= flag;
     }
 
-#if DEBUG_PARSER
-    ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
-            mapUsage ? "usage" : "scan code", code, keyCode, flags);
-#endif
+    ALOGD_IF(DEBUG_PARSER, "Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
+             mapUsage ? "usage" : "scan code", code, keyCode, flags);
+
     Key key;
     key.keyCode = keyCode;
     key.flags = flags;
-    map.add(code, key);
+    map.insert({code, key});
     return NO_ERROR;
 }
 
@@ -377,7 +391,7 @@
                 scanCodeToken.string());
         return BAD_VALUE;
     }
-    if (mMap->mAxes.indexOfKey(scanCode) >= 0) {
+    if (mMap->mAxes.find(scanCode) != mMap->mAxes.end()) {
         ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
                 scanCodeToken.string());
         return BAD_VALUE;
@@ -458,14 +472,12 @@
         }
     }
 
-#if DEBUG_PARSER
-    ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
-            "splitValue=%d, flatOverride=%d.",
-            scanCode,
-            axisInfo.mode, axisInfo.axis, axisInfo.highAxis,
-            axisInfo.splitValue, axisInfo.flatOverride);
-#endif
-    mMap->mAxes.add(scanCode, axisInfo);
+    ALOGD_IF(DEBUG_PARSER,
+             "Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
+             "splitValue=%d, flatOverride=%d.",
+             scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
+             axisInfo.flatOverride);
+    mMap->mAxes.insert({scanCode, axisInfo});
     return NO_ERROR;
 }
 
@@ -485,8 +497,9 @@
         return BAD_VALUE;
     }
 
-    KeyedVector<int32_t, Led>& map = mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode;
-    if (map.indexOfKey(code) >= 0) {
+    std::unordered_map<int32_t, Led>& map =
+            mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode;
+    if (map.find(code) != map.end()) {
         ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(),
                 mapUsage ? "usage" : "scan code", codeToken.string());
         return BAD_VALUE;
@@ -501,14 +514,12 @@
         return BAD_VALUE;
     }
 
-#if DEBUG_PARSER
-    ALOGD("Parsed led %s: code=%d, ledCode=%d.",
-            mapUsage ? "usage" : "scan code", code, ledCode);
-#endif
+    ALOGD_IF(DEBUG_PARSER, "Parsed led %s: code=%d, ledCode=%d.", mapUsage ? "usage" : "scan code",
+             code, ledCode);
 
     Led led;
     led.ledCode = ledCode;
-    map.add(code, led);
+    map.insert({code, led});
     return NO_ERROR;
 }
 
@@ -580,10 +591,8 @@
     }
     int32_t sensorDataIndex = indexOpt.value();
 
-#if DEBUG_PARSER
-    ALOGD("Parsed sensor: abs code=%d, sensorType=%d, sensorDataIndex=%d.", code,
-          NamedEnum::string(sensorType).c_str(), sensorDataIndex);
-#endif
+    ALOGD_IF(DEBUG_PARSER, "Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", code,
+             NamedEnum::string(sensorType).c_str(), sensorDataIndex);
 
     Sensor sensor;
     sensor.sensorType = sensorType;
@@ -591,4 +600,23 @@
     map.emplace(code, sensor);
     return NO_ERROR;
 }
+
+// Parse the name of a required kernel config.
+// The layout won't be used if the specified kernel config is not present
+// Examples:
+// requires_kernel_config CONFIG_HID_PLAYSTATION
+status_t KeyLayoutMap::Parser::parseRequiredKernelConfig() {
+    String8 codeToken = mTokenizer->nextToken(WHITESPACE);
+    std::string configName = codeToken.string();
+
+    const auto result = mMap->mRequiredKernelConfigs.emplace(configName);
+    if (!result.second) {
+        ALOGE("%s: Duplicate entry for required kernel config %s.",
+              mTokenizer->getLocation().string(), configName.c_str());
+        return BAD_VALUE;
+    }
+
+    ALOGD_IF(DEBUG_PARSER, "Parsed required kernel config: name=%s", configName.c_str());
+    return NO_ERROR;
+}
 };
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index f0895b3..c3f5151 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -20,16 +20,23 @@
 #include <unistd.h>
 #include <limits.h>
 
-#include <input/Keyboard.h>
-#include <input/InputEventLabels.h>
-#include <input/KeyLayoutMap.h>
-#include <input/KeyCharacterMap.h>
 #include <input/InputDevice.h>
+#include <input/InputEventLabels.h>
+#include <input/KeyCharacterMap.h>
+#include <input/KeyLayoutMap.h>
+#include <input/Keyboard.h>
+#include <log/log.h>
 #include <utils/Errors.h>
-#include <utils/Log.h>
 
 namespace android {
 
+static std::string getPath(const InputDeviceIdentifier& deviceIdentifier, const std::string& name,
+                           InputDeviceConfigurationFileType type) {
+    return name.empty()
+            ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
+            : getInputDeviceConfigurationFilePathByName(name, type);
+}
+
 // --- KeyMap ---
 
 KeyMap::KeyMap() {
@@ -111,11 +118,25 @@
     }
 
     base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(path);
+    if (ret.ok()) {
+        keyLayoutMap = *ret;
+        keyLayoutFile = path;
+        return OK;
+    }
+
+    // Try to load fallback layout if the regular layout could not be loaded due to missing
+    // kernel modules
+    std::string fallbackPath(
+            getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier,
+                                                                  InputDeviceConfigurationFileType::
+                                                                          KEY_LAYOUT,
+                                                                  "_fallback"));
+    ret = KeyLayoutMap::load(fallbackPath);
     if (!ret.ok()) {
         return ret.error().code();
     }
     keyLayoutMap = *ret;
-    keyLayoutFile = path;
+    keyLayoutFile = fallbackPath;
     return OK;
 }
 
@@ -137,14 +158,6 @@
     return OK;
 }
 
-std::string KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
-        const std::string& name, InputDeviceConfigurationFileType type) {
-    return name.empty()
-            ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
-            : getInputDeviceConfigurationFilePathByName(name, type);
-}
-
-
 // --- Global functions ---
 
 bool isKeyboardSpecialFunction(const PropertyMap* config) {
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 6ffe851..d947cd9 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -36,8 +36,9 @@
         "liblog",
         "libui",
         "libutils",
+        "libvintf",
     ],
-    data: ["data/*.kcm"],
+    data: ["data/*"],
     test_suites: ["device-tests"],
 }
 
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
index 61e88df..e872fa4 100644
--- a/libs/input/tests/InputDevice_test.cpp
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -64,13 +64,11 @@
         mKeyMap.keyCharacterMapFile = path;
     }
 
-    virtual void SetUp() override {
+    void SetUp() override {
         loadKeyLayout("Generic");
         loadKeyCharacterMap("Generic");
     }
 
-    virtual void TearDown() override {}
-
     KeyMap mKeyMap;
 };
 
@@ -132,4 +130,20 @@
     ASSERT_EQ(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
 }
 
+TEST(InputDeviceKeyLayoutTest, DoesNotLoadWhenRequiredKernelConfigIsMissing) {
+    std::string klPath = base::GetExecutableDirectory() + "/data/kl_with_required_fake_config.kl";
+    base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
+    ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath;
+    // We assert error message here because it's used by 'validatekeymaps' tool
+    ASSERT_EQ("Missing kernel config", ret.error().message());
+}
+
+TEST(InputDeviceKeyLayoutTest, LoadsWhenRequiredKernelConfigIsPresent) {
+    std::string klPath = base::GetExecutableDirectory() + "/data/kl_with_required_real_config.kl";
+    base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
+    ASSERT_TRUE(ret.ok()) << "Cannot load KeyLayout at " << klPath;
+    const std::shared_ptr<KeyLayoutMap>& map = *ret;
+    ASSERT_NE(nullptr, map) << "Map should be valid because CONFIG_UHID should always be present";
+}
+
 } // namespace android
diff --git a/libs/input/tests/data/kl_with_required_fake_config.kl b/libs/input/tests/data/kl_with_required_fake_config.kl
new file mode 100644
index 0000000..2d0a507
--- /dev/null
+++ b/libs/input/tests/data/kl_with_required_fake_config.kl
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 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.
+
+# This KL should not be loaded unless the below config is present in the kernel
+# This config will never exist, and therefore this KL should never be loaded
+requires_kernel_config CONFIG_HID_FAKEMODULE
+
+# An arbitrary mapping taken from another file
+key 0x130    BUTTON_X
\ No newline at end of file
diff --git a/libs/input/tests/data/kl_with_required_real_config.kl b/libs/input/tests/data/kl_with_required_real_config.kl
new file mode 100644
index 0000000..303b23e
--- /dev/null
+++ b/libs/input/tests/data/kl_with_required_real_config.kl
@@ -0,0 +1,21 @@
+# Copyright (C) 2022 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.
+
+# This KL should not be loaded unless the below config is present in the kernel
+# The CONFIG_UHID option has been required for a while, and therefore it's safe
+# to assume that this will always be loaded
+requires_kernel_config CONFIG_UHID
+
+# An arbitrary mapping taken from another file
+key 0x130    BUTTON_X
\ No newline at end of file
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index ed728dc..4659b96 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -33,7 +33,7 @@
 
 cc_library_headers {
     name: "libnativedisplay_headers",
-    export_include_dirs: ["include",],
+    export_include_dirs: ["include"],
 }
 
 cc_library_shared {
@@ -43,8 +43,6 @@
         "include-private",
     ],
 
-    clang: true,
-
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index ef7602f..af55623 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -207,7 +207,11 @@
       if (result == 0) {
         outPlanes->planeCount = 3;
         outPlanes->planes[0].data = yuvData.y;
-        outPlanes->planes[0].pixelStride = 1;
+        if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010) {
+            outPlanes->planes[0].pixelStride = 2;
+        } else {
+            outPlanes->planes[0].pixelStride = 1;
+        }
         outPlanes->planes[0].rowStride = yuvData.ystride;
         outPlanes->planes[1].data = yuvData.cb;
         outPlanes->planes[1].pixelStride = yuvData.chroma_step;
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 9286009..f7d2451 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -64,7 +64,7 @@
         symbol_file: "libnativewindow.map.txt",
         unversioned: true,
         override_export_include_dirs: [
-            "include"
+            "include",
         ],
     },
     export_include_dirs: [
@@ -72,8 +72,6 @@
         "include-private",
     ],
 
-    clang: true,
-
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 570c7bc..e8a4146 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -95,7 +95,7 @@
         "skia/debug/SkiaMemoryReporter.cpp",
         "skia/filters/BlurFilter.cpp",
         "skia/filters/LinearEffect.cpp",
-        "skia/filters/StretchShaderFactory.cpp"
+        "skia/filters/StretchShaderFactory.cpp",
     ],
 }
 
@@ -103,7 +103,6 @@
     name: "librenderengine",
     defaults: ["librenderengine_defaults"],
     double_loadable: true,
-    clang: true,
     cflags: [
         "-fvisibility=hidden",
         "-Werror=format",
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index edd453a..2b93c6e 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -24,7 +24,6 @@
 cc_library_shared {
     name: "libsensor",
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -53,5 +52,9 @@
 
     export_include_dirs: ["include"],
 
-    export_shared_lib_headers: ["libbinder", "libpermission", "libhardware"],
+    export_shared_lib_headers: [
+        "libbinder",
+        "libpermission",
+        "libhardware",
+    ],
 }
diff --git a/libs/sensor/tests/Android.bp b/libs/sensor/tests/Android.bp
index 8fdb003..ac4be44 100644
--- a/libs/sensor/tests/Android.bp
+++ b/libs/sensor/tests/Android.bp
@@ -24,9 +24,10 @@
 cc_test {
     name: "libsensor_test",
 
-    clang: true,
-
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 
     srcs: [
         "Sensor_test.cpp",
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 506e308..2f4f111 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -31,7 +31,6 @@
 
 cc_defaults {
     name: "libui-defaults",
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -105,7 +104,6 @@
     },
     double_loadable: true,
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 80f6c82..162fd95 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -300,20 +300,19 @@
             if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
                 continue;
             }
-            if (0 != planeLayoutComponent.offsetInBits % 8) {
-                unlock(bufferHandle);
-                return BAD_VALUE;
-            }
 
-            uint8_t* tmpData = static_cast<uint8_t*>(data) + planeLayout.offsetInBytes +
-                    (planeLayoutComponent.offsetInBits / 8);
+            uint8_t* tmpData = static_cast<uint8_t*>(data) + planeLayout.offsetInBytes;
+
+            // Note that `offsetInBits` may not be a multiple of 8 for packed formats (e.g. P010)
+            // but we still want to point to the start of the first byte.
+            tmpData += (planeLayoutComponent.offsetInBits / 8);
+
             uint64_t sampleIncrementInBytes;
 
             auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
             switch (type) {
                 case PlaneLayoutComponentType::Y:
-                    if ((ycbcr.y != nullptr) || (planeLayoutComponent.sizeInBits != 8) ||
-                        (planeLayout.sampleIncrementInBits != 8)) {
+                    if ((ycbcr.y != nullptr) || (planeLayout.sampleIncrementInBits % 8 != 0)) {
                         unlock(bufferHandle);
                         return BAD_VALUE;
                     }
@@ -329,7 +328,8 @@
                     }
 
                     sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
-                    if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2)) {
+                    if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2) &&
+                        (sampleIncrementInBytes != 4)) {
                         unlock(bufferHandle);
                         return BAD_VALUE;
                     }
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 516aad8..b780770 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -93,7 +93,6 @@
     cflags: ["-Wall", "-Werror"],
     shared_libs: [
         "libbinder",
-        "libgui",
         "liblog",
         "libui",
         "libutils",
diff --git a/libs/ui/tests/GraphicBufferOverBinder_test.cpp b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
index 126a945..4c9d574 100644
--- a/libs/ui/tests/GraphicBufferOverBinder_test.cpp
+++ b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
@@ -20,9 +20,6 @@
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
 #include <gtest/gtest.h>
-#include <gui/BufferQueue.h>
-#include <gui/IGraphicBufferConsumer.h>
-#include <gui/IGraphicBufferProducer.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/Log.h>
 
diff --git a/libs/ui/tools/Android.bp b/libs/ui/tools/Android.bp
index c28c303..5d6070c 100644
--- a/libs/ui/tools/Android.bp
+++ b/libs/ui/tools/Android.bp
@@ -25,7 +25,7 @@
 
 cc_defaults {
     name: "libui_tools_default",
-    clang_cflags: [
+    cflags: [
         "-Wall",
         "-Wextra",
         "-Werror",
diff --git a/libs/vr/libbroadcastring/Android.bp b/libs/vr/libbroadcastring/Android.bp
index d4538f1..e72ca74 100644
--- a/libs/vr/libbroadcastring/Android.bp
+++ b/libs/vr/libbroadcastring/Android.bp
@@ -9,7 +9,7 @@
 
 cc_library_static {
     name: "libbroadcastring",
-    clang: true,
+
     cflags: [
         "-Wall",
         "-Wextra",
@@ -26,7 +26,6 @@
 
 cc_test {
     name: "broadcast_ring_tests",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index c1f6da3..c95603b 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -16,7 +16,6 @@
 
 cc_library_static {
     name: "libpdx",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
@@ -42,7 +41,6 @@
 
 cc_test {
     name: "pdx_tests",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
@@ -72,7 +70,6 @@
 // Code analysis target.
 cc_test {
     name: "pdx_encoder_performance_test",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
diff --git a/libs/vr/libpdx/fuzz/Android.bp b/libs/vr/libpdx/fuzz/Android.bp
index cc32b18..ac831ce 100644
--- a/libs/vr/libpdx/fuzz/Android.bp
+++ b/libs/vr/libpdx/fuzz/Android.bp
@@ -9,7 +9,6 @@
 
 cc_fuzz {
     name: "libpdx_service_dispatcher_fuzzer",
-    clang: true,
     srcs: [
         "service_dispatcher_fuzzer.cpp",
     ],
@@ -24,13 +23,12 @@
     shared_libs: [
         "libutils",
         "liblog",
-        "libcutils"
+        "libcutils",
     ],
 }
 
 cc_fuzz {
     name: "libpdx_message_fuzzer",
-    clang: true,
     srcs: [
         "message_fuzzer.cpp",
     ],
@@ -45,13 +43,12 @@
     shared_libs: [
         "libutils",
         "liblog",
-        "libcutils"
+        "libcutils",
     ],
 }
 
 cc_fuzz {
     name: "libpdx_serialization_fuzzer",
-    clang: true,
     srcs: [
         "serialization_fuzzer.cpp",
     ],
@@ -66,6 +63,6 @@
     shared_libs: [
         "libutils",
         "liblog",
-        "libcutils"
+        "libcutils",
     ],
 }
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index 8046857..a5758b5 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -9,7 +9,6 @@
 
 cc_defaults {
     name: "pdx_default_transport_compiler_defaults",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
@@ -26,7 +25,10 @@
 cc_defaults {
     name: "pdx_use_transport_servicefs",
     export_include_dirs: ["private/servicefs"],
-    whole_static_libs: ["libpdx_servicefs", "libservicefs"],
+    whole_static_libs: [
+        "libpdx_servicefs",
+        "libservicefs",
+    ],
 }
 
 cc_defaults {
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index 216ca9f..7f88daf 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -9,7 +9,6 @@
 
 cc_library_static {
     name: "libpdx_uds",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
@@ -41,7 +40,6 @@
 
 cc_test {
     name: "libpdx_uds_tests",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index bf848af..06ecd25 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -31,7 +31,7 @@
     "vr_flinger.cpp",
 ]
 
-includeFiles = [ "include" ]
+includeFiles = ["include"]
 
 staticLibraries = [
     "libdisplay",
@@ -83,8 +83,6 @@
 cc_library_static {
     srcs: sourceFiles,
     export_include_dirs: includeFiles,
-
-    clang: true,
     cflags: [
         "-DLOG_TAG=\"vr_flinger\"",
         "-DTRACE=0",
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index a8a8476..de7d8f8 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -17,6 +17,7 @@
 #include <processgroup/sched_policy.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
+#include <utils/ThreadDefs.h>
 
 #include <functional>
 
diff --git a/opengl/OWNERS b/opengl/OWNERS
index a47fb9a..379f763 100644
--- a/opengl/OWNERS
+++ b/opengl/OWNERS
@@ -6,7 +6,6 @@
 jessehall@google.com
 lfy@google.com
 lpy@google.com
-timvp@google.com
 romanl@google.com
 vantablack@google.com
 yuxinhu@google.com
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index c9fce8a..c1e935a 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -108,7 +108,6 @@
         // In particular, DO NOT add libutils nor anything "above" libui
         "libgraphicsenv",
         "libnativewindow",
-        "libbacktrace",
         "libbase",
     ],
 }
@@ -165,6 +164,7 @@
         "libnativeloader_lazy",
         "libutils",
         "libSurfaceFlingerProp",
+        "libunwindstack",
     ],
     static_libs: [
         "libEGL_getProcAddress",
diff --git a/opengl/libs/EGL/CallStack.h b/opengl/libs/EGL/CallStack.h
index b7fdf97..96437c3 100644
--- a/opengl/libs/EGL/CallStack.h
+++ b/opengl/libs/EGL/CallStack.h
@@ -16,8 +16,8 @@
 
 #pragma once
 
-#include <backtrace/Backtrace.h>
 #include <log/log.h>
+#include <unwindstack/AndroidUnwinder.h>
 
 #include <memory>
 
@@ -26,12 +26,15 @@
     // Create a callstack with the current thread's stack trace.
     // Immediately dump it to logcat using the given logtag.
     static void log(const char* logtag) noexcept {
-        std::unique_ptr<Backtrace> backtrace(
-                Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
-        if (backtrace->Unwind(2)) {
-            for (size_t i = 0, c = backtrace->NumFrames(); i < c; i++) {
+        unwindstack::AndroidLocalUnwinder unwinder;
+        unwindstack::AndroidUnwinderData data;
+        if (unwinder.Unwind(data)) {
+            for (size_t i = 2, c = data.frames.size(); i < c; i++) {
+                auto& frame = data.frames[i];
+                // Trim the first two frames.
+                frame.num -= 2;
                 __android_log_print(ANDROID_LOG_DEBUG, logtag, "%s",
-                                    backtrace->FormatFrameData(i).c_str());
+                                    unwinder.FormatFrame(frame).c_str());
             }
         }
     }
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index de36a7a..8363104 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -1448,7 +1448,11 @@
             setError(EGL_BAD_SURFACE, EGL_FALSE);
         }
         int err = native_window_set_auto_refresh(s->getNativeWindow(), value != 0);
-        return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+        if (err != 0) {
+            return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+        } else if (!s->cnx->useAngle) {
+            return EGL_TRUE;
+        } // else if ANGLE, fall through to the call to the driver (i.e. ANGLE) below
     }
 
     if (attribute == EGL_TIMESTAMPS_ANDROID) {
@@ -1458,7 +1462,11 @@
             return EGL_TRUE;
         }
         int err = native_window_enable_frame_timestamps(s->getNativeWindow(), value != 0);
-        return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+        if (err != 0) {
+            return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+        } else if (!s->cnx->useAngle) {
+            return EGL_TRUE;
+        } // else if ANGLE, fall through to the call to the driver (i.e. ANGLE) below
     }
 
     if (s->setSmpte2086Attribute(attribute, value)) {
diff --git a/opengl/tests/gl2_cameraeye/AndroidManifest.xml b/opengl/tests/gl2_cameraeye/AndroidManifest.xml
index c53f7be..a4674e1 100644
--- a/opengl/tests/gl2_cameraeye/AndroidManifest.xml
+++ b/opengl/tests/gl2_cameraeye/AndroidManifest.xml
@@ -26,7 +26,7 @@
     <uses-feature android:name="android.hardware.camera.autofocus" />
     <uses-feature android:glEsVersion="0x00020000" />
     <application android:label="@string/gl2cameraeye_name">
-        <activity android:name="GL2CameraEye">
+        <activity android:name="GL2CameraEye" android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
diff --git a/opengl/tests/gl2_java/AndroidManifest.xml b/opengl/tests/gl2_java/AndroidManifest.xml
index 8bb6840..500adb5 100644
--- a/opengl/tests/gl2_java/AndroidManifest.xml
+++ b/opengl/tests/gl2_java/AndroidManifest.xml
@@ -22,7 +22,8 @@
         <activity android:name="GL2JavaActivity"
                 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
             	android:launchMode="singleTask"
-            	android:configChanges="orientation|keyboardHidden">
+		android:configChanges="orientation|keyboardHidden"
+		android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/opengl/tests/gl2_jni/AndroidManifest.xml b/opengl/tests/gl2_jni/AndroidManifest.xml
index 1827e5f..b4ce99b 100644
--- a/opengl/tests/gl2_jni/AndroidManifest.xml
+++ b/opengl/tests/gl2_jni/AndroidManifest.xml
@@ -21,7 +21,8 @@
         <activity android:name="GL2JNIActivity"
                 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
             	android:launchMode="singleTask"
-            	android:configChanges="orientation|keyboardHidden">
+		android:configChanges="orientation|keyboardHidden"
+		android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/opengl/tests/gl_jni/AndroidManifest.xml b/opengl/tests/gl_jni/AndroidManifest.xml
index 5d0ec96..bedab56 100644
--- a/opengl/tests/gl_jni/AndroidManifest.xml
+++ b/opengl/tests/gl_jni/AndroidManifest.xml
@@ -24,7 +24,8 @@
                 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
             	android:launchMode="singleTask"
             	android:screenOrientation="landscape"
-            	android:configChanges="orientation|keyboardHidden">
+		android:configChanges="orientation|keyboardHidden"
+		android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/opengl/tests/lighting1709/AndroidManifest.xml b/opengl/tests/lighting1709/AndroidManifest.xml
index 6c23d42..d766be9 100644
--- a/opengl/tests/lighting1709/AndroidManifest.xml
+++ b/opengl/tests/lighting1709/AndroidManifest.xml
@@ -2,7 +2,7 @@
         package="com.android.lightingtest">
 
     <application>
-        <activity android:name="ClearActivity" android:label="LightingTest">
+        <activity android:name="ClearActivity" android:label="LightingTest" android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/opengl/tests/testPauseResume/AndroidManifest.xml b/opengl/tests/testPauseResume/AndroidManifest.xml
index 1879bc3..ae82a82 100644
--- a/opengl/tests/testPauseResume/AndroidManifest.xml
+++ b/opengl/tests/testPauseResume/AndroidManifest.xml
@@ -24,7 +24,8 @@
                 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
             	android:launchMode="singleTask"
             	android:screenOrientation="landscape"
-            	android:configChanges="orientation|keyboardHidden">
+		android:configChanges="orientation|keyboardHidden"
+		android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index 4fb0d2e..86f6c7f 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -35,6 +35,7 @@
     header_libs: ["bpf_headers"],
     shared_libs: [
         "libbase",
+        "libbinder",
         "libbpf_bcc",
         "libcutils",
         "libgfxstats",
diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp
index e916221..36ae179 100644
--- a/services/gpuservice/tests/unittests/GpuMemTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "gpuservice_unittest"
 
 #include <android-base/stringprintf.h>
+#define BPF_MAP_MAKE_VISIBLE_FOR_TESTING
 #include <bpf/BpfMap.h>
 #include <gmock/gmock.h>
 #include <gpumem/GpuMem.h>
@@ -65,11 +66,11 @@
         mTestableGpuMem = TestableGpuMem(mGpuMem.get());
         mTestableGpuMem.setInitialized();
         errno = 0;
-        mTestMap = bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE,
-                                                   BPF_F_NO_PREALLOC);
+        mTestMap = std::move(bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH,
+                                                             TEST_MAP_SIZE,
+                                                             BPF_F_NO_PREALLOC));
 
         EXPECT_EQ(0, errno);
-        EXPECT_LE(0, mTestMap.getMap().get());
         EXPECT_TRUE(mTestMap.isValid());
     }
 
diff --git a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
index d76f039..5c04210 100644
--- a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
@@ -17,6 +17,7 @@
 #undef LOG_TAG
 #define LOG_TAG "gpuservice_unittest"
 
+#define BPF_MAP_MAKE_VISIBLE_FOR_TESTING
 #include <bpf/BpfMap.h>
 #include <gpumem/GpuMem.h>
 #include <gtest/gtest.h>
@@ -64,11 +65,11 @@
         mTestableGpuMem = TestableGpuMem(mGpuMem.get());
 
         errno = 0;
-        mTestMap = bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE,
-                                                   BPF_F_NO_PREALLOC);
+        mTestMap = std::move(bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH,
+                                                             TEST_MAP_SIZE,
+                                                             BPF_F_NO_PREALLOC));
 
         EXPECT_EQ(0, errno);
-        EXPECT_LE(0, mTestMap.getMap().get());
         EXPECT_TRUE(mTestMap.isValid());
     }
 
diff --git a/services/gpuservice/tests/unittests/GpuStatsTest.cpp b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
index 20c8ccf..3c7644f 100644
--- a/services/gpuservice/tests/unittests/GpuStatsTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
@@ -18,12 +18,14 @@
 #define LOG_TAG "gpuservice_unittest"
 
 #include <unistd.h>
+#include <binder/ProcessState.h>
 #include <cutils/properties.h>
 #include <gmock/gmock.h>
 #include <gpustats/GpuStats.h>
 #include <gtest/gtest.h>
 #include <stats_pull_atom_callback.h>
 #include <statslog.h>
+#include <utils/Looper.h>
 #include <utils/String16.h>
 #include <utils/Vector.h>
 
@@ -61,8 +63,9 @@
 // clang-format on
 
 class GpuStatsTest : public testing::Test {
+    sp<android::Looper> looper;
 public:
-    GpuStatsTest() {
+    GpuStatsTest() : looper(Looper::prepare(0 /* opts */)) {
         const ::testing::TestInfo* const test_info =
                 ::testing::UnitTest::GetInstance()->current_test_info();
         ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
@@ -72,6 +75,10 @@
         const ::testing::TestInfo* const test_info =
                 ::testing::UnitTest::GetInstance()->current_test_info();
         ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+
+        // performs all pending callbacks until all data has been consumed
+        // gives time to process binder transactions by thread pool
+        looper->pollAll(1000);
     }
 
     std::string inputCommand(InputCommand cmd);
@@ -79,6 +86,10 @@
     void SetUp() override {
         mCpuVulkanVersion = property_get_int32("ro.cpuvulkan.version", 0);
         mGlesVersion = property_get_int32("ro.opengles.version", 0);
+
+        // start the thread pool
+        sp<ProcessState> ps(ProcessState::self());
+        ps->startThreadPool();
     }
 
     std::unique_ptr<GpuStats> mGpuStats = std::make_unique<GpuStats>();
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 166f358..26c33d2 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -449,8 +449,7 @@
         return false;
     }
 
-    std::vector<int32_t> scanCodes;
-    keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes);
+    std::vector<int32_t> scanCodes = keyMap.keyLayoutMap->findScanCodesForKey(keycode);
     const size_t N = scanCodes.size();
     for (size_t i = 0; i < N && i <= KEY_MAX; i++) {
         int32_t sc = scanCodes[i];
@@ -545,10 +544,10 @@
         return NAME_NOT_FOUND;
     }
 
-    int32_t scanCode;
-    if (keyMap.keyLayoutMap->findScanCodeForLed(led, &scanCode) != NAME_NOT_FOUND) {
-        if (scanCode >= 0 && scanCode <= LED_MAX && ledBitmask.test(scanCode)) {
-            *outScanCode = scanCode;
+    std::optional<int32_t> scanCode = keyMap.keyLayoutMap->findScanCodeForLed(led);
+    if (scanCode.has_value()) {
+        if (*scanCode >= 0 && *scanCode <= LED_MAX && ledBitmask.test(*scanCode)) {
+            *outScanCode = *scanCode;
             return NO_ERROR;
         }
     }
@@ -862,8 +861,7 @@
 
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
-        std::vector<int32_t> scanCodes;
-        device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes);
+        std::vector<int32_t> scanCodes = device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode);
         if (scanCodes.size() != 0) {
             if (device->readDeviceBitMask(EVIOCGKEY(0), device->keyState) >= 0) {
                 for (size_t i = 0; i < scanCodes.size(); i++) {
@@ -921,20 +919,16 @@
 
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr && device->keyMap.haveKeyLayout()) {
-        std::vector<int32_t> scanCodes;
         for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
-            scanCodes.clear();
+            std::vector<int32_t> scanCodes =
+                    device->keyMap.keyLayoutMap->findScanCodesForKey(keyCodes[codeIndex]);
 
-            status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey(keyCodes[codeIndex],
-                                                                            &scanCodes);
-            if (!err) {
-                // check the possible scan codes identified by the layout map against the
-                // map of codes actually emitted by the driver
-                for (size_t sc = 0; sc < scanCodes.size(); sc++) {
-                    if (device->keyBitmask.test(scanCodes[sc])) {
-                        outFlags[codeIndex] = 1;
-                        break;
-                    }
+            // check the possible scan codes identified by the layout map against the
+            // map of codes actually emitted by the driver
+            for (size_t sc = 0; sc < scanCodes.size(); sc++) {
+                if (device->keyBitmask.test(scanCodes[sc])) {
+                    outFlags[codeIndex] = 1;
+                    break;
                 }
             }
         }
@@ -988,14 +982,15 @@
     std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
 
-    if (device != nullptr && device->keyMap.haveKeyLayout()) {
-        status_t err = device->keyMap.keyLayoutMap->mapAxis(scanCode, outAxisInfo);
-        if (err == NO_ERROR) {
-            return NO_ERROR;
-        }
+    if (device == nullptr || !device->keyMap.haveKeyLayout()) {
+        return NAME_NOT_FOUND;
     }
-
-    return NAME_NOT_FOUND;
+    std::optional<AxisInfo> info = device->keyMap.keyLayoutMap->mapAxis(scanCode);
+    if (!info.has_value()) {
+        return NAME_NOT_FOUND;
+    }
+    *outAxisInfo = *info;
+    return NO_ERROR;
 }
 
 base::Result<std::pair<InputDeviceSensorType, int32_t>> EventHub::mapSensor(int32_t deviceId,
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index b419d9a..969c8ba 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1488,15 +1488,14 @@
     sp<TestInputListener> mFakeListener;
     sp<FakeInputReaderPolicy> mFakePolicy;
     std::shared_ptr<FakeEventHub> mFakeEventHub;
-    std::unique_ptr<InstrumentedInputReader> mReader;
+    sp<InstrumentedInputReader> mReader;
 
     void SetUp() override {
         mFakeEventHub = std::make_unique<FakeEventHub>();
         mFakePolicy = new FakeInputReaderPolicy();
         mFakeListener = new TestInputListener();
 
-        mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
-                                                            mFakeListener);
+        mReader = sp<InstrumentedInputReader>::make(mFakeEventHub, mFakePolicy, mFakeListener);
     }
 
     void TearDown() override {
@@ -2407,15 +2406,14 @@
     std::shared_ptr<FakeEventHub> mFakeEventHub;
     sp<FakeInputReaderPolicy> mFakePolicy;
     sp<TestInputListener> mFakeListener;
-    std::unique_ptr<InstrumentedInputReader> mReader;
+    sp<InstrumentedInputReader> mReader;
     std::shared_ptr<InputDevice> mDevice;
 
     void SetUp() override {
         mFakeEventHub = std::make_unique<FakeEventHub>();
         mFakePolicy = new FakeInputReaderPolicy();
         mFakeListener = new TestInputListener();
-        mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
-                                                            mFakeListener);
+        mReader = sp<InstrumentedInputReader>::make(mFakeEventHub, mFakePolicy, mFakeListener);
         InputDeviceIdentifier identifier;
         identifier.name = DEVICE_NAME;
         identifier.location = DEVICE_LOCATION;
@@ -2680,15 +2678,14 @@
     std::shared_ptr<FakeEventHub> mFakeEventHub;
     sp<FakeInputReaderPolicy> mFakePolicy;
     sp<TestInputListener> mFakeListener;
-    std::unique_ptr<InstrumentedInputReader> mReader;
+    sp<InstrumentedInputReader> mReader;
     std::shared_ptr<InputDevice> mDevice;
 
     virtual void SetUp(Flags<InputDeviceClass> classes) {
         mFakeEventHub = std::make_unique<FakeEventHub>();
         mFakePolicy = new FakeInputReaderPolicy();
         mFakeListener = new TestInputListener();
-        mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
-                                                            mFakeListener);
+        mReader = sp<InstrumentedInputReader>::make(mFakeEventHub, mFakePolicy, mFakeListener);
         mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes);
     }
 
@@ -8987,15 +8984,14 @@
     std::shared_ptr<FakeEventHub> mFakeEventHub;
     sp<FakeInputReaderPolicy> mFakePolicy;
     sp<TestInputListener> mFakeListener;
-    std::unique_ptr<InstrumentedInputReader> mReader;
+    sp<InstrumentedInputReader> mReader;
     std::shared_ptr<InputDevice> mDevice;
 
     virtual void SetUp(Flags<InputDeviceClass> classes) {
         mFakeEventHub = std::make_unique<FakeEventHub>();
         mFakePolicy = new FakeInputReaderPolicy();
         mFakeListener = new TestInputListener();
-        mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
-                                                            mFakeListener);
+        mReader = sp<InstrumentedInputReader>::make(mFakeEventHub, mFakePolicy, mFakeListener);
         mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes);
     }
 
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
index df4db19..455a1e2 100644
--- a/services/inputflinger/tests/fuzzers/Android.bp
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -42,4 +42,7 @@
     srcs: [
         "LatencyTrackerFuzzer.cpp",
     ],
+    fuzz_config: {
+       cc: ["android-framework-input@google.com"],
+    },
 }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index da7ff71..f94917c 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1608,8 +1608,10 @@
 void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
     for (const sp<Layer>& child : mDrawingChildren) {
         child->mDrawingParent = newParent;
+        const float parentShadowRadius =
+                newParent->canDrawShadows() ? 0.f : newParent->mEffectiveShadowRadius;
         child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform,
-                             newParent->mEffectiveShadowRadius);
+                             parentShadowRadius);
     }
 }
 
diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index 6916764..1834f2a 100644
--- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -94,7 +94,8 @@
     EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
 }
 
-TEST_F(OneShotTimerTest, resetBackToBackTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_resetBackToBackTest) {
     fake::FakeClock* clock = new fake::FakeClock();
     mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
                                                            mResetTimerCallback.getInvocable(),
diff --git a/services/utils/tests/Android.bp b/services/utils/tests/Android.bp
index 54cf5b7..cfa8a08 100644
--- a/services/utils/tests/Android.bp
+++ b/services/utils/tests/Android.bp
@@ -34,5 +34,4 @@
         "libgmock",
         "libserviceutils",
     ],
-    clang: true,
 }
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 440c5b1..5719b5c 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -37,7 +37,6 @@
             "vulkan_headers",
         ],
     },
-    clang: true,
     sanitize: {
         misc_undefined: ["integer"],
     },
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index cf774fd..0c5d61b 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -624,8 +624,10 @@
         switch (ext_bit) {
             case ProcHook::KHR_android_surface:
             case ProcHook::KHR_surface:
+            case ProcHook::KHR_surface_protected_capabilities:
             case ProcHook::EXT_swapchain_colorspace:
             case ProcHook::KHR_get_surface_capabilities2:
+            case ProcHook::GOOGLE_surfaceless_query:
                 hook_extensions_.set(ext_bit);
                 // return now as these extensions do not require HAL support
                 return;
@@ -701,8 +703,10 @@
             case ProcHook::KHR_external_fence_capabilities:
             case ProcHook::KHR_get_surface_capabilities2:
             case ProcHook::KHR_surface:
+            case ProcHook::KHR_surface_protected_capabilities:
             case ProcHook::EXT_debug_report:
             case ProcHook::EXT_swapchain_colorspace:
+            case ProcHook::GOOGLE_surfaceless_query:
             case ProcHook::ANDROID_native_buffer:
             case ProcHook::EXTENSION_CORE_1_0:
             case ProcHook::EXTENSION_CORE_1_1:
@@ -913,6 +917,9 @@
     loader_extensions.push_back({
         VK_KHR_SURFACE_EXTENSION_NAME,
         VK_KHR_SURFACE_SPEC_VERSION});
+    loader_extensions.push_back(
+        {VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME,
+         VK_KHR_SURFACE_PROTECTED_CAPABILITIES_SPEC_VERSION});
     loader_extensions.push_back({
         VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
         VK_KHR_ANDROID_SURFACE_SPEC_VERSION});
@@ -922,6 +929,8 @@
     loader_extensions.push_back({
         VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
         VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION});
+    loader_extensions.push_back({VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME,
+                                 VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION});
 
     static const VkExtensionProperties loader_debug_report_extension = {
         VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION,
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 5f37a50..b436db1 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -565,11 +565,13 @@
     if (strcmp(name, "VK_EXT_hdr_metadata") == 0) return ProcHook::EXT_hdr_metadata;
     if (strcmp(name, "VK_EXT_swapchain_colorspace") == 0) return ProcHook::EXT_swapchain_colorspace;
     if (strcmp(name, "VK_GOOGLE_display_timing") == 0) return ProcHook::GOOGLE_display_timing;
+    if (strcmp(name, "VK_GOOGLE_surfaceless_query") == 0) return ProcHook::GOOGLE_surfaceless_query;
     if (strcmp(name, "VK_KHR_android_surface") == 0) return ProcHook::KHR_android_surface;
     if (strcmp(name, "VK_KHR_get_surface_capabilities2") == 0) return ProcHook::KHR_get_surface_capabilities2;
     if (strcmp(name, "VK_KHR_incremental_present") == 0) return ProcHook::KHR_incremental_present;
     if (strcmp(name, "VK_KHR_shared_presentable_image") == 0) return ProcHook::KHR_shared_presentable_image;
     if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface;
+    if (strcmp(name, "VK_KHR_surface_protected_capabilities") == 0) return ProcHook::KHR_surface_protected_capabilities;
     if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain;
     if (strcmp(name, "VK_ANDROID_external_memory_android_hardware_buffer") == 0) return ProcHook::ANDROID_external_memory_android_hardware_buffer;
     if (strcmp(name, "VK_KHR_bind_memory2") == 0) return ProcHook::KHR_bind_memory2;
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 047e774..688630c 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -41,11 +41,13 @@
         EXT_hdr_metadata,
         EXT_swapchain_colorspace,
         GOOGLE_display_timing,
+        GOOGLE_surfaceless_query,
         KHR_android_surface,
         KHR_get_surface_capabilities2,
         KHR_incremental_present,
         KHR_shared_presentable_image,
         KHR_surface,
+        KHR_surface_protected_capabilities,
         KHR_swapchain,
         ANDROID_external_memory_android_hardware_buffer,
         KHR_bind_memory2,
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 6191063..e60625b 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -614,42 +614,65 @@
 
 VKAPI_ATTR
 VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(
-    VkPhysicalDevice /*pdev*/,
+    VkPhysicalDevice pdev,
     VkSurfaceKHR surface,
     VkSurfaceCapabilitiesKHR* capabilities) {
     ATRACE_CALL();
 
     int err;
-    ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
-
     int width, height;
-    err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
-    if (err != android::OK) {
-        ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
-              strerror(-err), err);
-        return VK_ERROR_SURFACE_LOST_KHR;
-    }
-    err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
-    if (err != android::OK) {
-        ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
-              strerror(-err), err);
-        return VK_ERROR_SURFACE_LOST_KHR;
-    }
-
     int transform_hint;
-    err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
-    if (err != android::OK) {
-        ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
-              strerror(-err), err);
-        return VK_ERROR_SURFACE_LOST_KHR;
-    }
-
     int max_buffer_count;
-    err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &max_buffer_count);
-    if (err != android::OK) {
-        ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)",
-              strerror(-err), err);
-        return VK_ERROR_SURFACE_LOST_KHR;
+    if (surface == VK_NULL_HANDLE) {
+        const InstanceData& instance_data = GetData(pdev);
+        ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query;
+        bool surfaceless_enabled =
+            instance_data.hook_extensions.test(surfaceless);
+        if (!surfaceless_enabled) {
+            // It is an error to pass a surface==VK_NULL_HANDLE unless the
+            // VK_GOOGLE_surfaceless_query extension is enabled
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+        // Support for VK_GOOGLE_surfaceless_query.  The primary purpose of this
+        // extension for this function is for
+        // VkSurfaceProtectedCapabilitiesKHR::supportsProtected.  The following
+        // four values cannot be known without a surface.  Default values will
+        // be supplied anyway, but cannot be relied upon.
+        width = 1000;
+        height = 1000;
+        transform_hint = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+        max_buffer_count = 10;
+    } else {
+        ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
+
+        err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
+        if (err != android::OK) {
+            ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
+                  strerror(-err), err);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+        err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
+        if (err != android::OK) {
+            ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
+                  strerror(-err), err);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+
+        err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT,
+                            &transform_hint);
+        if (err != android::OK) {
+            ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
+                  strerror(-err), err);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+
+        err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT,
+                            &max_buffer_count);
+        if (err != android::OK) {
+            ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)",
+                  strerror(-err), err);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
     }
     capabilities->minImageCount = std::min(max_buffer_count, 3);
     capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count);
@@ -690,23 +713,43 @@
     const InstanceData& instance_data = GetData(pdev);
 
     bool wide_color_support = false;
-    Surface& surface = *SurfaceFromHandle(surface_handle);
-    int err = native_window_get_wide_color_support(surface.window.get(),
-                                                   &wide_color_support);
-    if (err) {
-        return VK_ERROR_SURFACE_LOST_KHR;
-    }
-    ALOGV("wide_color_support is: %d", wide_color_support);
-    wide_color_support =
-        wide_color_support &&
+    uint64_t consumer_usage = 0;
+    bool colorspace_ext =
         instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
+    if (surface_handle == VK_NULL_HANDLE) {
+        ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query;
+        bool surfaceless_enabled =
+            instance_data.hook_extensions.test(surfaceless);
+        if (!surfaceless_enabled) {
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+        // Support for VK_GOOGLE_surfaceless_query.  The EGL loader
+        // unconditionally supports wide color formats, even if they will cause
+        // a SurfaceFlinger fallback.  Based on that, wide_color_support will be
+        // set to true in this case.
+        wide_color_support = true;
+
+        // TODO(b/203826952): research proper value; temporarily use the
+        // values seen on Pixel
+        consumer_usage = AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY;
+    } else {
+        Surface& surface = *SurfaceFromHandle(surface_handle);
+        int err = native_window_get_wide_color_support(surface.window.get(),
+                                                       &wide_color_support);
+        if (err) {
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+        ALOGV("wide_color_support is: %d", wide_color_support);
+
+        consumer_usage = surface.consumer_usage;
+    }
+    wide_color_support = wide_color_support && colorspace_ext;
 
     AHardwareBuffer_Desc desc = {};
     desc.width = 1;
     desc.height = 1;
     desc.layers = 1;
-    desc.usage = surface.consumer_usage |
-                 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+    desc.usage = consumer_usage | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
                  AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER;
 
     // We must support R8G8B8A8
@@ -714,6 +757,11 @@
         {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
         {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}};
 
+    if (colorspace_ext) {
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_BT709_LINEAR_EXT});
+    }
+
     if (wide_color_support) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
             VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
@@ -721,6 +769,10 @@
             VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
     }
 
+    // NOTE: Any new formats that are added must be coordinated across different
+    // Android users.  This includes the ANGLE team (a layered implementation of
+    // OpenGL-ES).
+
     desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
     if (AHardwareBuffer_isSupported(&desc)) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
@@ -797,6 +849,12 @@
                         .supportedUsageFlags;
             } break;
 
+            case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {
+                VkSurfaceProtectedCapabilitiesKHR* protected_caps =
+                    reinterpret_cast<VkSurfaceProtectedCapabilitiesKHR*>(caps);
+                protected_caps->supportsProtected = VK_TRUE;
+            } break;
+
             default:
                 // Ignore all other extension structs
                 break;
@@ -848,31 +906,50 @@
 
     int err;
     int query_value;
-    ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
-
-    err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-                        &query_value);
-    if (err != android::OK || query_value < 0) {
-        ALOGE(
-            "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) "
-            "value=%d",
-            strerror(-err), err, query_value);
-        return VK_ERROR_SURFACE_LOST_KHR;
-    }
-    uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
-
-    err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
-    if (err != android::OK || query_value < 0) {
-        ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d) value=%d",
-              strerror(-err), err, query_value);
-        return VK_ERROR_SURFACE_LOST_KHR;
-    }
-    uint32_t max_buffer_count = static_cast<uint32_t>(query_value);
-
     std::vector<VkPresentModeKHR> present_modes;
-    if (min_undequeued_buffers + 1 < max_buffer_count)
-        present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
-    present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
+    if (surface == VK_NULL_HANDLE) {
+        const InstanceData& instance_data = GetData(pdev);
+        ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query;
+        bool surfaceless_enabled =
+            instance_data.hook_extensions.test(surfaceless);
+        if (!surfaceless_enabled) {
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+        // Support for VK_GOOGLE_surfaceless_query.  The primary purpose of this
+        // extension for this function is for
+        // VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR and
+        // VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR.  We technically cannot
+        // know if VK_PRESENT_MODE_SHARED_MAILBOX_KHR is supported without a
+        // surface, and that cannot be relied upon.  Therefore, don't return it.
+        present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
+    } else {
+        ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
+
+        err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                            &query_value);
+        if (err != android::OK || query_value < 0) {
+            ALOGE(
+                "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) "
+                "value=%d",
+                strerror(-err), err, query_value);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+        uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
+
+        err =
+            window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
+        if (err != android::OK || query_value < 0) {
+            ALOGE(
+                "NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d) value=%d",
+                strerror(-err), err, query_value);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+        uint32_t max_buffer_count = static_cast<uint32_t>(query_value);
+
+        if (min_undequeued_buffers + 1 < max_buffer_count)
+            present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
+        present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
+    }
 
     VkPhysicalDevicePresentationPropertiesANDROID present_properties;
     QueryPresentationProperties(pdev, &present_properties);
diff --git a/vulkan/nulldrv/Android.bp b/vulkan/nulldrv/Android.bp
index 0daad9c..a6d540b 100644
--- a/vulkan/nulldrv/Android.bp
+++ b/vulkan/nulldrv/Android.bp
@@ -27,7 +27,6 @@
     proprietary: true,
     relative_install_path: "hw",
 
-    clang: true,
     cflags: [
         "-fvisibility=hidden",
         "-fstrict-aliasing",
diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py
index 6a73023..af56764 100644
--- a/vulkan/scripts/driver_generator.py
+++ b/vulkan/scripts/driver_generator.py
@@ -27,11 +27,13 @@
     'VK_EXT_hdr_metadata',
     'VK_EXT_swapchain_colorspace',
     'VK_GOOGLE_display_timing',
+    'VK_GOOGLE_surfaceless_query',
     'VK_KHR_android_surface',
     'VK_KHR_get_surface_capabilities2',
     'VK_KHR_incremental_present',
     'VK_KHR_shared_presentable_image',
     'VK_KHR_surface',
+    'VK_KHR_surface_protected_capabilities',
     'VK_KHR_swapchain',
 ]
 
diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp
index fa0258b..b6d3a0b 100644
--- a/vulkan/vkjson/Android.bp
+++ b/vulkan/vkjson/Android.bp
@@ -37,7 +37,6 @@
 
 cc_library_static {
     name: "libvkjson_ndk",
-    clang: true,
     srcs: [
         "vkjson.cc",
         "vkjson_instance.cc",
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 438e5dd..61e3859 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -840,56 +840,52 @@
 template <typename Visitor>
 inline bool Iterate(Visitor* visitor, VkJsonDevice* device) {
   bool ret = true;
-  switch (device->properties.apiVersion ^
-          VK_VERSION_PATCH(device->properties.apiVersion)) {
-    case VK_API_VERSION_1_2:
-      FALLTHROUGH_INTENDED;
-    case VK_API_VERSION_1_1:
-      ret &=
-          visitor->Visit("subgroupProperties", &device->subgroup_properties) &&
-          visitor->Visit("pointClippingProperties",
-                         &device->point_clipping_properties) &&
-          visitor->Visit("multiviewProperties",
-                         &device->multiview_properties) &&
-          visitor->Visit("idProperties", &device->id_properties) &&
-          visitor->Visit("maintenance3Properties",
-                         &device->maintenance3_properties) &&
-          visitor->Visit("16bitStorageFeatures",
-                         &device->bit16_storage_features) &&
-          visitor->Visit("multiviewFeatures", &device->multiview_features) &&
-          visitor->Visit("variablePointerFeatures",
-                         &device->variable_pointer_features) &&
-          visitor->Visit("protectedMemoryFeatures",
-                         &device->protected_memory_features) &&
-          visitor->Visit("samplerYcbcrConversionFeatures",
-                         &device->sampler_ycbcr_conversion_features) &&
-          visitor->Visit("shaderDrawParameterFeatures",
-                         &device->shader_draw_parameter_features) &&
-          visitor->Visit("externalFenceProperties",
-                         &device->external_fence_properties) &&
-          visitor->Visit("externalSemaphoreProperties",
-                         &device->external_semaphore_properties);
-      FALLTHROUGH_INTENDED;
-    case VK_API_VERSION_1_0:
-      ret &= visitor->Visit("properties", &device->properties) &&
-             visitor->Visit("features", &device->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);
-      }
-      if (device->ext_shader_float16_int8_features.reported) {
-        ret &= visitor->Visit("VK_KHR_shader_float16_int8",
-                              &device->ext_shader_float16_int8_features);
-      }
+  if (device->properties.apiVersion >= VK_API_VERSION_1_1) {
+    ret &=
+        visitor->Visit("subgroupProperties", &device->subgroup_properties) &&
+        visitor->Visit("pointClippingProperties",
+                        &device->point_clipping_properties) &&
+        visitor->Visit("multiviewProperties",
+                        &device->multiview_properties) &&
+        visitor->Visit("idProperties", &device->id_properties) &&
+        visitor->Visit("maintenance3Properties",
+                        &device->maintenance3_properties) &&
+        visitor->Visit("16bitStorageFeatures",
+                        &device->bit16_storage_features) &&
+        visitor->Visit("multiviewFeatures", &device->multiview_features) &&
+        visitor->Visit("variablePointerFeatures",
+                        &device->variable_pointer_features) &&
+        visitor->Visit("protectedMemoryFeatures",
+                        &device->protected_memory_features) &&
+        visitor->Visit("samplerYcbcrConversionFeatures",
+                        &device->sampler_ycbcr_conversion_features) &&
+        visitor->Visit("shaderDrawParameterFeatures",
+                        &device->shader_draw_parameter_features) &&
+        visitor->Visit("externalFenceProperties",
+                        &device->external_fence_properties) &&
+        visitor->Visit("externalSemaphoreProperties",
+                        &device->external_semaphore_properties);
+  }
+  if (device->properties.apiVersion >= VK_API_VERSION_1_0) {
+    ret &= visitor->Visit("properties", &device->properties) &&
+            visitor->Visit("features", &device->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);
+    }
+    if (device->ext_shader_float16_int8_features.reported) {
+      ret &= visitor->Visit("VK_KHR_shader_float16_int8",
+                            &device->ext_shader_float16_int8_features);
+    }
   }
   return ret;
 }
@@ -897,16 +893,13 @@
 template <typename Visitor>
 inline bool Iterate(Visitor* visitor, VkJsonInstance* instance) {
   bool ret = true;
-  switch (instance->api_version ^ VK_VERSION_PATCH(instance->api_version)) {
-    case VK_API_VERSION_1_2:
-      FALLTHROUGH_INTENDED;
-    case VK_API_VERSION_1_1:
-      ret &= visitor->Visit("deviceGroups", &instance->device_groups);
-      FALLTHROUGH_INTENDED;
-    case VK_API_VERSION_1_0:
-      ret &= visitor->Visit("layers", &instance->layers) &&
-             visitor->Visit("extensions", &instance->extensions) &&
-             visitor->Visit("devices", &instance->devices);
+  if (instance->api_version >= VK_API_VERSION_1_1) {
+    ret &= visitor->Visit("deviceGroups", &instance->device_groups);
+  }
+  if (instance->api_version >= VK_API_VERSION_1_0) {
+    ret &= visitor->Visit("layers", &instance->layers) &&
+           visitor->Visit("extensions", &instance->extensions) &&
+           visitor->Visit("devices", &instance->devices);
   }
   return ret;
 }