Merge "Enable secondary_user_on_secondary_display for CtsFsMgrTestCases" into main
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index baddf65..08619b9 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -18,6 +18,7 @@
 #include <dlfcn.h>
 #include <err.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <linux/prctl.h>
 #include <malloc.h>
 #include <pthread.h>
@@ -69,7 +70,6 @@
 #include "crash_test.h"
 #include "debuggerd/handler.h"
 #include "gtest/gtest.h"
-#include "libdebuggerd/utility.h"
 #include "protocol.h"
 #include "tombstoned/tombstoned.h"
 #include "util.h"
@@ -86,6 +86,7 @@
 #define ARCH_SUFFIX ""
 #endif
 
+constexpr size_t kTagGranuleSize = 16;
 constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
 
 #define TIMEOUT(seconds, expr)                                     \
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 5156754..3e70f79 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -28,6 +28,7 @@
 #include <sys/ioctl.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
+#include <sys/statvfs.h>
 #include <sys/swap.h>
 #include <sys/types.h>
 #include <sys/utsname.h>
@@ -215,10 +216,6 @@
          */
         if (!(*fs_stat & FS_STAT_FULL_MOUNT_FAILED)) {  // already tried if full mount failed
             errno = 0;
-            if (fs_type == "ext4") {
-                // This option is only valid with ext4
-                tmpmnt_opts += ",nomblk_io_submit";
-            }
             ret = mount(blk_device.c_str(), target.c_str(), fs_type.c_str(), tmpmnt_flags,
                         tmpmnt_opts.c_str());
             PINFO << __FUNCTION__ << "(): mount(" << blk_device << "," << target << "," << fs_type
@@ -930,7 +927,8 @@
 // attempted_idx: On return, will indicate which fstab entry
 //     succeeded. In case of failure, it will be the start_idx.
 // Sets errno to match the 1st mount failure on failure.
-static bool mount_with_alternatives(Fstab& fstab, int start_idx, int* end_idx, int* attempted_idx) {
+static bool mount_with_alternatives(Fstab& fstab, int start_idx, bool interrupted, int* end_idx,
+                                    int* attempted_idx) {
     unsigned long i;
     int mount_errno = 0;
     bool mounted = false;
@@ -949,6 +947,13 @@
             continue;
         }
 
+        if (interrupted) {
+            LINFO << __FUNCTION__ << "(): skipping fstab mountpoint=" << fstab[i].mount_point
+                  << " rec[" << i << "].fs_type=" << fstab[i].fs_type
+                  << " (previously interrupted during encryption step)";
+            continue;
+        }
+
         // fstab[start_idx].blk_device is already updated to /dev/dm-<N> by
         // AVB related functions. Copy it from start_idx to the current index i.
         if ((i != start_idx) && fstab[i].fs_mgr_flags.logical &&
@@ -1416,6 +1421,15 @@
     return GetEntryForMountPoint(&fstab, mount_point) != nullptr;
 }
 
+std::string fs_mgr_metadata_encryption_in_progress_file_name(const FstabEntry& entry) {
+    return entry.metadata_key_dir + "/in_progress";
+}
+
+bool WasMetadataEncryptionInterrupted(const FstabEntry& entry) {
+    if (!should_use_metadata_encryption(entry)) return false;
+    return access(fs_mgr_metadata_encryption_in_progress_file_name(entry).c_str(), R_OK) == 0;
+}
+
 // When multiple fstab records share the same mount_point, it will try to mount each
 // one in turn, and ignore any duplicates after a first successful mount.
 // Returns -1 on error, and  FS_MGR_MNTALL_* otherwise.
@@ -1530,7 +1544,9 @@
         int top_idx = i;
         int attempted_idx = -1;
 
-        bool mret = mount_with_alternatives(*fstab, i, &last_idx_inspected, &attempted_idx);
+        bool encryption_interrupted = WasMetadataEncryptionInterrupted(current_entry);
+        bool mret = mount_with_alternatives(*fstab, i, encryption_interrupted, &last_idx_inspected,
+                                            &attempted_idx);
         auto& attempted_entry = (*fstab)[attempted_idx];
         i = last_idx_inspected;
         int mount_errno = errno;
@@ -1579,13 +1595,18 @@
         // Mounting failed, understand why and retry.
         wiped = partition_wiped(current_entry.blk_device.c_str());
         if (mount_errno != EBUSY && mount_errno != EACCES &&
-            current_entry.fs_mgr_flags.formattable && wiped) {
+            current_entry.fs_mgr_flags.formattable && (wiped || encryption_interrupted)) {
             // current_entry and attempted_entry point at the same partition, but sometimes
             // at two different lines in the fstab.  Use current_entry for formatting
             // as that is the preferred one.
-            LERROR << __FUNCTION__ << "(): " << realpath(current_entry.blk_device)
-                   << " is wiped and " << current_entry.mount_point << " " << current_entry.fs_type
-                   << " is formattable. Format it.";
+            if (wiped)
+                LERROR << __FUNCTION__ << "(): " << realpath(current_entry.blk_device)
+                       << " is wiped and " << current_entry.mount_point << " "
+                       << current_entry.fs_type << " is formattable. Format it.";
+            if (encryption_interrupted)
+                LERROR << __FUNCTION__ << "(): " << realpath(current_entry.blk_device)
+                       << " was interrupted during encryption and " << current_entry.mount_point
+                       << " " << current_entry.fs_type << " is formattable. Format it.";
 
             checkpoint_manager.Revert(&current_entry);
 
@@ -1625,7 +1646,7 @@
         }
 
         // mount(2) returned an error, handle the encryptable/formattable case.
-        if (mount_errno != EBUSY && mount_errno != EACCES &&
+        if (mount_errno != EBUSY && mount_errno != EACCES && !encryption_interrupted &&
             should_use_metadata_encryption(attempted_entry)) {
             if (!call_vdc({"cryptfs", "mountFstab", attempted_entry.blk_device,
                            attempted_entry.mount_point,
@@ -1643,13 +1664,13 @@
             // Use StringPrintf to output "(null)" instead.
             if (attempted_entry.fs_mgr_flags.no_fail) {
                 PERROR << android::base::StringPrintf(
-                        "Ignoring failure to mount an un-encryptable or wiped "
+                        "Ignoring failure to mount an un-encryptable, interrupted, or wiped "
                         "partition on %s at %s options: %s",
                         attempted_entry.blk_device.c_str(), attempted_entry.mount_point.c_str(),
                         attempted_entry.fs_options.c_str());
             } else {
                 PERROR << android::base::StringPrintf(
-                        "Failed to mount an un-encryptable or wiped partition "
+                        "Failed to mount an un-encryptable, interrupted, or wiped partition "
                         "on %s at %s options: %s",
                         attempted_entry.blk_device.c_str(), attempted_entry.mount_point.c_str(),
                         attempted_entry.fs_options.c_str());
@@ -2069,11 +2090,45 @@
     return true;
 }
 
+/*
+ * Zram backing device can be created as long as /data has at least `size`
+ * free space, though we may want to leave some extra space for the remaining
+ * boot process and other system activities.
+ */
+static bool ZramBackingDeviceSizeAvailable(off64_t size) {
+    constexpr const char* data_path = "/data";
+    uint64_t min_free_mb =
+            android::base::GetUintProperty<uint64_t>("ro.zram_backing_device_min_free_mb", 0);
+
+    // No min_free property. Skip the available size check.
+    if (min_free_mb == 0) return true;
+
+    struct statvfs vst;
+    if (statvfs(data_path, &vst) < 0) {
+        PERROR << "Cannot check available space: " << data_path;
+        return false;
+    }
+
+    uint64_t size_free = static_cast<uint64_t>(vst.f_bfree) * vst.f_frsize;
+    uint64_t size_required = size + (min_free_mb * 1024 * 1024);
+    if (size_required > size_free) {
+        PERROR << "Free space is not enough for zram backing device: " << size_required << " > "
+               << size_free;
+        return false;
+    }
+    return true;
+}
+
 static bool PrepareZramBackingDevice(off64_t size) {
 
     constexpr const char* file_path = "/data/per_boot/zram_swap";
     if (size == 0) return true;
 
+    // Check available space
+    if (!ZramBackingDeviceSizeAvailable(size)) {
+        PERROR << "No space for target path: " << file_path;
+        return false;
+    }
     // Prepare target path
     unique_fd target_fd(TEMP_FAILURE_RETRY(open(file_path, O_RDWR | O_CREAT | O_CLOEXEC, 0600)));
     if (target_fd.get() == -1) {
@@ -2082,6 +2137,7 @@
     }
     if (fallocate(target_fd.get(), 0, 0, size) < 0) {
         PERROR << "Cannot truncate target path: " << file_path;
+        unlink(file_path);
         return false;
     }
 
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index bc4a7a6..2e1cf76 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -144,3 +144,7 @@
 // Unlike fs_mgr_overlayfs, mount overlayfs without upperdir and workdir, so the
 // filesystem cannot be remount read-write.
 bool fs_mgr_mount_overlayfs_fstab_entry(const android::fs_mgr::FstabEntry& entry);
+
+// File name used to track if encryption was interrupted, leading to a known bad fs state
+std::string fs_mgr_metadata_encryption_in_progress_file_name(
+        const android::fs_mgr::FstabEntry& entry);
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index b2e36d4..d66490c 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -2840,7 +2840,6 @@
     // that is fixed, don't call GTEST_SKIP here, but instead call GTEST_SKIP in individual test
     // suites.
     RETURN_IF_NON_VIRTUAL_AB_MSG("Virtual A/B is not enabled, skipping global setup.\n");
-    RETURN_IF_VENDOR_ON_ANDROID_S_MSG("Test not enabled for Vendor on Android S.\n");
 
     std::vector<std::string> paths = {
             // clang-format off
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
index b3a7e8c..efbcb5a 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -267,6 +267,10 @@
     test_suites: [
         "vts",
     ],
+    test_options: {
+        // VABC mandatory in Android T per VSR.
+        min_shipping_api_level: 32,
+    },
 }
 
 cc_binary_host {
diff --git a/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp b/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp
index e988335..4599ad3 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp
@@ -27,11 +27,12 @@
 DmUserBlockServer::DmUserBlockServer(const std::string& misc_name, unique_fd&& ctrl_fd,
                                      Delegate* delegate, size_t buffer_size)
     : misc_name_(misc_name), ctrl_fd_(std::move(ctrl_fd)), delegate_(delegate) {
-    buffer_.Initialize(buffer_size);
+    buffer_.Initialize(sizeof(struct dm_user_header), buffer_size);
 }
 
 bool DmUserBlockServer::ProcessRequests() {
-    struct dm_user_header* header = buffer_.GetHeaderPtr();
+    struct dm_user_header* header =
+            reinterpret_cast<struct dm_user_header*>(buffer_.GetHeaderPtr());
     if (!android::base::ReadFully(ctrl_fd_, header, sizeof(*header))) {
         if (errno != ENOTBLK) {
             SNAP_PLOG(ERROR) << "Control-read failed";
@@ -90,7 +91,8 @@
 }
 
 void DmUserBlockServer::SendError() {
-    struct dm_user_header* header = buffer_.GetHeaderPtr();
+    struct dm_user_header* header =
+            reinterpret_cast<struct dm_user_header*>(buffer_.GetHeaderPtr());
     header->type = DM_USER_RESP_ERROR;
     // This is an issue with the dm-user interface. There
     // is no way to propagate the I/O error back to dm-user
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h
index f1f8da1..35c6bfb 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h
+++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h
@@ -20,6 +20,7 @@
 
 #include <snapuserd/block_server.h>
 #include <snapuserd/snapuserd_buffer.h>
+#include <snapuserd/snapuserd_kernel.h>
 
 namespace android {
 namespace snapshot {
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h
index c5ca2b1..cc7c48c 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h
+++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h
@@ -27,13 +27,17 @@
 
 class BufferSink final {
   public:
-    void Initialize(size_t size);
+    // Do not reserve any space of header by default
+    void Initialize(size_t size) { return Initialize(0, size); };
+    // This allows to set const header_size_ to be used if caller needs it
+    // for example, while working with dm_user
+    void Initialize(size_t header_size, size_t size);
     void* GetBufPtr() { return buffer_.get(); }
     void Clear() { memset(GetBufPtr(), 0, buffer_size_); }
     void* GetPayloadBuffer(size_t size);
     void* GetBuffer(size_t requested, size_t* actual);
     void UpdateBufferOffset(size_t size) { buffer_offset_ += size; }
-    struct dm_user_header* GetHeaderPtr();
+    void* GetHeaderPtr();
     void ResetBufferOffset() { buffer_offset_ = 0; }
     void* GetPayloadBufPtr();
     loff_t GetPayloadBytesWritten() { return buffer_offset_; }
@@ -56,6 +60,7 @@
     std::unique_ptr<uint8_t[]> buffer_;
     loff_t buffer_offset_;
     size_t buffer_size_;
+    size_t header_size_;
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h
index 7ab75dc..14291b2 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h
+++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h
@@ -92,15 +92,5 @@
     __u64 len;
 } __attribute__((packed));
 
-struct dm_user_payload {
-    __u8 buf[];
-};
-
-// Message comprising both header and payload
-struct dm_user_message {
-    struct dm_user_header header;
-    struct dm_user_payload payload;
-};
-
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp
index 490c0e6..51b2490 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp
@@ -22,8 +22,9 @@
 namespace android {
 namespace snapshot {
 
-void BufferSink::Initialize(size_t size) {
-    buffer_size_ = size + sizeof(struct dm_user_header);
+void BufferSink::Initialize(size_t header_size, size_t size) {
+    header_size_ = header_size;
+    buffer_size_ = size + header_size;
     buffer_offset_ = 0;
     buffer_ = std::make_unique<uint8_t[]>(buffer_size_);
 }
@@ -41,11 +42,11 @@
 
 void* BufferSink::GetPayloadBuffer(size_t size) {
     char* buffer = reinterpret_cast<char*>(GetBufPtr());
-    struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
-    if ((buffer_size_ - buffer_offset_ - sizeof(msg->header)) < size) {
+
+    if ((buffer_size_ - buffer_offset_ - header_size_) < size) {
         return nullptr;
     }
-    return (char*)msg->payload.buf + buffer_offset_;
+    return (char*)(&buffer[0] + header_size_ + buffer_offset_);
 }
 
 void* BufferSink::GetBuffer(size_t requested, size_t* actual) {
@@ -58,19 +59,18 @@
     return buf;
 }
 
-struct dm_user_header* BufferSink::GetHeaderPtr() {
-    if (!(sizeof(struct dm_user_header) <= buffer_size_)) {
+void* BufferSink::GetHeaderPtr() {
+    // If no sufficient space or header not reserved
+    if (!(header_size_ <= buffer_size_) || !header_size_) {
         return nullptr;
     }
     char* buf = reinterpret_cast<char*>(GetBufPtr());
-    struct dm_user_header* header = (struct dm_user_header*)(&(buf[0]));
-    return header;
+    return (void*)(&(buf[0]));
 }
 
 void* BufferSink::GetPayloadBufPtr() {
     char* buffer = reinterpret_cast<char*>(GetBufPtr());
-    struct dm_user_message* msg = reinterpret_cast<struct dm_user_message*>(&(buffer[0]));
-    return msg->payload.buf;
+    return &buffer[header_size_];
 }
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
index 9042f2b..4dfb9bf 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
@@ -1530,6 +1530,14 @@
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
 
+#ifdef __ANDROID__
+    if (!android::snapshot::CanUseUserspaceSnapshots() ||
+        android::snapshot::IsVendorFromAndroid12()) {
+        std::cerr << "snapuserd_test not supported on this device\n";
+        return 0;
+    }
+#endif
+
     gflags::ParseCommandLineFlags(&argc, &argv, false);
 
     return RUN_ALL_TESTS();
diff --git a/fs_mgr/libsnapshot/snapuserd/utility.cpp b/fs_mgr/libsnapshot/snapuserd/utility.cpp
index 684ca3d..b44f5ab 100644
--- a/fs_mgr/libsnapshot/snapuserd/utility.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/utility.cpp
@@ -14,11 +14,14 @@
 
 #include "utility.h"
 
+#include <android-base/properties.h>
 #include <sys/resource.h>
 #include <sys/utsname.h>
 #include <unistd.h>
 
 #include <android-base/file.h>
+#include <android-base/logging.h>
+#include <libdm/dm.h>
 #include <processgroup/processgroup.h>
 
 #include <private/android_filesystem_config.h>
@@ -27,6 +30,7 @@
 namespace snapshot {
 
 using android::base::unique_fd;
+using android::dm::DeviceMapper;
 
 bool SetThreadPriority([[maybe_unused]] int priority) {
 #ifdef __ANDROID__
@@ -61,5 +65,38 @@
     return major > 5 || (major == 5 && minor >= 6);
 }
 
+bool GetUserspaceSnapshotsEnabledProperty() {
+    return android::base::GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false);
+}
+
+bool KernelSupportsCompressedSnapshots() {
+    auto& dm = DeviceMapper::Instance();
+    return dm.GetTargetByName("user", nullptr);
+}
+
+bool IsVendorFromAndroid12() {
+    const std::string UNKNOWN = "unknown";
+    const std::string vendor_release =
+            android::base::GetProperty("ro.vendor.build.version.release_or_codename", UNKNOWN);
+
+    if (vendor_release.find("12") != std::string::npos) {
+        return true;
+    }
+    return false;
+}
+
+bool CanUseUserspaceSnapshots() {
+    if (!GetUserspaceSnapshotsEnabledProperty()) {
+        LOG(INFO) << "Virtual A/B - Userspace snapshots disabled";
+        return false;
+    }
+
+    if (!KernelSupportsCompressedSnapshots()) {
+        LOG(ERROR) << "Userspace snapshots requested, but no kernel support is available.";
+        return false;
+    }
+    return true;
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/utility.h b/fs_mgr/libsnapshot/snapuserd/utility.h
index c3c3cba..50be418 100644
--- a/fs_mgr/libsnapshot/snapuserd/utility.h
+++ b/fs_mgr/libsnapshot/snapuserd/utility.h
@@ -24,5 +24,10 @@
 bool SetProfiles(std::initializer_list<std::string_view> profiles);
 bool KernelSupportsIoUring();
 
+bool GetUserspaceSnapshotsEnabledProperty();
+bool KernelSupportsCompressedSnapshots();
+bool CanUseUserspaceSnapshots();
+bool IsVendorFromAndroid12();
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 55cce6e..927b45f 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -305,6 +305,11 @@
             return false;
         }
     }
+
+    if (IsArcvm() && !block_dev_init_.InitHvcDevice("hvc1")) {
+        return false;
+    }
+
     return true;
 }
 
diff --git a/init/selinux.cpp b/init/selinux.cpp
index c2d9b8d..01af2b6 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -474,6 +474,8 @@
     RestoreconIfExists(SnapshotManager::GetGlobalRollbackIndicatorPath().c_str(), 0);
     RestoreconIfExists("/metadata/gsi",
                        SELINUX_ANDROID_RESTORECON_RECURSE | SELINUX_ANDROID_RESTORECON_SKIP_SEHASH);
+
+    RestoreconIfExists("/dev/hvc1", 0);
 }
 
 int SelinuxKlogCallback(int type, const char* fmt, ...) {
diff --git a/init/test_kill_services/init_kill_services_test.cpp b/init/test_kill_services/init_kill_services_test.cpp
index 3af92bb..efba9f6 100644
--- a/init/test_kill_services/init_kill_services_test.cpp
+++ b/init/test_kill_services/init_kill_services_test.cpp
@@ -87,6 +87,25 @@
     return info.param;
 }
 
-INSTANTIATE_TEST_CASE_P(DeathTest, InitKillServicesTest,
-                        ::testing::Values("lmkd", "ueventd", "hwservicemanager", "servicemanager"),
-                        PrintName);
+INSTANTIATE_TEST_CASE_P(
+        DeathTest, InitKillServicesTest,
+        ::testing::Values(
+                // clang-format off
+
+// TODO: we may want a more automatic way of testing this for services based on some
+// criteria (e.g. not disabled), but for now adding core services one at a time
+
+// BEGIN INTERNAL ONLY MERGE GUARD (add things here if internal only, move down later)
+// END INTERNAL ONLY MERGE GUARD
+
+// BEGIN AOSP ONLY (add things here if adding to AOSP)
+    "lmkd",
+    "ueventd",
+    "hwservicemanager",
+    "servicemanager",
+    "system_suspend"
+// END AOSP ONLY
+
+                // clang-format on
+                ),
+        PrintName);
diff --git a/init/util.h b/init/util.h
index aa24123..0565391 100644
--- a/init/util.h
+++ b/init/util.h
@@ -18,6 +18,7 @@
 
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/unistd.h>
 
 #include <chrono>
 #include <functional>
@@ -108,6 +109,10 @@
 #endif
 }
 
+inline bool IsArcvm() {
+    return !access("/is_arcvm", F_OK);
+}
+
 bool Has32BitAbi();
 
 std::string GetApexNameFromFileName(const std::string& path);
diff --git a/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump b/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump
index 67c7514..7ed131c 100644
--- a/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump
+++ b/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump
@@ -6,7 +6,6 @@
    "linker_set_key" : "_ZTIA0_i",
    "name" : "int[0]",
    "referenced_type" : "_ZTIi",
-   "self_type" : "_ZTIA0_i",
    "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
   }
  ],
@@ -17,8 +16,6 @@
    "is_integral" : true,
    "linker_set_key" : "_ZTIa",
    "name" : "signed char",
-   "referenced_type" : "_ZTIa",
-   "self_type" : "_ZTIa",
    "size" : 1
   },
   {
@@ -27,8 +24,6 @@
    "is_unsigned" : true,
    "linker_set_key" : "_ZTIb",
    "name" : "bool",
-   "referenced_type" : "_ZTIb",
-   "self_type" : "_ZTIb",
    "size" : 1
   },
   {
@@ -37,25 +32,27 @@
    "is_unsigned" : true,
    "linker_set_key" : "_ZTIc",
    "name" : "char",
-   "referenced_type" : "_ZTIc",
-   "self_type" : "_ZTIc",
    "size" : 1
   },
   {
    "alignment" : 4,
    "linker_set_key" : "_ZTIf",
    "name" : "float",
-   "referenced_type" : "_ZTIf",
-   "self_type" : "_ZTIf",
    "size" : 4
   },
   {
+   "alignment" : 1,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIh",
+   "name" : "unsigned char",
+   "size" : 1
+  },
+  {
    "alignment" : 4,
    "is_integral" : true,
    "linker_set_key" : "_ZTIi",
    "name" : "int",
-   "referenced_type" : "_ZTIi",
-   "self_type" : "_ZTIi",
    "size" : 4
   },
   {
@@ -64,8 +61,6 @@
    "is_unsigned" : true,
    "linker_set_key" : "_ZTIj",
    "name" : "unsigned int",
-   "referenced_type" : "_ZTIj",
-   "self_type" : "_ZTIj",
    "size" : 4
   },
   {
@@ -73,8 +68,6 @@
    "is_integral" : true,
    "linker_set_key" : "_ZTIl",
    "name" : "long",
-   "referenced_type" : "_ZTIl",
-   "self_type" : "_ZTIl",
    "size" : 8
   },
   {
@@ -83,15 +76,49 @@
    "is_unsigned" : true,
    "linker_set_key" : "_ZTIm",
    "name" : "unsigned long",
-   "referenced_type" : "_ZTIm",
-   "self_type" : "_ZTIm",
    "size" : 8
   },
   {
+   "alignment" : 16,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIo",
+   "name" : "unsigned __int128",
+   "size" : 16
+  },
+  {
+   "alignment" : 2,
+   "is_integral" : true,
+   "linker_set_key" : "_ZTIs",
+   "name" : "short",
+   "size" : 2
+  },
+  {
+   "alignment" : 2,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIt",
+   "name" : "unsigned short",
+   "size" : 2
+  },
+  {
    "linker_set_key" : "_ZTIv",
-   "name" : "void",
-   "referenced_type" : "_ZTIv",
-   "self_type" : "_ZTIv"
+   "name" : "void"
+  },
+  {
+   "alignment" : 8,
+   "is_integral" : true,
+   "linker_set_key" : "_ZTIx",
+   "name" : "long long",
+   "size" : 8
+  },
+  {
+   "alignment" : 8,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIy",
+   "name" : "unsigned long long",
+   "size" : 8
   }
  ],
  "elf_functions" :
@@ -100,70 +127,6 @@
    "name" : "_Z23socket_make_sockaddr_unPKciP11sockaddr_unPj"
   },
   {
-   "binding" : "weak",
-   "name" : "_ZN7android4base4TrimIRNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEES8_OT_"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE4syncEv"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE5imbueERKNS_6localeE"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE6setbufEPcl"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE7seekoffExNS_8ios_base7seekdirEj"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE7seekposENS_4fposI9mbstate_tEEj"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE8overflowEi"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE9pbackfailEi"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE9underflowEv"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEEC2Ev"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEED0Ev"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEED2Ev"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__16vectorI5EntryNS_9allocatorIS1_EEE24__emplace_back_slow_pathIJS1_EEEvDpOT_"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__17getlineIcNS_11char_traitsIcEENS_9allocatorIcEEEERNS_13basic_istreamIT_T0_EES9_RNS_12basic_stringIS6_S7_T1_EES6_"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_PKc"
-  },
-  {
    "name" : "android_get_control_file"
   },
   {
@@ -488,6 +451,12 @@
    "name" : "str_parms_to_str"
   },
   {
+   "name" : "uevent_bind"
+  },
+  {
+   "name" : "uevent_create_socket"
+  },
+  {
    "name" : "uevent_kernel_multicast_recv"
   },
   {
@@ -503,22 +472,6 @@
  "elf_objects" :
  [
   {
-   "binding" : "weak",
-   "name" : "_ZTCNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE0_NS_13basic_istreamIcS2_EE"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZTTNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZTVNSt3__113basic_filebufIcNS_11char_traitsIcEEEE"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZTVNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE"
-  },
-  {
    "name" : "atrace_enabled_tags"
   },
   {
@@ -553,8 +506,6 @@
    ],
    "linker_set_key" : "_ZTI12IoSchedClass",
    "name" : "IoSchedClass",
-   "referenced_type" : "_ZTI12IoSchedClass",
-   "self_type" : "_ZTI12IoSchedClass",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h",
    "underlying_type" : "_ZTIj"
@@ -575,9 +526,7 @@
      "referenced_type" : "_ZTIPv"
     }
    ],
-   "referenced_type" : "_ZTIFbPvS_E",
    "return_type" : "_ZTIb",
-   "self_type" : "_ZTIFbPvS_E",
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
   {
@@ -596,9 +545,7 @@
      "referenced_type" : "_ZTIPv"
     }
    ],
-   "referenced_type" : "_ZTIFbPvS_S_E",
    "return_type" : "_ZTIb",
-   "self_type" : "_ZTIFbPvS_S_E",
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
   {
@@ -611,9 +558,7 @@
      "referenced_type" : "_ZTIPv"
     }
    ],
-   "referenced_type" : "_ZTIFiPvE",
    "return_type" : "_ZTIi",
-   "self_type" : "_ZTIFiPvE",
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
   {
@@ -632,9 +577,7 @@
      "referenced_type" : "_ZTIPv"
     }
    ],
-   "referenced_type" : "_ZTIFvPKcS0_PvE",
    "return_type" : "_ZTIv",
-   "self_type" : "_ZTIFvPKcS0_PvE",
    "source_file" : "system/core/libcutils/include/cutils/properties.h"
   }
  ],
@@ -2267,6 +2210,33 @@
    "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
   },
   {
+   "function_name" : "uevent_bind",
+   "linker_set_key" : "uevent_bind",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/uevent.h"
+  },
+  {
+   "function_name" : "uevent_create_socket",
+   "linker_set_key" : "uevent_create_socket",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIb"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/uevent.h"
+  },
+  {
    "function_name" : "uevent_kernel_multicast_recv",
    "linker_set_key" : "uevent_kernel_multicast_recv",
    "parameters" :
@@ -2374,7 +2344,6 @@
    "linker_set_key" : "_ZTIP12IoSchedClass",
    "name" : "IoSchedClass *",
    "referenced_type" : "_ZTI12IoSchedClass",
-   "self_type" : "_ZTIP12IoSchedClass",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h"
   },
@@ -2383,7 +2352,6 @@
    "linker_set_key" : "_ZTIP12RecordStream",
    "name" : "RecordStream *",
    "referenced_type" : "_ZTI12RecordStream",
-   "self_type" : "_ZTIP12RecordStream",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
   },
@@ -2392,7 +2360,6 @@
    "linker_set_key" : "_ZTIP13native_handle",
    "name" : "native_handle *",
    "referenced_type" : "_ZTI13native_handle",
-   "self_type" : "_ZTIP13native_handle",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
   },
@@ -2401,7 +2368,6 @@
    "linker_set_key" : "_ZTIP5cnode",
    "name" : "cnode *",
    "referenced_type" : "_ZTI5cnode",
-   "self_type" : "_ZTIP5cnode",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
   },
@@ -2410,7 +2376,6 @@
    "linker_set_key" : "_ZTIP7Hashmap",
    "name" : "Hashmap *",
    "referenced_type" : "_ZTI7Hashmap",
-   "self_type" : "_ZTIP7Hashmap",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
@@ -2419,7 +2384,6 @@
    "linker_set_key" : "_ZTIP9fs_config",
    "name" : "fs_config *",
    "referenced_type" : "_ZTI9fs_config",
-   "self_type" : "_ZTIP9fs_config",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/private/fs_config.h"
   },
@@ -2428,7 +2392,6 @@
    "linker_set_key" : "_ZTIP9str_parms",
    "name" : "str_parms *",
    "referenced_type" : "_ZTI9str_parms",
-   "self_type" : "_ZTIP9str_parms",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
   },
