Merge "Add an ABI dump directory for libutils"
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 46190f2..f1b82e9 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -129,23 +129,23 @@
 };
 
 struct Image {
-    const char* nickname;
-    const char* img_name;
-    const char* sig_name;
-    const char* part_name;
+    std::string nickname;
+    std::string img_name;
+    std::string sig_name;
+    std::string part_name;
     bool optional_if_no_image;
     ImageType type;
-    bool IsSecondary() const { return nickname == nullptr; }
+    bool IsSecondary() const { return nickname.empty(); }
 };
 
-static Image images[] = {
+static std::vector<Image> images = {
         // clang-format off
     { "boot",     "boot.img",         "boot.sig",     "boot",     false, ImageType::BootCritical },
     { "init_boot",
                   "init_boot.img",    "init_boot.sig",
                                                       "init_boot",
                                                                   true,  ImageType::BootCritical },
-    { nullptr,    "boot_other.img",   "boot.sig",     "boot",     true,  ImageType::Normal },
+    { "",    "boot_other.img",   "boot.sig",     "boot",     true,  ImageType::Normal },
     { "cache",    "cache.img",        "cache.sig",    "cache",    true,  ImageType::Extra },
     { "dtbo",     "dtbo.img",         "dtbo.sig",     "dtbo",     true,  ImageType::BootCritical },
     { "dts",      "dt.img",           "dt.sig",       "dts",      true,  ImageType::BootCritical },
@@ -164,7 +164,7 @@
                   "system_ext.img",   "system_ext.sig",
                                                       "system_ext",
                                                                   true,  ImageType::Normal },
-    { nullptr,    "system_other.img", "system.sig",   "system",   true,  ImageType::Normal },
+    { "",    "system_other.img", "system.sig",   "system",   true,  ImageType::Normal },
     { "userdata", "userdata.img",     "userdata.sig", "userdata", true,  ImageType::Extra },
     { "vbmeta",   "vbmeta.img",       "vbmeta.sig",   "vbmeta",   true,  ImageType::BootCritical },
     { "vbmeta_system",
@@ -191,7 +191,7 @@
                                       "vendor_kernel_boot.sig",
                                                       "vendor_kernel_boot",
                                                                   true,  ImageType::BootCritical },
-    { nullptr,    "vendor_other.img", "vendor.sig",   "vendor",   true,  ImageType::Normal },
+    { "",    "vendor_other.img", "vendor.sig",   "vendor",   true,  ImageType::Normal },
         // clang-format on
 };
 
@@ -212,8 +212,8 @@
 }
 
 static std::string find_item(const std::string& item) {
-    for (size_t i = 0; i < arraysize(images); ++i) {
-        if (images[i].nickname && item == images[i].nickname) {
+    for (size_t i = 0; i < images.size(); ++i) {
+        if (!images[i].nickname.empty() && item == images[i].nickname) {
             return find_item_given_name(images[i].img_name);
         }
     }
@@ -274,7 +274,8 @@
     // require matching serial number or device path if requested
     // at the command line with the -s option.
     if (local_serial && (strcmp(local_serial, info->serial_number) != 0 &&
-                   strcmp(local_serial, info->device_path) != 0)) return -1;
+                         strcmp(local_serial, info->device_path) != 0))
+        return -1;
     return 0;
 }
 
@@ -532,15 +533,15 @@
     std::vector<char> dtb_data;
     if (!g_dtb_path.empty()) {
         if (g_boot_img_hdr.header_version != 2) {
-                    die("Argument dtb not supported for boot image header version %d\n",
-                        g_boot_img_hdr.header_version);
+            die("Argument dtb not supported for boot image header version %d\n",
+                g_boot_img_hdr.header_version);
         }
         if (!ReadFileToVector(g_dtb_path, &dtb_data)) {
             die("cannot load '%s': %s", g_dtb_path.c_str(), strerror(errno));
         }
     }
 
-    fprintf(stderr,"creating boot image...\n");
+    fprintf(stderr, "creating boot image...\n");
 
     std::vector<char> out;
     mkbootimg(kernel_data, ramdisk_data, second_stage_data, dtb_data, g_base_addr, g_boot_img_hdr,
@@ -562,15 +563,15 @@
     }
 
     if (zip_entry.uncompressed_length > std::numeric_limits<size_t>::max()) {
-      die("entry '%s' is too large: %" PRIu64, entry_name.c_str(), zip_entry.uncompressed_length);
+        die("entry '%s' is too large: %" PRIu64, entry_name.c_str(), zip_entry.uncompressed_length);
     }
     out->resize(zip_entry.uncompressed_length);
 
     fprintf(stderr, "extracting %s (%zu MB) to RAM...\n", entry_name.c_str(),
             out->size() / 1024 / 1024);
 
-    int error = ExtractToMemory(zip, &zip_entry, reinterpret_cast<uint8_t*>(out->data()),
-                                out->size());
+    int error =
+            ExtractToMemory(zip, &zip_entry, reinterpret_cast<uint8_t*>(out->data()), out->size());
     if (error != 0) die("failed to extract '%s': %s", entry_name.c_str(), ErrorCodeString(error));
 
     return true;
@@ -618,8 +619,8 @@
     std::string path_template(make_temporary_template());
     int fd = mkstemp(&path_template[0]);
     if (fd == -1) {
-        die("failed to create temporary file for %s with template %s: %s\n",
-            path_template.c_str(), what, strerror(errno));
+        die("failed to create temporary file for %s with template %s: %s\n", path_template.c_str(),
+            what, strerror(errno));
     }
     unlink(path_template.c_str());
     return fd;