@@ -2437,7 +2400,6 @@
    "linker_set_key" : "_ZTIPFbPvS_E",
    "name" : "bool (*)(void *, void *)",
    "referenced_type" : "_ZTIFbPvS_E",
-   "self_type" : "_ZTIPFbPvS_E",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
@@ -2446,7 +2408,6 @@
    "linker_set_key" : "_ZTIPFbPvS_S_E",
    "name" : "bool (*)(void *, void *, void *)",
    "referenced_type" : "_ZTIFbPvS_S_E",
-   "self_type" : "_ZTIPFbPvS_S_E",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
@@ -2455,7 +2416,6 @@
    "linker_set_key" : "_ZTIPFiPvE",
    "name" : "int (*)(void *)",
    "referenced_type" : "_ZTIFiPvE",
-   "self_type" : "_ZTIPFiPvE",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
@@ -2464,7 +2424,6 @@
    "linker_set_key" : "_ZTIPFvPKcS0_PvE",
    "name" : "void (*)(const char *, const char *, void *)",
    "referenced_type" : "_ZTIFvPKcS0_PvE",
-   "self_type" : "_ZTIPFvPKcS0_PvE",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/properties.h"
   },
@@ -2473,7 +2432,6 @@
    "linker_set_key" : "_ZTIPK13native_handle",
    "name" : "const native_handle *",
    "referenced_type" : "_ZTIK13native_handle",
-   "self_type" : "_ZTIPK13native_handle",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
   },
@@ -2482,7 +2440,6 @@
    "linker_set_key" : "_ZTIPK22cutils_socket_buffer_t",
    "name" : "const cutils_socket_buffer_t *",
    "referenced_type" : "_ZTIK22cutils_socket_buffer_t",
-   "self_type" : "_ZTIPK22cutils_socket_buffer_t",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/sockets.h"
   },
@@ -2491,7 +2448,6 @@
    "linker_set_key" : "_ZTIPK5iovec",
    "name" : "const iovec *",
    "referenced_type" : "_ZTIK5iovec",
-   "self_type" : "_ZTIPK5iovec",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/klog.h"
   },
@@ -2500,7 +2456,6 @@
    "linker_set_key" : "_ZTIPKc",
    "name" : "const char *",
    "referenced_type" : "_ZTIKc",
-   "self_type" : "_ZTIPKc",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
   },
@@ -2509,7 +2464,6 @@
    "linker_set_key" : "_ZTIPKv",
    "name" : "const void *",
    "referenced_type" : "_ZTIKv",
-   "self_type" : "_ZTIPKv",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/sockets.h"
   },
@@ -2518,7 +2472,6 @@
    "linker_set_key" : "_ZTIPPv",
    "name" : "void **",
    "referenced_type" : "_ZTIPv",
-   "self_type" : "_ZTIPPv",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
   },
@@ -2527,7 +2480,6 @@
    "linker_set_key" : "_ZTIPc",
    "name" : "char *",
    "referenced_type" : "_ZTIc",
-   "self_type" : "_ZTIPc",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
   },
@@ -2536,7 +2488,6 @@
    "linker_set_key" : "_ZTIPf",
    "name" : "float *",
    "referenced_type" : "_ZTIf",
-   "self_type" : "_ZTIPf",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
   },
@@ -2545,7 +2496,6 @@
    "linker_set_key" : "_ZTIPi",
    "name" : "int *",
    "referenced_type" : "_ZTIi",
-   "self_type" : "_ZTIPi",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h"
   },
@@ -2554,7 +2504,6 @@
    "linker_set_key" : "_ZTIPj",
    "name" : "unsigned int *",
    "referenced_type" : "_ZTIj",