@@ -673,16 +674,15 @@
     std::string var_value;
     if (fb->GetVar(var, &var_value) != fastboot::SUCCESS) {
         fprintf(stderr, "FAILED\n\n");
-        fprintf(stderr, "Could not getvar for '%s' (%s)\n\n", var.c_str(),
-                fb->Error().c_str());
+        fprintf(stderr, "Could not getvar for '%s' (%s)\n\n", var.c_str(), fb->Error().c_str());
         return false;
     }
 
     bool match = false;
     for (const auto& option : options) {
-        if (option == var_value || (option.back() == '*' &&
-                                    !var_value.compare(0, option.length() - 1, option, 0,
-                                                       option.length() - 1))) {
+        if (option == var_value ||
+            (option.back() == '*' &&
+             !var_value.compare(0, option.length() - 1, option, 0, option.length() - 1))) {
             match = true;
             break;
         }
@@ -757,8 +757,8 @@
         die("device doesn't have required partition %s!", partition_name.c_str());
     }
     bool known_partition = false;
-    for (size_t i = 0; i < arraysize(images); ++i) {
-        if (images[i].nickname && images[i].nickname == partition_name) {
+    for (size_t i = 0; i < images.size(); ++i) {
+        if (!images[i].nickname.empty() && images[i].nickname == partition_name) {
             images[i].optional_if_no_image = false;
             known_partition = true;
         }
@@ -796,9 +796,9 @@
             bool met = CheckRequirement(cur_product, name, product, invert, options);
             if (!met) {
                 if (!force_flash) {
-                  die("requirements not met!");
+                    die("requirements not met!");
                 } else {
-                  fprintf(stderr, "requirements not met! but proceeding due to --force\n");
+                    fprintf(stderr, "requirements not met! but proceeding due to --force\n");
                 }
             }
         }
@@ -822,7 +822,6 @@
     DisplayVarOrError("Baseband Version.....", "version-baseband");
     DisplayVarOrError("Serial Number........", "serialno");
     fprintf(stderr, "--------------------------------------------\n");
-
 }
 
 static struct sparse_file** load_sparse_files(int fd, int64_t max_size) {
@@ -830,13 +829,14 @@
     if (!s) die("cannot sparse read file");
 
     if (max_size <= 0 || max_size > std::numeric_limits<uint32_t>::max()) {
-      die("invalid max size %" PRId64, max_size);
+        die("invalid max size %" PRId64, max_size);
     }
 
     int files = sparse_file_resparse(s, max_size, nullptr, 0);
     if (files < 0) die("Failed to resparse");
 
-    sparse_file** out_s = reinterpret_cast<sparse_file**>(calloc(sizeof(struct sparse_file *), files + 1));
+    sparse_file** out_s =
+            reinterpret_cast<sparse_file**>(calloc(sizeof(struct sparse_file*), files + 1));
     if (!out_s) die("Failed to allocate sparse file array");
 
     files = sparse_file_resparse(s, max_size, out_s, files);
@@ -1078,8 +1078,7 @@
     lseek(buf->fd.get(), 0, SEEK_SET);
 }
 
-static void flash_buf(const std::string& partition, struct fastboot_buffer *buf)
-{
+static void flash_buf(const std::string& partition, struct fastboot_buffer* buf) {
     sparse_file** s;
 
     if (partition == "boot" || partition == "boot_a" || partition == "boot_b" ||
@@ -1097,7 +1096,7 @@
             rewrite_vbmeta_buffer(buf, false /* vbmeta_in_boot */);
         } else if (!has_vbmeta_partition() &&
                    (partition == "boot" || partition == "boot_a" || partition == "boot_b")) {
-            rewrite_vbmeta_buffer(buf, true /* vbmeta_in_boot */ );
+            rewrite_vbmeta_buffer(buf, true /* vbmeta_in_boot */);
         }
     }
 
@@ -1143,14 +1142,14 @@
 }
 
 static bool supports_AB() {
-  return get_slot_count() >= 2;
+    return get_slot_count() >= 2;
 }
 
 // Given a current slot, this returns what the 'other' slot is.
 static std::string get_other_slot(const std::string& current_slot, int count) {
     if (count == 0) return "";
 
-    char next = (current_slot[0] - 'a' + 1)%count + 'a';
+    char next = (current_slot[0] - 'a' + 1) % count + 'a';
     return std::string(1, next);
 }
 
@@ -1185,17 +1184,17 @@
     if (count == 0) die("Device does not support slots");
 
     if (slot == "other") {
-        std::string other = get_other_slot( count);
+        std::string other = get_other_slot(count);
         if (other == "") {
-           die("No known slots");
+            die("No known slots");
         }
         return other;
     }
 
-    if (slot.size() == 1 && (slot[0]-'a' >= 0 && slot[0]-'a' < count)) return slot;
+    if (slot.size() == 1 && (slot[0] - 'a' >= 0 && slot[0] - 'a' < count)) return slot;
 
     fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot.c_str());
-    for (int i=0; i<count; i++) {
+    for (int i = 0; i < count; i++) {
         fprintf(stderr, "%c\n", (char)(i + 'a'));
     }
 
@@ -1203,7 +1202,7 @@
 }
 
 static std::string verify_slot(const std::string& slot) {
-   return verify_slot(slot, true);
+    return verify_slot(slot, true);
 }
 
 static void do_for_partition(const std::string& part, const std::string& slot,
@@ -1243,7 +1242,8 @@
  * partition does not support slots.
  */
 static void do_for_partitions(const std::string& part, const std::string& slot,
-                              const std::function<void(const std::string&)>& func, bool force_slot) {
+                              const std::function<void(const std::string&)>& func,
+                              bool force_slot) {
     std::string has_slot;
     // |part| can be vendor_boot:default. Query has-slot on the first token only.
     auto part_tokens = android::base::Split(part, ":");
@@ -1254,7 +1254,7 @@
                 slot.c_str());
         }
         if (has_slot == "yes") {
-            for (int i=0; i < get_slot_count(); i++) {
+            for (int i = 0; i < get_slot_count(); i++) {
                 do_for_partition(part, std::string(1, (char)(i + 'a')), func, force_slot);
             }
         } else {
@@ -1403,7 +1403,7 @@
 
 class ImageSource {
   public:
-    virtual ~ImageSource() {};
+    virtual ~ImageSource(){};
     virtual bool ReadFile(const std::string& name, std::vector<char>* out) const = 0;
     virtual unique_fd OpenFile(const std::string& name) const = 0;
 };
@@ -1435,13 +1435,11 @@
 
 FlashAllTool::FlashAllTool(const ImageSource& source, const std::string& slot_override,
                            bool skip_secondary, bool wipe, bool force_flash)
-   : source_(source),
-     slot_override_(slot_override),
-     skip_secondary_(skip_secondary),
-     wipe_(wipe),
-     force_flash_(force_flash)
-{
-}
+    : source_(source),
+      slot_override_(slot_override),
+      skip_secondary_(skip_secondary),
+      wipe_(wipe),
+      force_flash_(force_flash) {}
 
 void FlashAllTool::Flash() {
     DumpInfo();
@@ -1508,7 +1506,7 @@
 }
 
 void FlashAllTool::CollectImages() {
-    for (size_t i = 0; i < arraysize(images); ++i) {
+    for (size_t i = 0; i < images.size(); ++i) {
         std::string slot = slot_override_;
         if (images[i].IsSecondary()) {
             if (skip_secondary_) {
@@ -1532,7 +1530,7 @@
             if (image->optional_if_no_image) {
                 continue;
             }
-            die("could not load '%s': %s", image->img_name, strerror(errno));
+            die("could not load '%s': %s", image->img_name.c_str(), strerror(errno));
         }
         FlashImage(*image, slot, &buf);
     }
@@ -1734,8 +1732,7 @@
             fprintf(stderr, "File system type %s not supported.\n", partition_type.c_str());
             return;
         }
-        die("Formatting is not supported for file system with type '%s'.",
-            partition_type.c_str());
+        die("Formatting is not supported for file system with type '%s'.", partition_type.c_str());
     }
 
     int64_t size;
@@ -1892,32 +1889,30 @@
     g_boot_img_hdr.page_size = 2048;
     g_boot_img_hdr.dtb_addr = 0x01100000;
 
-    const struct option longopts[] = {
-        {"base", required_argument, 0, 0},
-        {"cmdline", required_argument, 0, 0},
-        {"disable-verification", no_argument, 0, 0},
-        {"disable-verity", no_argument, 0, 0},
-        {"force", no_argument, 0, 0},
-        {"fs-options", required_argument, 0, 0},
-        {"header-version", required_argument, 0, 0},
-        {"help", no_argument, 0, 'h'},
-        {"kernel-offset", required_argument, 0, 0},
-        {"os-patch-level", required_argument, 0, 0},
-        {"os-version", required_argument, 0, 0},
-        {"page-size", required_argument, 0, 0},
-        {"ramdisk-offset", required_argument, 0, 0},
-        {"set-active", optional_argument, 0, 'a'},
-        {"skip-reboot", no_argument, 0, 0},
-        {"skip-secondary", no_argument, 0, 0},
-        {"slot", required_argument, 0, 0},
-        {"tags-offset", required_argument, 0, 0},
-        {"dtb", required_argument, 0, 0},
-        {"dtb-offset", required_argument, 0, 0},
-        {"unbuffered", no_argument, 0, 0},
-        {"verbose", no_argument, 0, 'v'},
-        {"version", no_argument, 0, 0},
-        {0, 0, 0, 0}
-    };
+    const struct option longopts[] = {{"base", required_argument, 0, 0},
+                                      {"cmdline", required_argument, 0, 0},
+                                      {"disable-verification", no_argument, 0, 0},
+                                      {"disable-verity", no_argument, 0, 0},
+                                      {"force", no_argument, 0, 0},
+                                      {"fs-options", required_argument, 0, 0},
+                                      {"header-version", required_argument, 0, 0},
+                                      {"help", no_argument, 0, 'h'},
+                                      {"kernel-offset", required_argument, 0, 0},
+                                      {"os-patch-level", required_argument, 0, 0},
+                                      {"os-version", required_argument, 0, 0},
+                                      {"page-size", required_argument, 0, 0},
+                                      {"ramdisk-offset", required_argument, 0, 0},
+                                      {"set-active", optional_argument, 0, 'a'},
+                                      {"skip-reboot", no_argument, 0, 0},
+                                      {"skip-secondary", no_argument, 0, 0},
+                                      {"slot", required_argument, 0, 0},
+                                      {"tags-offset", required_argument, 0, 0},
+                                      {"dtb", required_argument, 0, 0},
+                                      {"dtb-offset", required_argument, 0, 0},
+                                      {"unbuffered", no_argument, 0, 0},
+                                      {"verbose", no_argument, 0, 'v'},
+                                      {"version", no_argument, 0, 0},
+                                      {0, 0, 0, 0}};
 
     serial = getenv("ANDROID_SERIAL");
 
@@ -1966,7 +1961,8 @@
                 setvbuf(stdout, nullptr, _IONBF, 0);
                 setvbuf(stderr, nullptr, _IONBF, 0);
             } else if (name == "version") {
-                fprintf(stdout, "fastboot version %s-%s\n", PLATFORM_TOOLS_VERSION, android::build::GetBuildNumber().c_str());
+                fprintf(stdout, "fastboot version %s-%s\n", PLATFORM_TOOLS_VERSION,
+                        android::build::GetBuildNumber().c_str());
                 fprintf(stdout, "Installed as %s\n", android::base::GetExecutablePath().c_str());
                 return 0;
             } else {
@@ -2024,9 +2020,9 @@
         return 1;
     }
     fastboot::DriverCallbacks driver_callbacks = {
-        .prolog = Status,
-        .epilog = Epilog,
-        .info = InfoMessage,
+            .prolog = Status,
+            .epilog = Epilog,
+            .info = InfoMessage,
     };
     fastboot::FastBootDriver fastboot_driver(transport, driver_callbacks, false);
     fb = &fastboot_driver;
@@ -2063,7 +2059,8 @@
             std::string partition = next_arg(&args);
             auto erase = [&](const std::string& partition) {
                 std::string partition_type;
-                if (fb->GetVar("partition-type:" + partition, &partition_type) == fastboot::SUCCESS &&
+                if (fb->GetVar("partition-type:" + partition, &partition_type) ==
+                            fastboot::SUCCESS &&
                     fs_get_generator(partition_type) != nullptr) {
                     fprintf(stderr, "******** Did you mean to fastboot format this %s partition?\n",
                             partition_type.c_str());
@@ -2118,7 +2115,6 @@
                 } else {
                     syntax_error("unknown reboot target %s", what.c_str());
                 }
-
             }
             if (!args.empty()) syntax_error("junk after reboot command");
         } else if (command == FB_CMD_REBOOT_BOOTLOADER) {
@@ -2149,7 +2145,7 @@
             }
             if (fname.empty()) die("cannot determine image filename for '%s'", pname.c_str());
 
-            auto flash = [&](const std::string &partition) {
+            auto flash = [&](const std::string& partition) {
                 if (should_flash_in_userspace(partition) && !is_userspace_fastboot() &&
                     !force_flash) {
                     die("The partition you are trying to flash is dynamic, and "
@@ -2178,7 +2174,8 @@
             do_for_partitions(partition, slot_override, flashraw, true);
         } else if (command == "flashall") {
             if (slot_override == "all") {
-                fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
+                fprintf(stderr,
+                        "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
                 do_flashall(slot_override, true, wants_wipe, force_flash);
             } else {
                 do_flashall(slot_override, skip_secondary, wants_wipe, force_flash);
@@ -2187,7 +2184,8 @@
         } else if (command == "update") {
             bool slot_all = (slot_override == "all");
             if (slot_all) {
-                fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
+                fprintf(stderr,
+                        "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
             }
             std::string filename = "update.zip";
             if (!args.empty()) {
@@ -2214,10 +2212,9 @@
         } else if (command == "flashing") {
             if (args.empty()) {
                 syntax_error("missing 'flashing' command");
-            } else if (args.size() == 1 && (args[0] == "unlock" || args[0] == "lock" ||
-                                            args[0] == "unlock_critical" ||
-                                            args[0] == "lock_critical" ||
-                                            args[0] == "get_unlock_ability")) {
+            } else if (args.size() == 1 &&
+                       (args[0] == "unlock" || args[0] == "lock" || args[0] == "unlock_critical" ||
+                        args[0] == "lock_critical" || args[0] == "get_unlock_ability")) {
                 do_oem_command("flashing", &args);
             } else {
                 syntax_error("unknown 'flashing' command %s", args[0].c_str());
@@ -2272,7 +2269,7 @@
         if (force_flash) {
             CancelSnapshotIfNeeded();
         }
-        std::vector<std::string> partitions = { "userdata", "cache", "metadata" };
+        std::vector<std::string> partitions = {"userdata", "cache", "metadata"};
         for (const auto& partition : partitions) {
             std::string partition_type;
             if (fb->GetVar("partition-type:" + partition, &partition_type) != fastboot::SUCCESS) {
@@ -2334,8 +2331,7 @@
     unsigned fsOptions = 0;
 
     std::vector<std::string> options = android::base::Split(arg, ",");
-    if (options.size() < 1)
-        syntax_error("bad options: %s", arg);
+    if (options.size() < 1) syntax_error("bad options: %s", arg);
 
     for (size_t i = 0; i < options.size(); ++i) {
         if (options[i] == "casefold")
diff --git a/fs_mgr/tools/dmuserd.cpp b/fs_mgr/tools/dmuserd.cpp
index 6b68b28..da7156c 100644
--- a/fs_mgr/tools/dmuserd.cpp
+++ b/fs_mgr/tools/dmuserd.cpp
@@ -13,6 +13,7 @@
 #include <sys/prctl.h>
 #include <unistd.h>
 #include <iostream>
+#include <string>
 
 #define SECTOR_SIZE ((__u64)512)
 #define BUFFER_BYTES 4096
@@ -133,16 +134,16 @@
     return 0;
 }
 
-int simple_daemon(char* control_path, char* backing_path) {
-    int control_fd = open(control_path, O_RDWR);
+static int simple_daemon(const std::string& control_path, const std::string& backing_path) {
+    int control_fd = open(control_path.c_str(), O_RDWR);
     if (control_fd < 0) {
-        fprintf(stderr, "Unable to open control device %s\n", control_path);
+        fprintf(stderr, "Unable to open control device %s\n", control_path.c_str());
         return -1;
     }
 
-    int backing_fd = open(backing_path, O_RDWR);
+    int backing_fd = open(backing_path.c_str(), O_RDWR);
     if (backing_fd < 0) {
-        fprintf(stderr, "Unable to open backing device %s\n", backing_path);
+        fprintf(stderr, "Unable to open backing device %s\n", backing_path.c_str());
         return -1;
     }
 
@@ -286,8 +287,8 @@
 }
 
 int main(int argc, char* argv[]) {
-    char* control_path = NULL;
-    char* backing_path = NULL;
+    std::string control_path;
+    std::string backing_path;
     char* store;
     int c;
 
@@ -299,10 +300,10 @@
                 usage(basename(argv[0]));
                 exit(0);
             case 'c':
-                control_path = strdup(optarg);
+                control_path = optarg;
                 break;
             case 'b':
-                backing_path = strdup(optarg);
+                backing_path = optarg;
                 break;
             case 'v':
                 verbose = true;
diff --git a/init/Android.bp b/init/Android.bp
index 06f696e..c7e7de8 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -109,21 +109,22 @@
         misc_undefined: ["signed-integer-overflow"],
     },
     cflags: [
-        "-DLOG_UEVENTS=0",
-        "-Wall",
-        "-Wextra",
-        "-Wno-unused-parameter",
-        "-Werror",
-        "-Wthread-safety",
         "-DALLOW_FIRST_STAGE_CONSOLE=0",
         "-DALLOW_LOCAL_PROP_OVERRIDE=0",
         "-DALLOW_PERMISSIVE_SELINUX=0",
-        "-DREBOOT_BOOTLOADER_ON_PANIC=0",
-        "-DWORLD_WRITABLE_KMSG=0",
+        "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
         "-DDUMP_ON_UMOUNT_FAILURE=0",
-        "-DSHUTDOWN_ZERO_TIMEOUT=0",
         "-DINIT_FULL_SOURCES",
         "-DINSTALL_DEBUG_POLICY_TO_SYSTEM_EXT=0",
+        "-DLOG_UEVENTS=0",
+        "-DREBOOT_BOOTLOADER_ON_PANIC=0",
+        "-DSHUTDOWN_ZERO_TIMEOUT=0",
+        "-DWORLD_WRITABLE_KMSG=0",
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-Wno-unused-parameter",
+        "-Wthread-safety",
     ],
     product_variables: {
         debuggable: {
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 7cb8b11..a89813e 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -331,13 +331,13 @@
     unique_fd s(TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)));
     if (s < 0) return ErrnoError() << "opening socket failed";
 
-    if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
+    if (ioctl(s.get(), SIOCGIFFLAGS, &ifr) < 0) {
         return ErrnoError() << "ioctl(..., SIOCGIFFLAGS, ...) failed";
     }
 
     ifr.ifr_flags |= IFF_UP;
 
-    if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
+    if (ioctl(s.get(), SIOCSIFFLAGS, &ifr) < 0) {
         return ErrnoError() << "ioctl(..., SIOCSIFFLAGS, ...) failed";
     }
 
@@ -516,11 +516,11 @@
 
             loop_info info;
             /* if it is a blank loop device */
-            if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
+            if (ioctl(loop.get(), LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
                 /* if it becomes our loop device */
-                if (ioctl(loop, LOOP_SET_FD, fd.get()) >= 0) {
+                if (ioctl(loop.get(), LOOP_SET_FD, fd.get()) >= 0) {
                     if (mount(tmp.c_str(), target, system, flags, options) < 0) {
-                        ioctl(loop, LOOP_CLR_FD, 0);
+                        ioctl(loop.get(), LOOP_CLR_FD, 0);
                         return ErrnoError() << "mount() failed";
                     }
                     return {};
@@ -901,16 +901,16 @@
     if (fd == -1) {
         return ErrnoError() << "Error opening file";
     }
-    if (posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED)) {
+    if (posix_fadvise(fd.get(), 0, 0, POSIX_FADV_WILLNEED)) {
         return ErrnoError() << "Error posix_fadvise file";
     }
-    if (readahead(fd, 0, std::numeric_limits<size_t>::max())) {
+    if (readahead(fd.get(), 0, std::numeric_limits<size_t>::max())) {
         return ErrnoError() << "Error readahead file";
     }
     if (fully) {
         char buf[BUFSIZ];
         ssize_t n;
-        while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
+        while ((n = TEMP_FAILURE_RETRY(read(fd.get(), &buf[0], sizeof(buf)))) > 0) {
         }
         if (n != 0) {
             return ErrnoError() << "Error reading file";
diff --git a/init/epoll.cpp b/init/epoll.cpp
index fd1af4f..cd73a0c 100644
--- a/init/epoll.cpp
+++ b/init/epoll.cpp
@@ -57,7 +57,7 @@
             .events = events,
             .data.fd = fd,
     };
-    if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
+    if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, fd, &ev) == -1) {
         Result<void> result = ErrnoError() << "epoll_ctl failed to add fd";
         epoll_handlers_.erase(fd);
         return result;
@@ -66,7 +66,7 @@
 }
 
 Result<void> Epoll::UnregisterHandler(int fd) {
-    if (epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, nullptr) == -1) {
+    if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, fd, nullptr) == -1) {
         return ErrnoError() << "epoll_ctl failed to remove fd";
     }
     auto it = epoll_handlers_.find(fd);
@@ -88,7 +88,7 @@
     }
     const auto max_events = epoll_handlers_.size();
     epoll_event ev[max_events];
-    auto num_events = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_, ev, max_events, timeout_ms));
+    auto num_events = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_.get(), ev, max_events, timeout_ms));
     if (num_events == -1) {
         return ErrnoError() << "epoll_wait failed";
     }
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index 30e808d..b9fa58c 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -257,12 +257,12 @@
             return false;
         }
         struct stat sb;
-        if (fstat(fw_fd, &sb) == -1) {
+        if (fstat(fw_fd.get(), &sb) == -1) {
             attempted_paths_and_errors.emplace_back("firmware: attempted " + file +
                                                     ", fstat failed: " + strerror(errno));
             return false;
         }
-        LoadFirmware(firmware, root, fw_fd, sb.st_size, loading_fd, data_fd);
+        LoadFirmware(firmware, root, fw_fd.get(), sb.st_size, loading_fd.get(), data_fd.get());
         return true;
     };
 
@@ -287,7 +287,7 @@
     }
 
     // Write "-1" as our response to the kernel's firmware request, since we have nothing for it.
-    write(loading_fd, "-1", 2);
+    write(loading_fd.get(), "-1", 2);
 }
 
 bool FirmwareHandler::ForEachFirmwareDirectory(
diff --git a/init/persistent_properties.cpp b/init/persistent_properties.cpp
index d33a6b8..8db7267 100644
--- a/init/persistent_properties.cpp
+++ b/init/persistent_properties.cpp
@@ -77,7 +77,7 @@
         }
 
         struct stat sb;
-        if (fstat(fd, &sb) == -1) {
+        if (fstat(fd.get(), &sb) == -1) {
             PLOG(ERROR) << "fstat on property file \"" << entry->d_name << "\" failed";
             continue;
         }
@@ -198,7 +198,7 @@
     if (!WriteStringToFd(serialized_string, fd)) {
         return ErrnoError() << "Unable to write file contents";
     }
-    fsync(fd);
+    fsync(fd.get());
     fd.reset();
 
     if (rename(temp_filename.c_str(), persistent_property_filename.c_str())) {
@@ -216,7 +216,7 @@
     if (dir_fd < 0) {
         return ErrnoError() << "Unable to open persistent properties directory for fsync()";
     }
-    fsync(dir_fd);
+    fsync(dir_fd.get());
 
     return {};
 }
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 22b66a9..9df9828 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -300,13 +300,13 @@
         if (!socket_.ok()) {
             return true;
         }
-        int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
+        int result = TEMP_FAILURE_RETRY(send(socket_.get(), &value, sizeof(value), 0));
         return result == sizeof(value);
     }
 
     bool GetSourceContext(std::string* source_context) const {
         char* c_source_context = nullptr;
-        if (getpeercon(socket_, &c_source_context) != 0) {
+        if (getpeercon(socket_.get(), &c_source_context) != 0) {
             return false;
         }
         *source_context = c_source_context;
@@ -321,7 +321,7 @@
   private:
     bool PollIn(uint32_t* timeout_ms) {
         struct pollfd ufd = {
-                .fd = socket_,
+                .fd = socket_.get(),
                 .events = POLLIN,
         };
         while (*timeout_ms > 0) {
@@ -368,7 +368,7 @@
                 return false;
             }
 
-            int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT));
+            int result = TEMP_FAILURE_RETRY(recv(socket_.get(), data, bytes_left, MSG_DONTWAIT));
             if (result <= 0) {
                 PLOG(ERROR) << "sys_prop: recv error";
                 return false;
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 1f4186d..a3fc534 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -767,7 +767,7 @@
     if (IsDataMounted("f2fs")) {
         uint32_t flag = F2FS_GOING_DOWN_FULLSYNC;
         unique_fd fd(TEMP_FAILURE_RETRY(open("/data", O_RDONLY)));
-        int ret = ioctl(fd, F2FS_IOC_SHUTDOWN, &flag);
+        int ret = ioctl(fd.get(), F2FS_IOC_SHUTDOWN, &flag);
         if (ret) {
             PLOG(ERROR) << "Shutdown /data: ";
         } else {
diff --git a/init/security.cpp b/init/security.cpp
index 2ecf687..6e616be 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -216,7 +216,7 @@
         return {};
     }
 
-    int ioctl_ret = ioctl(fd, PERF_EVENT_IOC_RESET);
+    int ioctl_ret = ioctl(fd.get(), PERF_EVENT_IOC_RESET);
     if (ioctl_ret != -1) {
         // Success implies that the kernel doesn't have the hooks.
         return {};
diff --git a/init/selinux.cpp b/init/selinux.cpp
index ab5b0a0..ea308aa 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -567,7 +567,7 @@
         return ErrnoError() << "Failed to open " << dstPath;
     }
 
-    ret = ExtractEntryToFile(archive, &entry, fd);
+    ret = ExtractEntryToFile(archive, &entry, fd.get());
     if (ret != 0) {
         return Error() << "Failed to extract entry \"" << fileName << "\" ("
                        << entry.uncompressed_length << " bytes) to \"" << dstPath
@@ -785,7 +785,7 @@
         return;
     }
 
-    TEMP_FAILURE_RETRY(send(fd, &request, sizeof(request), 0));
+    TEMP_FAILURE_RETRY(send(fd.get(), &request, sizeof(request), 0));
 }
 
 }  // namespace
diff --git a/init/service.h b/init/service.h
index 6fb2804..f9749d2 100644
--- a/init/service.h
+++ b/init/service.h
@@ -73,6 +73,8 @@
             const std::vector<gid_t>& supp_gids, int namespace_flags, const std::string& seclabel,
             Subcontext* subcontext_for_restart_commands, const std::string& filename,
             const std::vector<std::string>& args);
+    Service(const Service&) = delete;
+    void operator=(const Service&) = delete;
 
     static Result<std::unique_ptr<Service>> MakeTemporaryOneshotService(
             const std::vector<std::string>& args);
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index 15bf963..7004d8d 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -52,7 +52,7 @@
     if (fd == -1) {
         return ErrnoError() << "Could not open namespace at " << path;
     }
-    if (setns(fd, nstype) == -1) {
+    if (setns(fd.get(), nstype) == -1) {
         return ErrnoError() << "Could not setns() namespace at " << path;
     }
     return {};
@@ -127,22 +127,22 @@
 
 void SetupStdio(bool stdio_to_kmsg) {
     auto fd = unique_fd{open("/dev/null", O_RDWR | O_CLOEXEC)};
-    dup2(fd, STDIN_FILENO);
+    dup2(fd.get(), STDIN_FILENO);
     if (stdio_to_kmsg) {
         fd.reset(open("/dev/kmsg_debug", O_WRONLY | O_CLOEXEC));
         if (fd == -1) fd.reset(open("/dev/null", O_WRONLY | O_CLOEXEC));
     }
-    dup2(fd, STDOUT_FILENO);
-    dup2(fd, STDERR_FILENO);
+    dup2(fd.get(), STDOUT_FILENO);
+    dup2(fd.get(), STDERR_FILENO);
 }
 
 void OpenConsole(const std::string& console) {
     auto fd = unique_fd{open(console.c_str(), O_RDWR | O_CLOEXEC)};
     if (fd == -1) fd.reset(open("/dev/null", O_RDWR | O_CLOEXEC));
-    ioctl(fd, TIOCSCTTY, 0);
-    dup2(fd, 0);
-    dup2(fd, 1);
-    dup2(fd, 2);
+    ioctl(fd.get(), TIOCSCTTY, 0);
+    dup2(fd.get(), 0);
+    dup2(fd.get(), 1);
+    dup2(fd.get(), 2);
 }
 
 }  // namespace
@@ -190,7 +190,7 @@
     }
 
     // Fixup as we set O_NONBLOCK for open, the intent for fd is to block reads.
-    fcntl(fd, F_SETFL, flags);
+    fcntl(fd.get(), F_SETFL, flags);
 
     return Descriptor(ANDROID_FILE_ENV_PREFIX + name, std::move(fd));
 }
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 961e006..6a095fb 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -207,7 +207,7 @@
 
         // We explicitly do not use O_CLOEXEC here, such that we can reference this FD by number
         // in the subcontext process after we exec.
-        int child_fd = dup(subcontext_socket);  // NOLINT(android-cloexec-dup)
+        int child_fd = dup(subcontext_socket.get());  // NOLINT(android-cloexec-dup)
         if (child_fd < 0) {
             PLOG(FATAL) << "Could not dup child_fd";
         }
@@ -268,12 +268,12 @@
 }
 
 Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
-    if (auto result = SendMessage(socket_, subcontext_command); !result.ok()) {
+    if (auto result = SendMessage(socket_.get(), subcontext_command); !result.ok()) {
         Restart();
         return ErrnoError() << "Failed to send message to subcontext";
     }
 
-    auto subcontext_message = ReadMessage(socket_);
+    auto subcontext_message = ReadMessage(socket_.get());
     if (!subcontext_message.ok()) {
         Restart();
         return Error() << "Failed to receive result from subcontext: " << subcontext_message.error();
diff --git a/init/test_upgrade_mte/mte_upgrade_test_helper.cpp b/init/test_upgrade_mte/mte_upgrade_test_helper.cpp
index 10af06b..3188337 100644
--- a/init/test_upgrade_mte/mte_upgrade_test_helper.cpp
+++ b/init/test_upgrade_mte/mte_upgrade_test_helper.cpp
@@ -22,6 +22,7 @@
 #include <sys/prctl.h>
 #include <time.h>
 #include <unistd.h>
+#include <memory>
 
 int MaybeDowngrade() {
     int res = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
@@ -58,7 +59,7 @@
         // Disallow automatic upgrade from ASYNC mode.
         if (prctl(PR_SET_TAGGED_ADDR_CTRL, res & ~PR_MTE_TCF_SYNC, 0, 0, 0) == -1) abort();
     }
-    volatile char* f = (char*)malloc(1);
+    std::unique_ptr<volatile char[]> f(new char[1]);
     f[17] = 'x';
     char buf[1];
     read(1, buf, 1);
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index 7cd396a..5da6777 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -92,12 +92,12 @@
         LOG(FATAL) << "Could not open uevent socket";
     }
 
-    fcntl(device_fd_, F_SETFL, O_NONBLOCK);
+    fcntl(device_fd_.get(), F_SETFL, O_NONBLOCK);
 }
 
 ReadUeventResult UeventListener::ReadUevent(Uevent* uevent) const {
     char msg[UEVENT_MSG_LEN + 2];
-    int n = uevent_kernel_multicast_recv(device_fd_, msg, UEVENT_MSG_LEN);
+    int n = uevent_kernel_multicast_recv(device_fd_.get(), msg, UEVENT_MSG_LEN);
     if (n <= 0) {
         if (errno != EAGAIN && errno != EWOULDBLOCK) {
             PLOG(ERROR) << "Error reading from Uevent Fd";
@@ -184,9 +184,10 @@
                           const std::optional<std::chrono::milliseconds> relative_timeout) const {
     using namespace std::chrono;
 
-    pollfd ufd;
-    ufd.events = POLLIN;
-    ufd.fd = device_fd_;
+    pollfd ufd = {
+            .events = POLLIN,
+            .fd = device_fd_.get(),
+    };
 
     auto start_time = steady_clock::now();
 
diff --git a/init/util.cpp b/init/util.cpp
index 3d42855..bc8ea6e 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -120,12 +120,12 @@
 
     if (passcred) {
         int on = 1;
-        if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
+        if (setsockopt(fd.get(), SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
             return ErrnoError() << "Failed to set SO_PASSCRED '" << name << "'";
         }
     }
 
-    int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
+    int ret = bind(fd.get(), (struct sockaddr*)&addr, sizeof(addr));
     int savederrno = errno;
 
     if (!secontext.empty()) {
@@ -145,7 +145,7 @@
     if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) {
         return ErrnoError() << "Failed to fchmodat socket '" << addr.sun_path << "'";
     }
-    if (should_listen && listen(fd, /* use OS maximum */ 1 << 30)) {
+    if (should_listen && listen(fd.get(), /* use OS maximum */ 1 << 30)) {
         return ErrnoError() << "Failed to listen on socket '" << addr.sun_path << "'";
     }
 
@@ -168,7 +168,7 @@
     // For security reasons, disallow world-writable
     // or group-writable files.
     struct stat sb;
-    if (fstat(fd, &sb) == -1) {
+    if (fstat(fd.get(), &sb) == -1) {
         return ErrnoError() << "fstat failed()";
     }
     if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
diff --git a/libsystem/include/system/graphics-base-v1.2.h b/libsystem/include/system/graphics-base-v1.2.h
index 2194f5e..624912c 100644
--- a/libsystem/include/system/graphics-base-v1.2.h
+++ b/libsystem/include/system/graphics-base-v1.2.h
@@ -14,13 +14,17 @@
 } android_hdr_v1_2_t;
 
 typedef enum {
-    HAL_DATASPACE_DISPLAY_BT2020 = 142999552 /* ((STANDARD_BT2020 | TRANSFER_SRGB) | RANGE_FULL) */,
+    HAL_DATASPACE_DISPLAY_BT2020 = 142999552 /* STANDARD_BT2020 | TRANSFER_SRGB | RANGE_FULL */,
     HAL_DATASPACE_DYNAMIC_DEPTH = 4098 /* 0x1002 */,
     HAL_DATASPACE_JPEG_APP_SEGMENTS = 4099 /* 0x1003 */,
     HAL_DATASPACE_HEIF = 4100 /* 0x1004 */,
 } android_dataspace_v1_2_t;
 
 typedef enum {
+    HAL_COLOR_MODE_DISPLAY_BT2020 = 13,
+} android_color_mode_v1_2_t;
+
+typedef enum {
     HAL_PIXEL_FORMAT_HSV_888 = 55 /* 0x37 */,
 } android_pixel_format_v1_2_t;
 
diff --git a/libutils/Unicode_test.cpp b/libutils/Unicode_test.cpp
index 8b994d9..7969525 100644
--- a/libutils/Unicode_test.cpp
+++ b/libutils/Unicode_test.cpp
@@ -35,86 +35,208 @@
     }
 
     char16_t const * const kSearchString = u"I am a leaf on the wind.";
+
+    constexpr static size_t BUFSIZE = 64;       // large enough for all tests
+
+    void TestUTF8toUTF16(std::initializer_list<uint8_t> input,
+                         std::initializer_list<char16_t> expect,
+                         const char* err_msg_length = "",
+                         ssize_t expected_length = 0) {
+        uint8_t empty_str[] = {};
+        char16_t output[BUFSIZE];
+
+        const size_t inlen = input.size(), outlen = expect.size();
+        ASSERT_LT(outlen, BUFSIZE);
+
+        const uint8_t *input_data = inlen ? std::data(input) : empty_str;
+        ssize_t measured = utf8_to_utf16_length(input_data, inlen);
+        EXPECT_EQ(expected_length ? : (ssize_t)outlen, measured) << err_msg_length;
+
+        utf8_to_utf16(input_data, inlen, output, outlen + 1);
+        for (size_t i = 0; i < outlen; i++) {
+            EXPECT_EQ(std::data(expect)[i], output[i]);
+        }
+        EXPECT_EQ(0, output[outlen]) << "should be null terminated";
+    }
+
+    void TestUTF16toUTF8(std::initializer_list<char16_t> input,
+                         std::initializer_list<char> expect,
+                         const char* err_msg_length = "",
+                         ssize_t expected_length = 0) {
+        char16_t empty_str[] = {};
+        char output[BUFSIZE];
+
+        const size_t inlen = input.size(), outlen = expect.size();
+        ASSERT_LT(outlen, BUFSIZE);
+
+        const char16_t *input_data = inlen ? std::data(input) : empty_str;
+        ssize_t measured = utf16_to_utf8_length(input_data, inlen);
+        EXPECT_EQ(expected_length ? : (ssize_t)outlen, measured) << err_msg_length;
+
+        utf16_to_utf8(input_data, inlen, output, outlen + 1);
+        for (size_t i = 0; i < outlen; i++) {
+            EXPECT_EQ(std::data(expect)[i], output[i]);
+        }
+        EXPECT_EQ(0, output[outlen]) << "should be null terminated";
+    }
 };
 
 TEST_F(UnicodeTest, UTF8toUTF16ZeroLength) {
-    ssize_t measured;
-
-    const uint8_t str[] = { };
-
-    measured = utf8_to_utf16_length(str, 0);
-    EXPECT_EQ(0, measured)
-            << "Zero length input should return zero length output.";
+    TestUTF8toUTF16({}, {},
+        "Zero length input should return zero length output.");
 }
 
-TEST_F(UnicodeTest, UTF8toUTF16ASCIILength) {
-    ssize_t measured;
-
-    // U+0030 or ASCII '0'
-    const uint8_t str[] = { 0x30 };
-
-    measured = utf8_to_utf16_length(str, sizeof(str));
-    EXPECT_EQ(1, measured)
-            << "ASCII glyphs should have a length of 1 char16_t";
+TEST_F(UnicodeTest, UTF8toUTF16ASCII) {
+    TestUTF8toUTF16(
+        { 0x30 },               // U+0030 or ASCII '0'
+        { 0x0030 },
+        "ASCII codepoints should have a length of 1 char16_t");
 }
 
-TEST_F(UnicodeTest, UTF8toUTF16Plane1Length) {
-    ssize_t measured;
-
-    // U+2323 SMILE
-    const uint8_t str[] = { 0xE2, 0x8C, 0xA3 };
-
-    measured = utf8_to_utf16_length(str, sizeof(str));
-    EXPECT_EQ(1, measured)
-            << "Plane 1 glyphs should have a length of 1 char16_t";
+TEST_F(UnicodeTest, UTF8toUTF16Plane1) {
+    TestUTF8toUTF16(
+        { 0xE2, 0x8C, 0xA3 },   // U+2323 SMILE
+        { 0x2323 },
+        "Plane 1 codepoints should have a length of 1 char16_t");
 }
 
-TEST_F(UnicodeTest, UTF8toUTF16SurrogateLength) {
-    ssize_t measured;
-
-    // U+10000
-    const uint8_t str[] = { 0xF0, 0x90, 0x80, 0x80 };
-
-    measured = utf8_to_utf16_length(str, sizeof(str));
-    EXPECT_EQ(2, measured)
-            << "Surrogate pairs should have a length of 2 char16_t";
+TEST_F(UnicodeTest, UTF8toUTF16Surrogate) {
+    TestUTF8toUTF16(
+        { 0xF0, 0x90, 0x80, 0x80 },   // U+10000
+        { 0xD800, 0xDC00 },
+        "Surrogate pairs should have a length of 2 char16_t");
 }
 
 TEST_F(UnicodeTest, UTF8toUTF16TruncatedUTF8) {
-    ssize_t measured;
-
-    // Truncated U+2323 SMILE
-    // U+2323 SMILE
-    const uint8_t str[] = { 0xE2, 0x8C };
-
-    measured = utf8_to_utf16_length(str, sizeof(str));
-    EXPECT_EQ(-1, measured)
-            << "Truncated UTF-8 should return -1 to indicate invalid";
+    TestUTF8toUTF16(
+        { 0xE2, 0x8C },       // Truncated U+2323 SMILE
+        { },                  // Conversion should still work but produce nothing
+        "Truncated UTF-8 should return -1 to indicate invalid",
+        -1);
 }
 
 TEST_F(UnicodeTest, UTF8toUTF16Normal) {
-    const uint8_t str[] = {
-        0x30, // U+0030, 1 UTF-16 character
-        0xC4, 0x80, // U+0100, 1 UTF-16 character
-        0xE2, 0x8C, 0xA3, // U+2323, 1 UTF-16 character
+    TestUTF8toUTF16({
+        0x30,                   // U+0030, 1 UTF-16 character
+        0xC4, 0x80,             // U+0100, 1 UTF-16 character
+        0xE2, 0x8C, 0xA3,       // U+2323, 1 UTF-16 character
         0xF0, 0x90, 0x80, 0x80, // U+10000, 2 UTF-16 character
-    };
+    }, {
+        0x0030,
+        0x0100,
+        0x2323,
+        0xD800, 0xDC00
+    });
+}
 
-    char16_t output[1 + 1 + 1 + 2 + 1];  // Room for null
+TEST_F(UnicodeTest, UTF8toUTF16Invalid) {
+    // TODO: The current behavior of utf8_to_utf16 is to treat invalid
+    // leading byte (>= 0xf8) as a 4-byte UTF8 sequence, and to treat
+    // invalid trailing byte(s) (i.e. bytes not having MSB set) as if
+    // they are valid and do the normal conversion. However, a better
+    // handling would be to treat invalid sequences as errors, such
+    // cases need to be reported and invalid characters (e.g. U+FFFD)
+    // could be produced at the place of error.  Until a fix is ready
+    // and compatibility is not an issue, we will keep testing the
+    // current behavior
+    TestUTF8toUTF16({
+        0xf8,                   // invalid leading byte
+        0xc4, 0x00,             // U+0100 with invalid trailing byte
+        0xe2, 0x0c, 0xa3,       // U+2323 with invalid trailing bytes
+        0xf0, 0x10, 0x00, 0x00, // U+10000 with invalid trailing bytes
+    }, {
+        0x4022,                 // invalid leading byte (>=0xfc) is treated
+                                // as valid for 4-byte UTF8 sequence
+	0x000C,
+	0x00A3,                 // invalid leadnig byte (b'10xxxxxx) is
+                                // treated as valid single UTF-8 byte
+        0xD800,                 // invalid trailing bytes are treated
+        0xDC00,                 // as valid bytes and follow normal
+    });
+}
 
-    utf8_to_utf16(str, sizeof(str), output, sizeof(output) / sizeof(output[0]));
+TEST_F(UnicodeTest, UTF16toUTF8ZeroLength) {
+    // TODO: The current behavior of utf16_to_utf8_length() is that
+    // it returns -1 if the input is a zero length UTF16 string.
+    // This is inconsistent with utf8_to_utf16_length() where a zero
+    // length string returns 0.  However, to fix the current behavior,
+    // we could have compatibility issue.  Until then, we will keep
+    // testing the current behavior
+    TestUTF16toUTF8({}, {},
+        "Zero length UTF16 input should return length of -1.", -1);
+}
 
-    EXPECT_EQ(0x0030, output[0])
-            << "should be U+0030";
-    EXPECT_EQ(0x0100, output[1])
-            << "should be U+0100";
-    EXPECT_EQ(0x2323, output[2])
-            << "should be U+2323";
-    EXPECT_EQ(0xD800, output[3])
-            << "should be first half of surrogate U+10000";
-    EXPECT_EQ(0xDC00, output[4])
-            << "should be second half of surrogate U+10000";
-    EXPECT_EQ(0, output[5]) << "should be null terminated";
+TEST_F(UnicodeTest, UTF16toUTF8ASCII) {
+    TestUTF16toUTF8(
+        { 0x0030 },  // U+0030 or ASCII '0'
+        { '\x30' },
+        "ASCII codepoints in UTF16 should give a length of 1 in UTF8");
+}
+
+TEST_F(UnicodeTest, UTF16toUTF8Plane1) {
+    TestUTF16toUTF8(
+        { 0x2323 },  // U+2323 SMILE
+        { '\xE2', '\x8C', '\xA3' },
+        "Plane 1 codepoints should have a length of 3 char in UTF-8");
+}
+
+TEST_F(UnicodeTest, UTF16toUTF8Surrogate) {
+    TestUTF16toUTF8(
+        { 0xD800, 0xDC00 },  // U+10000
+        { '\xF0', '\x90', '\x80', '\x80' },
+        "Surrogate pairs should have a length of 4 chars");
+}
+
+TEST_F(UnicodeTest, UTF16toUTF8UnpairedSurrogate) {
+    TestUTF16toUTF8(
+        { 0xD800 },     // U+10000 with high surrogate pair only
+        { },            // Unpaired surrogate should be ignored
+        "A single unpaired high surrogate should have a length of 0 chars");
+
+    TestUTF16toUTF8(
+        { 0xDC00 },     // U+10000 with low surrogate pair only
+        { },            // Unpaired surrogate should be ignored
+        "A single unpaired low surrogate should have a length of 0 chars");
+
+    TestUTF16toUTF8(
+        // U+0030, U+0100, U+10000 with high surrogate pair only, U+2323
+        { 0x0030, 0x0100, 0xDC00, 0x2323 },
+        { '\x30', '\xC4', '\x80', '\xE2', '\x8C', '\xA3' },
+        "Unpaired high surrogate should be skipped in the middle");
+
+    TestUTF16toUTF8(
+        // U+0030, U+0100, U+10000 with high surrogate pair only, U+2323
+        { 0x0030, 0x0100, 0xDC00, 0x2323 },
+        { '\x30', '\xC4', '\x80', '\xE2', '\x8C', '\xA3' },
+        "Unpaired low surrogate should be skipped in the middle");
+}
+
+TEST_F(UnicodeTest, UTF16toUTF8CorrectInvalidSurrogate) {
+    // http://b/29250543
+    // d841d8 is an invalid start for a surrogate pair. Make sure this is handled by ignoring the
+    // first character in the pair and handling the rest correctly.
+    TestUTF16toUTF8(
+        { 0xD841, 0xD841, 0xDC41 },     // U+20441
+        { '\xF0', '\xA0', '\x91', '\x81' },
+        "Invalid start for a surrogate pair should be ignored");
+}
+
+TEST_F(UnicodeTest, UTF16toUTF8Normal) {
+    TestUTF16toUTF8({
+        0x0024, // U+0024 ($) --> 0x24,           1 UTF-8 byte
+        0x00A3, // U+00A3 (£) --> 0xC2 0xA3,      2 UTF-8 bytes
+        0x0939, // U+0939 (ह) --> 0xE0 0xA4 0xB9, 3 UTF-8 bytes
+        0x20AC, // U+20AC (€) --> 0xE2 0x82 0xAC, 3 UTF-8 bytes
+        0xD55C, // U+D55C (한)--> 0xED 0x95 0x9C, 3 UTF-8 bytes
+        0xD801, 0xDC37, // U+10437 (𐐷) --> 0xF0 0x90 0x90 0xB7, 4 UTF-8 bytes
+    }, {
+        '\x24',
+        '\xC2', '\xA3',
+        '\xE0', '\xA4', '\xB9',
+        '\xE2', '\x82', '\xAC',
+        '\xED', '\x95', '\x9C',
+        '\xF0', '\x90', '\x90', '\xB7',
+    });
 }
 
 TEST_F(UnicodeTest, strstr16EmptyTarget) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1131f3f..d8e6b55 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -936,16 +936,20 @@
     restorecon /data/media
     exec - media_rw media_rw -- /system/bin/chattr +F /data/media
 
-    # A tmpfs directory, which will contain all apps CE DE data directory that
-    # bind mount from the original source.
+    # A tmpfs directory, which will contain all apps and sdk sandbox CE and DE
+    # data directory that bind mount from the original source.
     mount tmpfs tmpfs /data_mirror nodev noexec nosuid mode=0700,uid=0,gid=1000
     restorecon /data_mirror
     mkdir /data_mirror/data_ce 0700 root root
     mkdir /data_mirror/data_de 0700 root root
+    mkdir /data_mirror/misc_ce 0700 root root
+    mkdir /data_mirror/misc_de 0700 root root
 
     # Create CE and DE data directory for default volume
     mkdir /data_mirror/data_ce/null 0700 root root
     mkdir /data_mirror/data_de/null 0700 root root
+    mkdir /data_mirror/misc_ce/null 0700 root root
+    mkdir /data_mirror/misc_de/null 0700 root root
 
     # Bind mount CE and DE data directory to mirror's default volume directory.
     # Note that because the /data mount has the "shared" propagation type, the
@@ -953,6 +957,8 @@
     # propagate to /data_mirror/data_ce/null/0 as well.
     mount none /data/user /data_mirror/data_ce/null bind rec
     mount none /data/user_de /data_mirror/data_de/null bind rec
+    mount none /data/misc_ce /data_mirror/misc_ce/null bind rec
+    mount none /data/misc_de /data_mirror/misc_de/null bind rec
 
     # Create mirror directory for jit profiles
     mkdir /data_mirror/cur_profiles 0700 root root
diff --git a/trusty/keymint/Android.bp b/trusty/keymint/Android.bp
new file mode 100644
index 0000000..c19ebbd
--- /dev/null
+++ b/trusty/keymint/Android.bp
@@ -0,0 +1,41 @@
+//
+// 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_binary {
+    name: "android.hardware.security.keymint-service.rust.trusty",
+    relative_install_path: "hw",
+    vendor: true,
+    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"
+    ],
+    rustlibs: [
+        "libandroid_logger",
+        "libbinder_rs",
+        "libkmr_wire",
+        "libkmr_hal",
+        "libtrusty-rs",
+        "liblibc",
+        "liblog_rust",
+    ],
+    required: [
+        "android.hardware.hardware_keystore.xml",
+    ],
+}
diff --git a/trusty/keymint/android.hardware.hardware_keystore.rust.trusty-keymint.xml b/trusty/keymint/android.hardware.hardware_keystore.rust.trusty-keymint.xml
new file mode 100644
index 0000000..cd656b2
--- /dev/null
+++ b/trusty/keymint/android.hardware.hardware_keystore.rust.trusty-keymint.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<permissions>
+  <feature name="android.hardware.hardware_keystore" version="300" />
+</permissions>
diff --git a/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.rc b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.rc
new file mode 100644
index 0000000..e3d94c6
--- /dev/null
+++ b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.rc
@@ -0,0 +1,7 @@
+service vendor.keymint.rust-trusty /vendor/bin/hw/android.hardware.security.keymint-service.rust.trusty
+    class early_hal
+    user nobody
+    group drmrpc
+    # The keymint service is not allowed to restart.
+    # If it crashes, a device restart is required.
+    oneshot
\ No newline at end of file
diff --git a/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.xml b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.xml
new file mode 100644
index 0000000..3dc9c88
--- /dev/null
+++ b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.xml
@@ -0,0 +1,20 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.security.keymint</name>
+        <version>3</version>
+        <fqname>IKeyMintDevice/default</fqname>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.security.secureclock</name>
+        <fqname>ISecureClock/default</fqname>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.security.sharedsecret</name>
+        <fqname>ISharedSecret/default</fqname>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.security.keymint</name>
+        <version>3</version>
+        <fqname>IRemotelyProvisionedComponent/default</fqname>
+    </hal>
+</manifest>
diff --git a/trusty/keymint/src/keymint_hal_main.rs b/trusty/keymint/src/keymint_hal_main.rs
new file mode 100644
index 0000000..d2d5f27
--- /dev/null
+++ b/trusty/keymint/src/keymint_hal_main.rs
@@ -0,0 +1,155 @@
+//
+// 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 module implements the HAL service for Keymint (Rust) in Trusty.
+use kmr_hal::{keymint, rpc, secureclock, send_hal_info, sharedsecret, SerializedChannel};
+use log::{error, info};
+use std::{
+    ffi::CString,
+    ops::DerefMut,
+    panic,
+    sync::{Arc, Mutex},
+};
+use trusty::DEFAULT_DEVICE;
+
+const TRUSTY_KEYMINT_RUST_SERVICE_NAME: &str = "com.android.trusty.keymint";
+
+static SERVICE_INSTANCE: &str = "default";
+
+static KM_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
+static RPC_SERVICE_NAME: &str = "android.hardware.security.keymint.IRemotelyProvisionedComponent";
+static SECURE_CLOCK_SERVICE_NAME: &str = "android.hardware.security.secureclock.ISecureClock";
+static SHARED_SECRET_SERVICE_NAME: &str = "android.hardware.security.sharedsecret.ISharedSecret";
+
+/// Local error type for failures in the HAL service.
+#[derive(Debug, Clone)]
+struct HalServiceError(String);
+
+#[derive(Debug)]
+struct TipcChannel(trusty::TipcChannel);
+
+impl SerializedChannel for TipcChannel {
+    fn execute(&mut self, serialized_req: &[u8]) -> binder::Result<Vec<u8>> {
+        self.0.send(serialized_req).map_err(|e| {
+            binder::Status::new_exception(
+                binder::ExceptionCode::TRANSACTION_FAILED,
+                Some(
+                    &CString::new(format!(
+                        "Failed to send the request via tipc channel because of {:?}",
+                        e
+                    ))
+                    .unwrap(),
+                ),
+            )
+        })?;
+        let mut recv_buf = Vec::new();
+        // TODO(b/253501976): cope with fragmentation of responses
+        self.0.recv(&mut recv_buf).map_err(|e| {
+            binder::Status::new_exception(
+                binder::ExceptionCode::TRANSACTION_FAILED,
+                Some(
+                    &CString::new(format!(
+                        "Failed to receive the response via tipc channel because of {:?}",
+                        e
+                    ))
+                    .unwrap(),
+                ),
+            )
+        })?;
+        Ok(recv_buf)
+    }
+}
+
+fn main() {
+    if let Err(e) = inner_main() {
+        panic!("HAL service failed: {:?}", e);
+    }
+}
+
+fn inner_main() -> Result<(), HalServiceError> {
+    // Initialize Android logging.
+    android_logger::init_once(
+        android_logger::Config::default()
+            .with_tag("keymint-hal-trusty")
+            .with_min_level(log::Level::Info)
+            .with_log_id(android_logger::LogId::System),
+    );
+    // Redirect panic messages to logcat.
+    panic::set_hook(Box::new(|panic_info| {
+        error!("{}", panic_info);
+    }));
+
+    info!("Trusty KM HAL service is starting.");
+
+    info!("Starting thread pool now.");
+    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 tipc_channel = Arc::new(Mutex::new(TipcChannel(connection)));
+
+    // Register the Keymint service
+    let km_service = keymint::Device::new_as_binder(tipc_channel.clone());
+    let km_service_name = format!("{}/{}", KM_SERVICE_NAME, SERVICE_INSTANCE);
+    binder::add_service(&km_service_name, km_service.as_binder()).map_err(|e| {
+        HalServiceError(format!(
+            "Failed to register service {} because of {:?}.",
+            km_service_name, e
+        ))
+    })?;
+
+    // Register the Remotely Provisioned Component service
+    let rpc_service = rpc::Device::new_as_binder(tipc_channel.clone());
+    let rpc_service_name = format!("{}/{}", RPC_SERVICE_NAME, SERVICE_INSTANCE);
+    binder::add_service(&rpc_service_name, rpc_service.as_binder()).map_err(|e| {
+        HalServiceError(format!(
+            "Failed to register service {} because of {:?}.",
+            rpc_service_name, e
+        ))
+    })?;
+
+    // Register the Secure Clock service
+    let sclock_service = secureclock::Device::new_as_binder(tipc_channel.clone());
+    let sclock_service_name = format!("{}/{}", SECURE_CLOCK_SERVICE_NAME, SERVICE_INSTANCE);
+    binder::add_service(&sclock_service_name, sclock_service.as_binder()).map_err(|e| {
+        HalServiceError(format!(
+            "Failed to register service {} because of {:?}.",
+            sclock_service_name, e
+        ))
+    })?;
+
+    // Register the Shared Secret service
+    let ssecret_service = sharedsecret::Device::new_as_binder(tipc_channel.clone());
+    let ssecret_service_name = format!("{}/{}", SHARED_SECRET_SERVICE_NAME, SERVICE_INSTANCE);
+    binder::add_service(&ssecret_service_name, ssecret_service.as_binder()).map_err(|e| {
+        HalServiceError(format!(
+            "Failed to register service {} because of {:?}.",
+            ssecret_service_name, e
+        ))
+    })?;
+
+    // Send the HAL service information to the TA
+    send_hal_info(tipc_channel.lock().unwrap().deref_mut())
+        .map_err(|e| HalServiceError(format!("Failed to populate HAL info: {:?}", e)))?;
+
+    info!("Successfully registered KeyMint HAL services.");
+    info!("Joining thread pool now.");
+    binder::ProcessState::join_thread_pool();
+    info!("KeyMint HAL service is terminating."); // should not reach here
+    Ok(())
+}