-   "self_type" : "_ZTIPj",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/misc.h"
   },
@@ -2563,7 +2512,6 @@
    "linker_set_key" : "_ZTIPm",
    "name" : "unsigned long *",
    "referenced_type" : "_ZTIm",
-   "self_type" : "_ZTIPm",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
   },
@@ -2572,7 +2520,6 @@
    "linker_set_key" : "_ZTIPv",
    "name" : "void *",
    "referenced_type" : "_ZTIv",
-   "self_type" : "_ZTIPv",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/misc.h"
   }
@@ -2585,7 +2532,6 @@
    "linker_set_key" : "_ZTIK13native_handle",
    "name" : "const native_handle",
    "referenced_type" : "_ZTI13native_handle",
-   "self_type" : "_ZTIK13native_handle",
    "size" : 12,
    "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
   },
@@ -2595,7 +2541,6 @@
    "linker_set_key" : "_ZTIK22cutils_socket_buffer_t",
    "name" : "const cutils_socket_buffer_t",
    "referenced_type" : "_ZTI22cutils_socket_buffer_t",
-   "self_type" : "_ZTIK22cutils_socket_buffer_t",
    "size" : 16,
    "source_file" : "system/core/libcutils/include/cutils/sockets.h"
   },
@@ -2605,7 +2550,6 @@
    "linker_set_key" : "_ZTIK5iovec",
    "name" : "const iovec",
    "referenced_type" : "_ZTI5iovec",
-   "self_type" : "_ZTIK5iovec",
    "size" : 16,
    "source_file" : "system/core/libcutils/include/cutils/klog.h"
   },
@@ -2615,7 +2559,6 @@
    "linker_set_key" : "_ZTIKc",
    "name" : "const char",
    "referenced_type" : "_ZTIc",
-   "self_type" : "_ZTIKc",
    "size" : 1,
    "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
   },
@@ -2624,7 +2567,6 @@
    "linker_set_key" : "_ZTIKv",
    "name" : "const void",
    "referenced_type" : "_ZTIv",
-   "self_type" : "_ZTIKv",
    "source_file" : "system/core/libcutils/include/cutils/sockets.h"
   }
  ],
@@ -2656,8 +2598,6 @@
    ],
    "linker_set_key" : "_ZTI13native_handle",
    "name" : "native_handle",
-   "referenced_type" : "_ZTI13native_handle",
-   "self_type" : "_ZTI13native_handle",
    "size" : 12,
    "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
   },
@@ -2677,8 +2617,6 @@
    ],
    "linker_set_key" : "_ZTI22cutils_socket_buffer_t",
    "name" : "cutils_socket_buffer_t",
-   "referenced_type" : "_ZTI22cutils_socket_buffer_t",
-   "self_type" : "_ZTI22cutils_socket_buffer_t",
    "size" : 16,
    "source_file" : "system/core/libcutils/include/cutils/sockets.h"
   },
@@ -2713,8 +2651,6 @@
    ],
    "linker_set_key" : "_ZTI5cnode",
    "name" : "cnode",
-   "referenced_type" : "_ZTI5cnode",
-   "self_type" : "_ZTI5cnode",
    "size" : 40,
    "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
   },
@@ -2744,8 +2680,6 @@
    ],
    "linker_set_key" : "_ZTI9fs_config",
    "name" : "fs_config",
-   "referenced_type" : "_ZTI9fs_config",
-   "self_type" : "_ZTI9fs_config",
    "size" : 24,
    "source_file" : "system/core/libcutils/include/private/fs_config.h"
   }
diff --git a/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump b/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump
index f75240c..fe4361a 100644
--- a/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump
+++ b/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump
@@ -6,7 +6,6 @@
    "linker_set_key" : "_ZTIA0_i",
    "name" : "int[0]",
    "referenced_type" : "_ZTIi",
-   "self_type" : "_ZTIA0_i",
    "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
   }
  ],
@@ -17,8 +16,6 @@
    "is_integral" : true,
    "linker_set_key" : "_ZTIa",
    "name" : "signed char",
-   "referenced_type" : "_ZTIa",
-   "self_type" : "_ZTIa",
    "size" : 1
   },
   {
@@ -27,8 +24,6 @@
    "is_unsigned" : true,
    "linker_set_key" : "_ZTIb",
    "name" : "bool",
-   "referenced_type" : "_ZTIb",
-   "self_type" : "_ZTIb",
    "size" : 1
   },
   {
@@ -37,25 +32,27 @@
    "is_unsigned" : true,
    "linker_set_key" : "_ZTIc",
    "name" : "char",
-   "referenced_type" : "_ZTIc",
-   "self_type" : "_ZTIc",
    "size" : 1
   },
   {
    "alignment" : 4,
    "linker_set_key" : "_ZTIf",
    "name" : "float",
-   "referenced_type" : "_ZTIf",
-   "self_type" : "_ZTIf",
    "size" : 4
   },
   {
+   "alignment" : 1,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIh",
+   "name" : "unsigned char",
+   "size" : 1
+  },
+  {
    "alignment" : 4,
    "is_integral" : true,
    "linker_set_key" : "_ZTIi",
    "name" : "int",
-   "referenced_type" : "_ZTIi",
-   "self_type" : "_ZTIi",
    "size" : 4
   },
   {
@@ -64,33 +61,47 @@
    "is_unsigned" : true,
    "linker_set_key" : "_ZTIj",
    "name" : "unsigned int",
-   "referenced_type" : "_ZTIj",
-   "self_type" : "_ZTIj",
    "size" : 4
   },
   {
+   "alignment" : 4,
+   "is_integral" : true,
+   "linker_set_key" : "_ZTIl",
+   "name" : "long",
+   "size" : 4
+  },
+  {
+   "alignment" : 4,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIm",
+   "name" : "unsigned long",
+   "size" : 4
+  },
+  {
+   "alignment" : 2,
+   "is_integral" : true,
+   "linker_set_key" : "_ZTIs",
+   "name" : "short",
+   "size" : 2
+  },
+  {
    "alignment" : 2,
    "is_integral" : true,
    "is_unsigned" : true,
    "linker_set_key" : "_ZTIt",
    "name" : "unsigned short",
-   "referenced_type" : "_ZTIt",
-   "self_type" : "_ZTIt",
    "size" : 2
   },
   {
    "linker_set_key" : "_ZTIv",
-   "name" : "void",
-   "referenced_type" : "_ZTIv",
-   "self_type" : "_ZTIv"
+   "name" : "void"
   },
   {
    "alignment" : 8,
    "is_integral" : true,
    "linker_set_key" : "_ZTIx",
    "name" : "long long",
-   "referenced_type" : "_ZTIx",
-   "self_type" : "_ZTIx",
    "size" : 8
   },
   {
@@ -99,8 +110,6 @@
    "is_unsigned" : true,
    "linker_set_key" : "_ZTIy",
    "name" : "unsigned long long",
-   "referenced_type" : "_ZTIy",
-   "self_type" : "_ZTIy",
    "size" : 8
   }
  ],
@@ -114,66 +123,6 @@
    "name" : "_ZN7android4base4TrimIRNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEES8_OT_"
   },
   {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE4syncEv"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE5imbueERKNS_6localeE"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE6setbufEPci"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE7seekoffExNS_8ios_base7seekdirEj"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE7seekposENS_4fposI9mbstate_tEEj"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE8overflowEi"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE9pbackfailEi"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE9underflowEv"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEEC2Ev"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEED0Ev"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEED2Ev"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_j"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__16vectorI5EntryNS_9allocatorIS1_EEE24__emplace_back_slow_pathIJS1_EEEvDpOT_"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__17getlineIcNS_11char_traitsIcEENS_9allocatorIcEEEERNS_13basic_istreamIT_T0_EES9_RNS_12basic_stringIS6_S7_T1_EES6_"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_PKc"
-  },
-  {
    "name" : "android_get_control_file"
   },
   {
@@ -498,6 +447,12 @@
    "name" : "str_parms_to_str"
   },
   {
+   "name" : "uevent_bind"
+  },
+  {
+   "name" : "uevent_create_socket"
+  },
+  {
    "name" : "uevent_kernel_multicast_recv"
   },
   {
@@ -513,22 +468,6 @@
  "elf_objects" :
  [
   {
-   "binding" : "weak",
-   "name" : "_ZTCNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE0_NS_13basic_istreamIcS2_EE"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZTTNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZTVNSt3__113basic_filebufIcNS_11char_traitsIcEEEE"
-  },
-  {
-   "binding" : "weak",
-   "name" : "_ZTVNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE"
-  },
-  {
    "name" : "atrace_enabled_tags"
   },
   {
@@ -563,8 +502,6 @@
    ],
    "linker_set_key" : "_ZTI12IoSchedClass",
    "name" : "IoSchedClass",
-   "referenced_type" : "_ZTI12IoSchedClass",
-   "self_type" : "_ZTI12IoSchedClass",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h",
    "underlying_type" : "_ZTIj"
@@ -585,9 +522,7 @@
      "referenced_type" : "_ZTIPv"
     }
    ],
-   "referenced_type" : "_ZTIFbPvS_E",
    "return_type" : "_ZTIb",
-   "self_type" : "_ZTIFbPvS_E",
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
   {
@@ -606,9 +541,7 @@
      "referenced_type" : "_ZTIPv"
     }
    ],
-   "referenced_type" : "_ZTIFbPvS_S_E",
    "return_type" : "_ZTIb",
-   "self_type" : "_ZTIFbPvS_S_E",
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
   {
@@ -621,9 +554,7 @@
      "referenced_type" : "_ZTIPv"
     }
    ],
-   "referenced_type" : "_ZTIFiPvE",
    "return_type" : "_ZTIi",
-   "self_type" : "_ZTIFiPvE",
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
   {
@@ -642,9 +573,7 @@
      "referenced_type" : "_ZTIPv"
     }
    ],
-   "referenced_type" : "_ZTIFvPKcS0_PvE",
    "return_type" : "_ZTIv",
-   "self_type" : "_ZTIFvPKcS0_PvE",
    "source_file" : "system/core/libcutils/include/cutils/properties.h"
   }
  ],
@@ -2277,6 +2206,33 @@
    "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
   },
   {
+   "function_name" : "uevent_bind",
+   "linker_set_key" : "uevent_bind",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/uevent.h"
+  },
+  {
+   "function_name" : "uevent_create_socket",
+   "linker_set_key" : "uevent_create_socket",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIb"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/uevent.h"
+  },
+  {
    "function_name" : "uevent_kernel_multicast_recv",
    "linker_set_key" : "uevent_kernel_multicast_recv",
    "parameters" :
@@ -2384,7 +2340,6 @@
    "linker_set_key" : "_ZTIP12IoSchedClass",
    "name" : "IoSchedClass *",
    "referenced_type" : "_ZTI12IoSchedClass",
-   "self_type" : "_ZTIP12IoSchedClass",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h"
   },
@@ -2393,7 +2348,6 @@
    "linker_set_key" : "_ZTIP12RecordStream",
    "name" : "RecordStream *",
    "referenced_type" : "_ZTI12RecordStream",
-   "self_type" : "_ZTIP12RecordStream",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
   },
@@ -2402,7 +2356,6 @@
    "linker_set_key" : "_ZTIP13native_handle",
    "name" : "native_handle *",
    "referenced_type" : "_ZTI13native_handle",
-   "self_type" : "_ZTIP13native_handle",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
   },
@@ -2411,7 +2364,6 @@
    "linker_set_key" : "_ZTIP5cnode",
    "name" : "cnode *",
    "referenced_type" : "_ZTI5cnode",
-   "self_type" : "_ZTIP5cnode",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
   },
@@ -2420,7 +2372,6 @@
    "linker_set_key" : "_ZTIP7Hashmap",
    "name" : "Hashmap *",
    "referenced_type" : "_ZTI7Hashmap",
-   "self_type" : "_ZTIP7Hashmap",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
@@ -2429,7 +2380,6 @@
    "linker_set_key" : "_ZTIP9fs_config",
    "name" : "fs_config *",
    "referenced_type" : "_ZTI9fs_config",
-   "self_type" : "_ZTIP9fs_config",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/private/fs_config.h"
   },
@@ -2438,7 +2388,6 @@
    "linker_set_key" : "_ZTIP9str_parms",
    "name" : "str_parms *",
    "referenced_type" : "_ZTI9str_parms",
-   "self_type" : "_ZTIP9str_parms",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
   },
@@ -2447,7 +2396,6 @@
    "linker_set_key" : "_ZTIPFbPvS_E",
    "name" : "bool (*)(void *, void *)",
    "referenced_type" : "_ZTIFbPvS_E",
-   "self_type" : "_ZTIPFbPvS_E",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
@@ -2456,7 +2404,6 @@
    "linker_set_key" : "_ZTIPFbPvS_S_E",
    "name" : "bool (*)(void *, void *, void *)",
    "referenced_type" : "_ZTIFbPvS_S_E",
-   "self_type" : "_ZTIPFbPvS_S_E",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
@@ -2465,7 +2412,6 @@
    "linker_set_key" : "_ZTIPFiPvE",
    "name" : "int (*)(void *)",
    "referenced_type" : "_ZTIFiPvE",
-   "self_type" : "_ZTIPFiPvE",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
   },
@@ -2474,7 +2420,6 @@
    "linker_set_key" : "_ZTIPFvPKcS0_PvE",
    "name" : "void (*)(const char *, const char *, void *)",
    "referenced_type" : "_ZTIFvPKcS0_PvE",
-   "self_type" : "_ZTIPFvPKcS0_PvE",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/properties.h"
   },
@@ -2483,7 +2428,6 @@
    "linker_set_key" : "_ZTIPK13native_handle",
    "name" : "const native_handle *",
    "referenced_type" : "_ZTIK13native_handle",
-   "self_type" : "_ZTIPK13native_handle",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
   },
@@ -2492,7 +2436,6 @@
    "linker_set_key" : "_ZTIPK22cutils_socket_buffer_t",
    "name" : "const cutils_socket_buffer_t *",
    "referenced_type" : "_ZTIK22cutils_socket_buffer_t",
-   "self_type" : "_ZTIPK22cutils_socket_buffer_t",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/sockets.h"
   },
@@ -2501,7 +2444,6 @@
    "linker_set_key" : "_ZTIPK5iovec",
    "name" : "const iovec *",
    "referenced_type" : "_ZTIK5iovec",
-   "self_type" : "_ZTIPK5iovec",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/klog.h"
   },
@@ -2510,7 +2452,6 @@
    "linker_set_key" : "_ZTIPKc",
    "name" : "const char *",
    "referenced_type" : "_ZTIKc",
-   "self_type" : "_ZTIPKc",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
   },
@@ -2519,7 +2460,6 @@
    "linker_set_key" : "_ZTIPKv",
    "name" : "const void *",
    "referenced_type" : "_ZTIKv",
-   "self_type" : "_ZTIPKv",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/sockets.h"
   },
@@ -2528,7 +2468,6 @@
    "linker_set_key" : "_ZTIPPv",
    "name" : "void **",
    "referenced_type" : "_ZTIPv",
-   "self_type" : "_ZTIPPv",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
   },
@@ -2537,7 +2476,6 @@
    "linker_set_key" : "_ZTIPc",
    "name" : "char *",
    "referenced_type" : "_ZTIc",
-   "self_type" : "_ZTIPc",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
   },
@@ -2546,7 +2484,6 @@
    "linker_set_key" : "_ZTIPf",
    "name" : "float *",
    "referenced_type" : "_ZTIf",
-   "self_type" : "_ZTIPf",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
   },
@@ -2555,7 +2492,6 @@
    "linker_set_key" : "_ZTIPi",
    "name" : "int *",
    "referenced_type" : "_ZTIi",
-   "self_type" : "_ZTIPi",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h"
   },
@@ -2564,7 +2500,6 @@
    "linker_set_key" : "_ZTIPj",
    "name" : "unsigned int *",
    "referenced_type" : "_ZTIj",
-   "self_type" : "_ZTIPj",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/misc.h"
   },
@@ -2573,7 +2508,6 @@
    "linker_set_key" : "_ZTIPv",
    "name" : "void *",
    "referenced_type" : "_ZTIv",
-   "self_type" : "_ZTIPv",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/cutils/misc.h"
   },
@@ -2582,7 +2516,6 @@
    "linker_set_key" : "_ZTIPy",
    "name" : "unsigned long long *",
    "referenced_type" : "_ZTIy",
-   "self_type" : "_ZTIPy",
    "size" : 4,
    "source_file" : "system/core/libcutils/include/private/canned_fs_config.h"
   }
@@ -2595,7 +2528,6 @@
    "linker_set_key" : "_ZTIK13native_handle",
    "name" : "const native_handle",
    "referenced_type" : "_ZTI13native_handle",
-   "self_type" : "_ZTIK13native_handle",
    "size" : 12,
    "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
   },
@@ -2605,7 +2537,6 @@
    "linker_set_key" : "_ZTIK22cutils_socket_buffer_t",
    "name" : "const cutils_socket_buffer_t",
    "referenced_type" : "_ZTI22cutils_socket_buffer_t",
-   "self_type" : "_ZTIK22cutils_socket_buffer_t",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/sockets.h"
   },
@@ -2615,7 +2546,6 @@
    "linker_set_key" : "_ZTIK5iovec",
    "name" : "const iovec",
    "referenced_type" : "_ZTI5iovec",
-   "self_type" : "_ZTIK5iovec",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/klog.h"
   },
@@ -2625,7 +2555,6 @@
    "linker_set_key" : "_ZTIKc",
    "name" : "const char",
    "referenced_type" : "_ZTIc",
-   "self_type" : "_ZTIKc",
    "size" : 1,
    "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
   },
@@ -2634,7 +2563,6 @@
    "linker_set_key" : "_ZTIKv",
    "name" : "const void",
    "referenced_type" : "_ZTIv",
-   "self_type" : "_ZTIKv",
    "source_file" : "system/core/libcutils/include/cutils/sockets.h"
   }
  ],
@@ -2666,8 +2594,6 @@
    ],
    "linker_set_key" : "_ZTI13native_handle",
    "name" : "native_handle",
-   "referenced_type" : "_ZTI13native_handle",
-   "self_type" : "_ZTI13native_handle",
    "size" : 12,
    "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
   },
@@ -2687,8 +2613,6 @@
    ],
    "linker_set_key" : "_ZTI22cutils_socket_buffer_t",
    "name" : "cutils_socket_buffer_t",
-   "referenced_type" : "_ZTI22cutils_socket_buffer_t",
-   "self_type" : "_ZTI22cutils_socket_buffer_t",
    "size" : 8,
    "source_file" : "system/core/libcutils/include/cutils/sockets.h"
   },
@@ -2723,8 +2647,6 @@
    ],
    "linker_set_key" : "_ZTI5cnode",
    "name" : "cnode",
-   "referenced_type" : "_ZTI5cnode",
-   "self_type" : "_ZTI5cnode",
    "size" : 20,
    "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
   },
@@ -2754,8 +2676,6 @@
    ],
    "linker_set_key" : "_ZTI9fs_config",
    "name" : "fs_config",
-   "referenced_type" : "_ZTI9fs_config",
-   "self_type" : "_ZTI9fs_config",
    "size" : 24,
    "source_file" : "system/core/libcutils/include/private/fs_config.h"
   }
diff --git a/libcutils/include/cutils/uevent.h b/libcutils/include/cutils/uevent.h
index da1c2aa..1be981b 100644
--- a/libcutils/include/cutils/uevent.h
+++ b/libcutils/include/cutils/uevent.h
@@ -24,6 +24,8 @@
 extern "C" {
 #endif
 
+int uevent_create_socket(int buf_sz, bool passcred);
+int uevent_bind(int socket);
 int uevent_open_socket(int buf_sz, bool passcred);
 ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length);
 ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, size_t length, uid_t *uid);
diff --git a/libcutils/uevent.cpp b/libcutils/uevent.cpp
index 40bbd5c..f01a479 100644
--- a/libcutils/uevent.cpp
+++ b/libcutils/uevent.cpp
@@ -92,20 +92,22 @@
     return -1;
 }
 
-int uevent_open_socket(int buf_sz, bool passcred) {
-    struct sockaddr_nl addr;
-    int on = passcred;
+/*
+ * Creates an unbound netlink socket for receiving uevent messages.
+ * @buf_sz: socket receive buffer size.
+ * @passcred: whether or not to enable receiving the SCM_CREDENTIALS control
+ *	message.
+ *
+ * Returns: a socket descriptor upon success or -1 upon failure.
+ */
+int uevent_create_socket(int buf_sz, bool passcred) {
+    int s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
+    if (s < 0) {
+        return -1;
+    }
+
     int buf_sz_readback = 0;
     socklen_t optlen = sizeof(buf_sz_readback);
-    int s;
-
-    memset(&addr, 0, sizeof(addr));
-    addr.nl_family = AF_NETLINK;
-    addr.nl_pid = 0;
-    addr.nl_groups = 0xffffffff;
-
-    s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
-    if (s < 0) return -1;
 
     if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0 ||
           getsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz_readback, &optlen) < 0) {
@@ -123,9 +125,43 @@
         }
     }
 
+    int on = passcred;
+
     setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
 
-    if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+    return s;
+}
+
+/*
+ * Binds a netlink socket. Binding a netlink socket makes the kernel start
+ * sending netlink messages to that netlink socket.
+ *
+ * Returns: 0 upon success; -1 upon error.
+ */
+int uevent_bind(int socket) {
+    struct sockaddr_nl addr = {
+            .nl_family = AF_NETLINK,
+            .nl_pid = 0,
+            .nl_groups = 0xffffffff,
+    };
+    return bind(socket, (struct sockaddr*)&addr, sizeof(addr));
+}
+
+/*
+ * Creates a bound netlink socket for receiving uevent messages.
+ * @buf_sz: socket receive buffer size.
+ * @passcred: whether or not to enable receiving the SCM_CREDENTIALS control
+ *	message.
+ *
+ * Returns: a socket descriptor upon success or -1 upon failure.
+ */
+int uevent_open_socket(int buf_sz, bool passcred) {
+    int s = uevent_create_socket(buf_sz, passcred);
+    if (s < 0) {
+        return -1;
+    }
+
+    if (uevent_bind(s) < 0) {
         close(s);
         return -1;
     }
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index 1a40da1..8cc0b9b 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -447,7 +447,7 @@
 // Softdeps are taken care in InsmodWithDeps().
 bool Modprobe::LoadModulesParallel(int num_threads) {
     bool ret = true;
-    std::unordered_map<std::string, std::vector<std::string>> mod_with_deps;
+    std::map<std::string, std::vector<std::string>> mod_with_deps;
 
     // Get dependencies
     for (const auto& module : module_load_) {
diff --git a/libutils/include/utils/Trace.h b/libutils/include/utils/Trace.h
index 9986bf5..1809100 100644
--- a/libutils/include/utils/Trace.h
+++ b/libutils/include/utils/Trace.h
@@ -17,13 +17,6 @@
 #ifndef ANDROID_TRACE_H
 #define ANDROID_TRACE_H
 
-#if defined(_WIN32)
-
-#define ATRACE_NAME(...)
-#define ATRACE_CALL()
-
-#else  // !_WIN32
-
 #include <stdint.h>
 
 #include <cutils/trace.h>
@@ -56,6 +49,4 @@
 
 }  // namespace android
 
-#endif  // _WIN32
-
 #endif // ANDROID_TRACE_H
diff --git a/rootdir/Android.bp b/rootdir/Android.bp
index 7105ed5..1e7b48b 100644
--- a/rootdir/Android.bp
+++ b/rootdir/Android.bp
@@ -134,3 +134,58 @@
 sanitizer_libraries_txt {
     name: "sanitizer.libraries.txt",
 }
+
+EXPORT_GLOBAL_ASAN_OPTIONS = select(soong_config_variable("ANDROID", "ASAN_ENABLED"), {
+    true: "export ASAN_OPTIONS include=/system/asan.options",
+    default: "",
+})
+
+EXPORT_GLOBAL_HWASAN_OPTIONS = select(soong_config_variable("ANDROID", "HWASAN_ENABLED"), {
+    true: "export HWASAN_OPTIONS heap_history_size=1023,stack_history_size=512,export_memory_stats=0,max_malloc_fill_size=131072,malloc_fill_byte=0",
+    default: "",
+})
+
+EXPORT_GLOBAL_GCOV_OPTIONS = select(soong_config_variable("ANDROID", "GCOV_COVERAGE"), {
+    true: "export GCOV_PREFIX /data/misc/trace",
+    default: "",
+})
+
+EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS = select((soong_config_variable("ANDROID", "CLANG_COVERAGE"), soong_config_variable("ANDROID", "CLANG_COVERAGE_CONTINUOUS_MODE")), {
+    (true, true): "export LLVM_PROFILE_FILE /data/misc/trace/clang%c-%20m.profraw",
+    (true, default): "export LLVM_PROFILE_FILE /data/misc/trace/clang-%20m.profraw",
+    (default, default): "",
+})
+
+EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE = select(soong_config_variable("ANDROID", "SCUDO_ALLOCATION_RING_BUFFER_SIZE"), {
+    "": "",
+    any @ size: "export SCUDO_ALLOCATION_RING_BUFFER_SIZE " + size,
+    default: "",
+})
+
+genrule {
+    name: "init.environ.rc.gen",
+    srcs: ["init.environ.rc.in"],
+    out: ["init.environ.rc"],
+    cmd: "cp -f $(in) $(out) && " +
+        "echo '    " + EXPORT_GLOBAL_ASAN_OPTIONS + "' >> $(out) && " +
+        "echo '    " + EXPORT_GLOBAL_GCOV_OPTIONS + "' >> $(out) && " +
+        "echo '    " + EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS + "' >> $(out) && " +
+        "echo '    " + EXPORT_GLOBAL_HWASAN_OPTIONS + "' >> $(out) && " +
+        "echo '    " + EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE + "' >> $(out)",
+}
+
+prebuilt_root {
+    name: "init.environ.rc-soong",
+    src: ":init.environ.rc.gen",
+    filename: "init.environ.rc",
+    install_in_root: true,
+    no_full_install: true,
+    required: select((soong_config_variable("ANDROID", "ASAN_ENABLED"), soong_config_variable("ANDROID", "SANITIZE_TARGET_SYSTEM_ENABLED")), {
+        (true, true): [
+            "asan.options",
+            "asan_extract",
+        ],
+        (true, default): ["asan.options"],
+        (default, default): [],
+    }),
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e6ccda7..e743743 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -11,6 +11,7 @@
 endif
 #######################################
 # init.environ.rc
+# TODO(b/353429422): move LOCAL_POST_INSTALL_CMD to other rules and remove Android.mk module.
 
 include $(CLEAR_VARS)
 LOCAL_MODULE_CLASS := ETC
@@ -19,36 +20,8 @@
 LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
 
-EXPORT_GLOBAL_ASAN_OPTIONS :=
 ifneq ($(filter address,$(SANITIZE_TARGET)),)
-  EXPORT_GLOBAL_ASAN_OPTIONS := export ASAN_OPTIONS include=/system/asan.options
-  LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES) $(ASAN_EXTRACT_FILES)
-endif
-
-EXPORT_GLOBAL_HWASAN_OPTIONS :=
-ifneq ($(filter hwaddress,$(SANITIZE_TARGET)),)
-  ifneq ($(HWADDRESS_SANITIZER_GLOBAL_OPTIONS),)
-    EXPORT_GLOBAL_HWASAN_OPTIONS := export HWASAN_OPTIONS $(HWADDRESS_SANITIZER_GLOBAL_OPTIONS)
-  endif
-endif
-
-EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE :=
-ifneq ($(PRODUCT_SCUDO_ALLOCATION_RING_BUFFER_SIZE),)
-  EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE := export SCUDO_ALLOCATION_RING_BUFFER_SIZE $(PRODUCT_SCUDO_ALLOCATION_RING_BUFFER_SIZE)
-endif
-
-EXPORT_GLOBAL_GCOV_OPTIONS :=
-ifeq ($(NATIVE_COVERAGE),true)
-  EXPORT_GLOBAL_GCOV_OPTIONS := export GCOV_PREFIX /data/misc/trace
-endif
-
-EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS :=
-ifeq ($(CLANG_COVERAGE),true)
-  ifeq ($(CLANG_COVERAGE_CONTINUOUS_MODE),true)
-    EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS := export LLVM_PROFILE_FILE /data/misc/trace/clang%c-%20m.profraw
-  else
-    EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS := export LLVM_PROFILE_FILE /data/misc/trace/clang-%20m.profraw
-  endif
+  LOCAL_REQUIRED_MODULES := asan.options $(ASAN_EXTRACT_FILES)
 endif
 
 # Put it here instead of in init.rc module definition,
@@ -173,15 +146,10 @@
 include $(BUILD_SYSTEM)/base_rules.mk
 
 $(ALL_ROOTDIR_SYMLINKS): $(LOCAL_BUILT_MODULE)
-$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in
-	@echo "Generate: $< -> $@"
-	@mkdir -p $(dir $@)
-	$(hide) cp $< $@
-	$(hide) sed -i -e 's?%EXPORT_GLOBAL_ASAN_OPTIONS%?$(EXPORT_GLOBAL_ASAN_OPTIONS)?g' $@
-	$(hide) sed -i -e 's?%EXPORT_GLOBAL_GCOV_OPTIONS%?$(EXPORT_GLOBAL_GCOV_OPTIONS)?g' $@
-	$(hide) sed -i -e 's?%EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS%?$(EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS)?g' $@
-	$(hide) sed -i -e 's?%EXPORT_GLOBAL_HWASAN_OPTIONS%?$(EXPORT_GLOBAL_HWASAN_OPTIONS)?g' $@
-	$(hide) sed -i -e 's?%EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE%?$(EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE)?g' $@
+
+init.environ.rc-soong := $(call intermediates-dir-for,ETC,init.environ.rc-soong)/init.environ.rc-soong
+$(eval $(call copy-one-file,$(init.environ.rc-soong),$(LOCAL_BUILT_MODULE)))
+init.environ.rc-soong :=
 
 #######################################
 # ramdisk_node_list
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 7ba1f46..9249270 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -10,8 +10,5 @@
     export ANDROID_TZDATA_ROOT /apex/com.android.tzdata
     export EXTERNAL_STORAGE /sdcard
     export ASEC_MOUNTPOINT /mnt/asec
-    %EXPORT_GLOBAL_ASAN_OPTIONS%
-    %EXPORT_GLOBAL_GCOV_OPTIONS%
-    %EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS%
-    %EXPORT_GLOBAL_HWASAN_OPTIONS%
-    %EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE%
+    # Additional environment variables will be appended here during build (see Android.bp).
+    # DO NOT ADD additional sections like 'on <event>' here.
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b804c1b..7c089c2 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -648,6 +648,14 @@
     chmod 0755 /sys/kernel/tracing
     chmod 0755 /sys/kernel/debug/tracing
 
+    # Early HALs may use early VM. Mount /mnt/vm before starting such HALs.
+    mkdir /mnt/vm 0755 root root
+    mount tmpfs tmpfs /mnt/vm nosuid nodev noexec rw
+    restorecon /mnt/vm
+    chown system system /mnt/vm
+    chmod 0770 /mnt/vm
+    mkdir /mnt/vm/early 0770 system system
+
     # HALs required before storage encryption can get unlocked (FBE)
     class_start early_hal
 
diff --git a/trusty/gatekeeper/service.cpp b/trusty/gatekeeper/service.cpp
index d09804f..59366b8 100644
--- a/trusty/gatekeeper/service.cpp
+++ b/trusty/gatekeeper/service.cpp
@@ -18,12 +18,66 @@
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
+#include <getopt.h>
 
 #include "trusty_gatekeeper.h"
+#include "trusty_gatekeeper_ipc.h"
 
 using aidl::android::hardware::gatekeeper::TrustyGateKeeperDevice;
 
-int main() {
+static const char* _sopts = "hD:";
+static const struct option _lopts[] = {
+        {"help", no_argument, 0, 'h'},
+        {"dev", required_argument, 0, 'D'},
+        {0, 0, 0, 0},
+};
+
+static const char* usage =
+        "Usage: %s [options]\n"
+        "\n"
+        "options:\n"
+        "  -h, --help            prints this message and exit\n"
+        "  -D, --dev name        Trusty device name\n"
+        "\n";
+
+static const char* usage_long = "\n";
+
+static void print_usage_and_exit(const char* prog, int code, bool verbose) {
+    fprintf(stderr, usage, prog);
+    if (verbose) {
+        fprintf(stderr, "%s", usage_long);
+    }
+    exit(code);
+}
+
+static void parse_options(int argc, char** argv) {
+    int c;
+    int oidx = 0;
+
+    while (1) {
+        c = getopt_long(argc, argv, _sopts, _lopts, &oidx);
+        if (c == -1) {
+            break; /* done */
+        }
+
+        switch (c) {
+            case 'D':
+                trusty_gatekeeper_set_dev_name(optarg);
+                break;
+
+            case 'h':
+                print_usage_and_exit(argv[0], EXIT_SUCCESS, true);
+                break;
+
+            default:
+                print_usage_and_exit(argv[0], EXIT_FAILURE, false);
+        }
+    }
+}
+
+int main(int argc, char** argv) {
+    parse_options(argc, argv);
+
     ABinderProcess_setThreadPoolMaxThreadCount(0);
 
     std::shared_ptr<TrustyGateKeeperDevice> gatekeeper =
diff --git a/trusty/gatekeeper/trusty_gatekeeper_ipc.c b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
index f67944b..5ca951c 100644
--- a/trusty/gatekeeper/trusty_gatekeeper_ipc.c
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
@@ -28,12 +28,15 @@
 #include "trusty_gatekeeper_ipc.h"
 #include "gatekeeper_ipc.h"
 
-#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
-
+static const char* trusty_device_name = "/dev/trusty-ipc-dev0";
 static int handle_ = 0;
 
+void trusty_gatekeeper_set_dev_name(const char* device_name) {
+    trusty_device_name = device_name;
+}
+
 int trusty_gatekeeper_connect() {
-    int rc = tipc_connect(TRUSTY_DEVICE_NAME, GATEKEEPER_PORT);
+    int rc = tipc_connect(trusty_device_name, GATEKEEPER_PORT);
     if (rc < 0) {
         return rc;
     }
diff --git a/trusty/gatekeeper/trusty_gatekeeper_ipc.h b/trusty/gatekeeper/trusty_gatekeeper_ipc.h
index f8de7f8..47ba33b 100644
--- a/trusty/gatekeeper/trusty_gatekeeper_ipc.h
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.h
@@ -16,6 +16,7 @@
 
 __BEGIN_DECLS
 
+void trusty_gatekeeper_set_dev_name(const char* device_name);
 int trusty_gatekeeper_connect();
 int trusty_gatekeeper_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
                            uint32_t *out_size);
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index b249013..aca59b6 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -44,7 +44,7 @@
         "libtrusty",
         "libkeymaster_messages",
         "libkeymaster3device",
-        "android.hardware.keymaster@3.0"
+        "android.hardware.keymaster@3.0",
     ],
 }
 
@@ -74,7 +74,7 @@
         "libtrusty",
         "libkeymaster_messages",
         "libkeymaster4",
-        "android.hardware.keymaster@4.0"
+        "android.hardware.keymaster@4.0",
     ],
 
     vintf_fragments: ["4.0/android.hardware.keymaster@4.0-service.trusty.xml"],
@@ -208,3 +208,36 @@
         "-Werror",
     ],
 }
+
+prebuilt_etc {
+    name: "rkp_uds_cert_test.xml",
+    vendor: true,
+    src: "set_uds_certs/rkp_uds_cert_test.xml",
+}
+
+cc_binary {
+    name: "trusty_rkp_set_uds_cert",
+    vendor: true,
+
+    srcs: [
+        "set_uds_certs/set_uds_certificates.cpp",
+        "ipc/trusty_keymaster_ipc.cpp",
+    ],
+
+    local_include_dirs: ["include"],
+
+    shared_libs: [
+        "libc",
+        "libcrypto",
+        "liblog",
+        "libtrusty",
+        "libhardware",
+        "libkeymaster_messages",
+        "libutils",
+        "libxml2",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index 09f696b..822e933 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -78,6 +78,8 @@
     KM_SET_ATTESTATION_IDS = (0xc000 << KEYMASTER_REQ_SHIFT),
     KM_SET_ATTESTATION_IDS_KM3 = (0xc001 << KEYMASTER_REQ_SHIFT),
     KM_CONFIGURE_BOOT_PATCHLEVEL = (0xd000 << KEYMASTER_REQ_SHIFT),
+    KM_APPEND_UDS_CERT_CHAIN = (0xe0000 << KEYMASTER_REQ_SHIFT),
+    KM_CLEAR_UDS_CERT_CHAIN = (0xe0001 << KEYMASTER_REQ_SHIFT),
 };
 
 #ifdef __ANDROID__
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/trusty_keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/trusty_keymaster_ipc.h
index efad254..15241f4 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/trusty_keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/trusty_keymaster_ipc.h
@@ -26,6 +26,7 @@
 const uint32_t TRUSTY_KEYMASTER_SEND_BUF_SIZE =
         (4096 - sizeof(struct keymaster_message) - 16 /* tipc header */);
 
+void trusty_keymaster_set_dev_name(const char* device_name);
 int trusty_keymaster_connect(void);
 int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
                           uint32_t* out_size);
diff --git a/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp b/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
index db1a9f4..c01877f 100644
--- a/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
+++ b/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
@@ -36,15 +36,18 @@
 #include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
 #include <utils/Timers.h>
 
-#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
+static const char* trusty_device_name = "/dev/trusty-ipc-dev0";
 
 static int handle_ = -1;
 
 static const int timeout_ms = 10 * 1000;
 static const int max_timeout_ms = 60 * 1000;
 
+void trusty_keymaster_set_dev_name(const char* device_name) {
+    trusty_device_name = device_name;
+}
 int trusty_keymaster_connect() {
-    int rc = tipc_connect(TRUSTY_DEVICE_NAME, KEYMASTER_PORT);
+    int rc = tipc_connect(trusty_device_name, KEYMASTER_PORT);
     if (rc < 0) {
         return rc;
     }
diff --git a/trusty/keymaster/keymint/service.cpp b/trusty/keymaster/keymint/service.cpp
index 14549d2..583d840 100644
--- a/trusty/keymaster/keymint/service.cpp
+++ b/trusty/keymaster/keymint/service.cpp
@@ -18,11 +18,13 @@
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
+#include <getopt.h>
 
 #include <trusty_keymaster/TrustyKeyMintDevice.h>
 #include <trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h>
 #include <trusty_keymaster/TrustySecureClock.h>
 #include <trusty_keymaster/TrustySharedSecret.h>
+#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
 
 using aidl::android::hardware::security::keymint::trusty::TrustyKeyMintDevice;
 using aidl::android::hardware::security::keymint::trusty::TrustyRemotelyProvisionedComponentDevice;
@@ -39,7 +41,58 @@
     return service;
 }
 
-int main() {
+static const char* _sopts = "hD:";
+static const struct option _lopts[] = {
+        {"help", no_argument, 0, 'h'},
+        {"dev", required_argument, 0, 'D'},
+        {0, 0, 0, 0},
+};
+
+static const char* usage =
+        "Usage: %s [options]\n"
+        "\n"
+        "options:\n"
+        "  -h, --help            prints this message and exit\n"
+        "  -D, --dev name        Trusty device name\n"
+        "\n";
+
+static const char* usage_long = "\n";
+
+static void print_usage_and_exit(const char* prog, int code, bool verbose) {
+    fprintf(stderr, usage, prog);
+    if (verbose) {
+        fprintf(stderr, "%s", usage_long);
+    }
+    exit(code);
+}
+
+static void parse_options(int argc, char** argv) {
+    int c;
+    int oidx = 0;
+
+    while (1) {
+        c = getopt_long(argc, argv, _sopts, _lopts, &oidx);
+        if (c == -1) {
+            break; /* done */
+        }
+
+        switch (c) {
+            case 'D':
+                trusty_keymaster_set_dev_name(optarg);
+                break;
+
+            case 'h':
+                print_usage_and_exit(argv[0], EXIT_SUCCESS, true);
+                break;
+
+            default:
+                print_usage_and_exit(argv[0], EXIT_FAILURE, false);
+        }
+    }
+}
+
+int main(int argc, char** argv) {
+    parse_options(argc, argv);
     auto trustyKeymaster = std::make_shared<keymaster::TrustyKeymaster>();
     int err = trustyKeymaster->Initialize(keymaster::KmVersion::KEYMINT_3);
     if (err != 0) {
diff --git a/trusty/keymaster/set_uds_certs/rkp_uds_cert_test.xml b/trusty/keymaster/set_uds_certs/rkp_uds_cert_test.xml
new file mode 100644
index 0000000..73b7b4c
--- /dev/null
+++ b/trusty/keymaster/set_uds_certs/rkp_uds_cert_test.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<PixelUdsCertificates>
+  <CertificateChain>
+    <NumberOfCertificates>3</NumberOfCertificates>
+    <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIIBWTCB3qADAgECAgUA3q2+7zAMBggqhkjOPQQDAwUAMBIxEDAOBgNVBAMMB0dT
+TUkxLjAwIhgPMjAyNDAxMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowEjEQMA4G
+A1UEAwwHR1NNSTEuMDB2MBAGByqGSM49AgEGBSuBBAAiA2IABFsNPdsPmx2NKNiT
+7oReF36HTXjftRfGffYgPf/vEhrT7XLJ7dThkcb+OFYWYlOckdk3DRgqTNWQXsot
+UsZhwRveU8huEjOBO5+dwDiWPs+s9jSRAn5inlTqJ0YGAmdHRzAMBggqhkjOPQQD
+AwUAA2gAMGUCMQCuiJwmRWOgfWbqdSlnXfhCbphjdWc6sHelLkkM21vxQ3RZkhC2
+ERh90RA1rxB+XTgCMHZrYG3leS0PEoz5hUviv27LbBHBU6GeOzrS2e0VH0BMSNXN
+iP9Wnit+mJw58niEGw==
+-----END CERTIFICATE-----
+    </Certificate>
+    <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIIBWTCB3qADAgECAgUA3q2+7zAMBggqhkjOPQQDAwUAMBIxEDAOBgNVBAMMB0dT
+TUkxLjAwIhgPMjAyNDAxMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowEjEQMA4G
+A1UEAwwHR1NNSTEuMDB2MBAGByqGSM49AgEGBSuBBAAiA2IABFsNPdsPmx2NKNiT
+7oReF36HTXjftRfGffYgPf/vEhrT7XLJ7dThkcb+OFYWYlOckdk3DRgqTNWQXsot
+UsZhwRveU8huEjOBO5+dwDiWPs+s9jSRAn5inlTqJ0YGAmdHRzAMBggqhkjOPQQD
+AwUAA2gAMGUCMQCuiJwmRWOgfWbqdSlnXfhCbphjdWc6sHelLkkM21vxQ3RZkhC2
+ERh90RA1rxB+XTgCMHZrYG3leS0PEoz5hUviv27LbBHBU6GeOzrS2e0VH0BMSNXN
+iP9Wnit+mJw58niEGw==
+-----END CERTIFICATE-----
+    </Certificate>
+    <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIIBWTCB3qADAgECAgUA3q2+7zAMBggqhkjOPQQDAwUAMBIxEDAOBgNVBAMMB0dT
+TUkxLjAwIhgPMjAyNDAxMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowEjEQMA4G
+A1UEAwwHR1NNSTEuMDB2MBAGByqGSM49AgEGBSuBBAAiA2IABFsNPdsPmx2NKNiT
+7oReF36HTXjftRfGffYgPf/vEhrT7XLJ7dThkcb+OFYWYlOckdk3DRgqTNWQXsot
+UsZhwRveU8huEjOBO5+dwDiWPs+s9jSRAn5inlTqJ0YGAmdHRzAMBggqhkjOPQQD
+AwUAA2gAMGUCMQCuiJwmRWOgfWbqdSlnXfhCbphjdWc6sHelLkkM21vxQ3RZkhC2
+ERh90RA1rxB+XTgCMHZrYG3leS0PEoz5hUviv27LbBHBU6GeOzrS2e0VH0BMSNXN
+iP9Wnit+mJw58niEGw==
+-----END CERTIFICATE-----
+    </Certificate>
+  </CertificateChain>
+</PixelUdsCertificates>
diff --git a/trusty/keymaster/set_uds_certs/set_uds_certificates.cpp b/trusty/keymaster/set_uds_certs/set_uds_certificates.cpp
new file mode 100644
index 0000000..13356a9
--- /dev/null
+++ b/trusty/keymaster/set_uds_certs/set_uds_certificates.cpp
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2020 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 <errno.h>
+#include <getopt.h>
+#include <libxml/xmlreader.h>
+#include <openssl/pem.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <string>
+
+#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
+
+static const char* _sopts = "h";
+static const struct option _lopts[] = {
+        {"help", no_argument, 0, 'h'},
+        {0, 0, 0, 0},
+};
+
+static const char* usage =
+        "Usage: %s [options] xml-file\n"
+        "\n"
+        "options:\n"
+        "  -h, --help            prints this message and exit\n"
+        "\n";
+
+static void print_usage_and_exit(const char* prog, int code) {
+    fprintf(stderr, usage, prog);
+    exit(code);
+}
+
+static void parse_options(int argc, char** argv) {
+    int c;
+    int oidx = 0;
+
+    while (1) {
+        c = getopt_long(argc, argv, _sopts, _lopts, &oidx);
+        if (c == -1) {
+            break; /* done */
+        }
+
+        switch (c) {
+            case 'h':
+                print_usage_and_exit(argv[0], EXIT_SUCCESS);
+                break;
+
+            default:
+                print_usage_and_exit(argv[0], EXIT_FAILURE);
+        }
+    }
+}
+
+struct AppendUdsCertificateRequest : public keymaster::KeymasterMessage {
+    explicit AppendUdsCertificateRequest(int32_t ver = keymaster::kDefaultMessageVersion)
+        : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return cert_data.SerializedSize(); }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        return cert_data.Serialize(buf, end);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return cert_data.Deserialize(buf_ptr, end);
+    }
+
+    keymaster::Buffer cert_data;
+};
+
+struct ClearUdsCertificateRequest : public keymaster::KeymasterMessage {
+    explicit ClearUdsCertificateRequest(int32_t ver = keymaster::kDefaultMessageVersion)
+        : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return 0; }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool Deserialize(const uint8_t**, const uint8_t*) override { return true; };
+};
+
+struct KeymasterNoResponse : public keymaster::KeymasterResponse{
+    explicit KeymasterNoResponse(int32_t ver = keymaster::kDefaultMessageVersion)
+        : keymaster::KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override { return 0; }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
+};
+
+struct AppendUdsCertificateResponse : public KeymasterNoResponse {};
+struct ClearUdsCertificateResponse : public KeymasterNoResponse {};
+
+static int set_uds_cert_bin(uint32_t cmd, const void* cert_data, size_t cert_data_size) {
+    int ret;
+
+    AppendUdsCertificateRequest req;
+    req.cert_data.Reinitialize(cert_data, cert_data_size);
+    AppendUdsCertificateResponse rsp;
+
+    ret = trusty_keymaster_send(cmd, req, &rsp);
+    if (ret) {
+        fprintf(stderr, "trusty_keymaster_send cmd 0x%x failed %d\n", cmd, ret);
+        return ret;
+    }
+
+    return 0;
+}
+
+static int set_uds_cert_pem(uint32_t cmd, const xmlChar* pemkey) {
+    int ret;
+    int sslret;
+
+    /* Convert from pem to binary */
+    BIO* bio = BIO_new_mem_buf(pemkey, xmlStrlen(pemkey));
+    if (!bio) {
+        fprintf(stderr, "BIO_new_mem_buf failed\n");
+        ERR_print_errors_fp(stderr);
+        return -1;
+    }
+
+    char* key_name;
+    char* key_header;
+    uint8_t* key;
+    long keylen;
+    sslret = PEM_read_bio(bio, &key_name, &key_header, &key, &keylen);
+    BIO_free(bio);
+
+    if (!sslret) {
+        fprintf(stderr, "PEM_read_bio failed\n");
+        ERR_print_errors_fp(stderr);
+        return -1;
+    }
+
+    /* Send key in binary format to trusty */
+    ret = set_uds_cert_bin(cmd, key, keylen);
+
+    OPENSSL_free(key_name);
+    OPENSSL_free(key_header);
+    OPENSSL_free(key);
+
+    return ret;
+}
+
+static int set_uds_cert(uint32_t cmd, const xmlChar* format, const xmlChar* str) {
+    int ret;
+
+    if (xmlStrEqual(format, BAD_CAST "pem")) {
+        ret = set_uds_cert_pem(cmd, str);
+    } else {
+        printf("unsupported key/cert format: %s\n", format);
+        return -1;
+    }
+    return ret;
+}
+
+// TODO: Guard by Production Mode
+static int clear_cert_chain() {
+    int ret;
+    ClearUdsCertificateRequest req;
+    ClearUdsCertificateResponse rsp;
+
+    ret = trusty_keymaster_send(KM_CLEAR_UDS_CERT_CHAIN, req, &rsp);
+    if (ret) {
+        fprintf(stderr, "%s: trusty_keymaster_send failed %d\n", __func__, ret);
+        return ret;
+    }
+    return 0;
+}
+
+static int process_xml(xmlTextReaderPtr xml) {
+    int ret;
+    const xmlChar* element = NULL;
+    const xmlChar* element_format = NULL;
+    bool isPixelUdsCert = false;
+
+    while ((ret = xmlTextReaderRead(xml)) == 1) {
+        int nodetype = xmlTextReaderNodeType(xml);
+        const xmlChar *name, *value;
+        name = xmlTextReaderConstName(xml);
+        switch (nodetype) {
+            case XML_READER_TYPE_ELEMENT:
+                element = name;
+                element_format = xmlTextReaderGetAttribute(xml, BAD_CAST "format");
+                if (isPixelUdsCert || xmlStrEqual(name, BAD_CAST "PixelUdsCertificates")) {
+                    // The first element name must be "PixelUdsCertificates"
+                    isPixelUdsCert = true;
+                } else {
+                    fprintf(stderr, "Not a PixelUdsCertificates: \"%s\"\n", name);
+                    return -1;
+                }
+                if (xmlStrEqual(name, BAD_CAST "CertificateChain")) {
+                    ret = clear_cert_chain();
+                    if (ret) {
+                        fprintf(stderr, "%s: Clear cert chain cmd failed, %d\n", element, ret);
+                        return ret;
+                    }
+                    printf("%s: Clear cert chain cmd done\n", element);
+                }
+                break;
+            case XML_READER_TYPE_TEXT:
+                value = xmlTextReaderConstValue(xml);
+                uint32_t cmd;
+                if (xmlStrEqual(element, BAD_CAST "Certificate")) {
+                    cmd = KM_APPEND_UDS_CERT_CHAIN;
+                } else {
+                    break;
+                }
+
+                ret = set_uds_cert(cmd, element_format, value);
+                if (ret) {
+                    fprintf(stderr, "%s, format %s: Cmd 0x%x failed, %d\n", element, element_format,
+                            cmd, ret);
+                    return ret;
+                }
+                printf("%s, format %s: Cmd 0x%x done\n", element, element_format, cmd);
+                break;
+            case XML_READER_TYPE_END_ELEMENT:
+                element = NULL;
+                break;
+        }
+    }
+    return ret;
+}
+
+static int parse_and_provision_xml_file(const char* filename) {
+    int ret;
+    xmlTextReaderPtr xml = xmlReaderForFile(filename, NULL, 0);
+    if (!xml) {
+        fprintf(stderr, "failed to open %s\n", filename);
+        return -1;
+    }
+
+    ret = process_xml(xml);
+
+    xmlFreeTextReader(xml);
+    if (ret != 0) {
+        fprintf(stderr, "Failed to parse or process %s\n", filename);
+        return -1;
+    }
+
+    return 0;
+}
+
+int main(int argc, char** argv) {
+    int ret = 0;
+
+    parse_options(argc, argv);
+    if (optind + 1 != argc) {
+        print_usage_and_exit(argv[0], EXIT_FAILURE);
+    }
+
+    ret = trusty_keymaster_connect();
+    if (ret) {
+        fprintf(stderr, "trusty_keymaster_connect failed %d\n", ret);
+        return EXIT_FAILURE;
+    }
+
+    ret = parse_and_provision_xml_file(argv[optind]);
+    if (ret) {
+        fprintf(stderr, "parse_and_provision_xml_file failed %d\n", ret);
+        trusty_keymaster_disconnect();
+        return EXIT_FAILURE;
+    }
+
+    return EXIT_SUCCESS;
+}
diff --git a/trusty/keymint/Android.bp b/trusty/keymint/Android.bp
index 19dcc98..92d9c6f 100644
--- a/trusty/keymint/Android.bp
+++ b/trusty/keymint/Android.bp
@@ -24,11 +24,12 @@
     init_rc: ["android.hardware.security.keymint-service.rust.trusty.rc"],
     vintf_fragments: ["android.hardware.security.keymint-service.rust.trusty.xml"],
     srcs: [
-        "src/keymint_hal_main.rs"
+        "src/keymint_hal_main.rs",
     ],
     rustlibs: [
         "libandroid_logger",
         "libbinder_rs",
+        "libclap",
         "libkmr_wire",
         "libkmr_hal",
         "libtrusty-rs",
diff --git a/trusty/keymint/src/keymint_hal_main.rs b/trusty/keymint/src/keymint_hal_main.rs
index ef0c598..3c5627b 100644
--- a/trusty/keymint/src/keymint_hal_main.rs
+++ b/trusty/keymint/src/keymint_hal_main.rs
@@ -14,6 +14,7 @@
 // limitations under the License.
 
 //! This module implements the HAL service for Keymint (Rust) in Trusty.
+use clap::Parser;
 use kmr_hal::{
     extract_rsp, keymint, rpc, secureclock, send_hal_info, sharedsecret, SerializedChannel,
 };
@@ -81,6 +82,13 @@
     }
 }
 
+#[derive(Parser, Debug)]
+struct Args {
+    /// Tipc device path
+    #[arg(short, long, default_value_t = DEFAULT_DEVICE.to_string())]
+    dev: String,
+}
+
 fn main() {
     if let Err(HalServiceError(e)) = inner_main() {
         panic!("HAL service failed: {:?}", e);
@@ -88,6 +96,7 @@
 }
 
 fn inner_main() -> Result<(), HalServiceError> {
+    let args = Args::parse();
     // Initialize Android logging.
     android_logger::init_once(
         android_logger::Config::default()
@@ -106,10 +115,15 @@
     binder::ProcessState::start_thread_pool();
 
     // Create connection to the TA
-    let connection = trusty::TipcChannel::connect(DEFAULT_DEVICE, TRUSTY_KEYMINT_RUST_SERVICE_NAME)
-        .map_err(|e| {
-            HalServiceError(format!("Failed to connect to Trusty Keymint TA because of {:?}.", e))
-        })?;
+    let connection =
+        trusty::TipcChannel::connect(args.dev.as_str(), TRUSTY_KEYMINT_RUST_SERVICE_NAME).map_err(
+            |e| {
+                HalServiceError(format!(
+                    "Failed to connect to Trusty Keymint TA at {} because of {:?}.",
+                    args.dev, e
+                ))
+            },
+        )?;
     let tipc_channel = Arc::new(Mutex::new(TipcChannel(connection)));
 
     // Register the Keymint service