Merge "Remove obsolete subdirs entry."
diff --git a/base/include/android-base/expected.h b/base/include/android-base/expected.h
index 6153b77..030ef35e 100644
--- a/base/include/android-base/expected.h
+++ b/base/include/android-base/expected.h
@@ -256,7 +256,8 @@
   expected& operator=(const expected& rhs) = default;
 
   // Note for SFNAIE above applies to here as well
-  expected& operator=(expected&& rhs) = default;
+  expected& operator=(expected&& rhs) noexcept(
+      std::is_nothrow_move_assignable_v<T>&& std::is_nothrow_move_assignable_v<E>) = default;
 
   template <class U = T _ENABLE_IF(
                 !std::is_void_v<T> &&
@@ -542,7 +543,7 @@
   expected& operator=(const expected& rhs) = default;
 
   // Note for SFNAIE above applies to here as well
-  expected& operator=(expected&& rhs) = default;
+  expected& operator=(expected&& rhs) noexcept(std::is_nothrow_move_assignable_v<E>) = default;
 
   template<class G = E>
   expected& operator=(const unexpected<G>& rhs) {
@@ -633,7 +634,7 @@
  public:
   // constructors
   constexpr unexpected(const unexpected&) = default;
-  constexpr unexpected(unexpected&&) = default;
+  constexpr unexpected(unexpected&&) noexcept(std::is_nothrow_move_constructible_v<E>) = default;
 
   template <class Err = E _ENABLE_IF(
                 std::is_constructible_v<E, Err> &&
@@ -709,7 +710,8 @@
 
   // assignment
   constexpr unexpected& operator=(const unexpected&) = default;
-  constexpr unexpected& operator=(unexpected&&) = default;
+  constexpr unexpected& operator=(unexpected&&) noexcept(std::is_nothrow_move_assignable_v<E>) =
+      default;
   template<class Err = E>
   constexpr unexpected& operator=(const unexpected<Err>& rhs) {
     val_ = rhs.value();
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 6936cc2..cd9fda3 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -140,13 +140,13 @@
     {"mba_err", 13},
     {"Watchdog", 14},
     {"Panic", 15},
-    {"power_key", 16},  // Mediatek
-    {"power_on", 17},
+    {"power_key", 16},  // aliasReasons to cold,powerkey (Mediatek)
+    {"power_on", 17},   // aliasReasons to cold,powerkey
     {"Reboot", 18},
     {"rtc", 19},
     {"edl", 20},
     {"oem_pon1", 21},
-    {"oem_powerkey", 22},
+    {"oem_powerkey", 22},  // aliasReasons to cold,powerkey
     {"oem_unknown_reset", 23},
     {"srto: HWWDT reset SC", 24},
     {"srto: HWWDT reset platform", 25},
@@ -201,15 +201,15 @@
     {"hard,hw_reset", 72},
     {"shutdown,suspend", 73},    // Suspend to RAM
     {"shutdown,hibernate", 74},  // Suspend to DISK
-    {"power_on_key", 75},
-    {"reboot_by_key", 76},
-    {"wdt_by_pass_pwk", 77},  // Mediatek
-    {"reboot_longkey", 78},
-    {"powerkey", 79},
-    {"usb", 80},               // Mediatek
-    {"wdt", 81},               // Mediatek
-    {"tool_by_pass_pwk", 82},  // Mediatek
-    {"2sec_reboot", 83},       // Mediatek
+    {"power_on_key", 75},        // aliasReasons to cold,powerkey
+    {"reboot_by_key", 76},       // translated to reboot,by_key
+    {"wdt_by_pass_pwk", 77},     // Mediatek
+    {"reboot_longkey", 78},      // translated to reboot,longkey
+    {"powerkey", 79},            // aliasReasons to cold,powerkey
+    {"usb", 80},                 // aliasReasons to cold,charger (Mediatek)
+    {"wdt", 81},                 // Mediatek
+    {"tool_by_pass_pwk", 82},    // aliasReasons to reboot,tool (Mediatek)
+    {"2sec_reboot", 83},         // aliasReasons to cold,rtc,2sec (Mediatek)
     {"reboot,by_key", 84},
     {"reboot,longkey", 85},
     {"reboot,2sec", 86},  // Deprecate in two years, replaced with cold,rtc,2sec
@@ -219,28 +219,28 @@
     {"reboot,rescueparty", 90},
     {"charge", 91},
     {"oem_tz_crash", 92},
-    {"uvlo", 93},  // aliasReasons converts to reboot,undervoltage
+    {"uvlo", 93},  // aliasReasons to reboot,undervoltage
     {"oem_ps_hold", 94},
     {"abnormal_reset", 95},
     {"oemerr_unknown", 96},
     {"reboot_fastboot_mode", 97},
     {"watchdog_apps_bite", 98},
     {"xpu_err", 99},
-    {"power_on_usb", 100},
+    {"power_on_usb", 100},  // aliasReasons to cold,charger
     {"watchdog_rpm", 101},
     {"watchdog_nonsec", 102},
     {"watchdog_apps_bark", 103},
     {"reboot_dmverity_corrupted", 104},
-    {"reboot_smpl", 105},  // aliasReasons converts to reboot,powerloss
+    {"reboot_smpl", 105},  // aliasReasons to reboot,powerloss
     {"watchdog_sdi_apps_reset", 106},
-    {"smpl", 107},  // aliasReasons converts to reboot,powerloss
+    {"smpl", 107},  // aliasReasons to reboot,powerloss
     {"oem_modem_failed_to_powerup", 108},
     {"reboot_normal", 109},
     {"oem_lpass_cfg", 110},
     {"oem_xpu_ns_error", 111},
-    {"power_key_press", 112},
+    {"power_key_press", 112},  // aliasReasons to cold,powerkey
     {"hardware_reset", 113},
-    {"reboot_by_powerkey", 114},
+    {"reboot_by_powerkey", 114},  // aliasReasons to cold,powerkey (is this correct?)
     {"reboot_verity", 115},
     {"oem_rpm_undef_error", 116},
     {"oem_crash_on_the_lk", 117},
@@ -250,7 +250,7 @@
     {"factory_cable", 121},
     {"oem_ar6320_failed_to_powerup", 122},
     {"watchdog_rpm_bite", 123},
-    {"power_on_cable", 124},
+    {"power_on_cable", 124},  // aliasReasons to cold,charger
     {"reboot_unknown", 125},
     {"wireless_charger", 126},
     {"0x776655ff", 127},
@@ -839,12 +839,12 @@
     // following table smaller.
     static const std::vector<std::pair<const std::string, const std::string>> aliasReasons = {
         {"watchdog", "wdog"},
-        {"cold,powerkey", "powerkey|power_key|PowerKey"},
         {"kernel_panic", "panic"},
         {"shutdown,thermal", "thermal"},
         {"warm,s3_wakeup", "s3_wakeup"},
         {"hard,hw_reset", "hw_reset"},
-        {"cold,charger", "usb"},
+        {"cold,charger", "usb|power_on_cable"},
+        {"cold,powerkey", "powerkey|power_key|PowerKey|power_on"},
         {"cold,rtc", "rtc"},
         {"cold,rtc,2sec", "2sec_reboot"},
         {"!warm", "wdt_by_pass_pwk"},  // change flavour of blunt
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index 2ebd57d..e01e39b 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -61,7 +61,7 @@
         LOG(ERROR) << "Could not map partition: " << partition_name;
         return false;
     }
-    auto closer = [partition_name]() -> void { DestroyLogicalPartition(partition_name, 5s); };
+    auto closer = [partition_name]() -> void { DestroyLogicalPartition(partition_name); };
     *handle = PartitionHandle(dm_path, std::move(closer));
     return true;
 }
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 3d3503c..65f0eff 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -73,6 +73,7 @@
     whole_static_libs: [
         "liblogwrap",
         "libdm",
+        "libext2_uuid",
         "libfstab",
     ],
     cppflags: [
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 259f800..7a0d019 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1331,7 +1331,7 @@
                 continue;
             }
         } else if ((current_entry.fs_mgr_flags.verify)) {
-            if (!fs_mgr_teardown_verity(&current_entry, true /* wait */)) {
+            if (!fs_mgr_teardown_verity(&current_entry)) {
                 LERROR << "Failed to tear down verified partition on mount point: "
                        << current_entry.mount_point;
                 ret |= FsMgrUmountStatus::ERROR_VERITY;
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index 1f21a71..04ba0bf 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -122,19 +122,9 @@
         table.set_readonly(false);
     }
     std::string name = GetPartitionName(partition);
-    if (!dm.CreateDevice(name, table)) {
+    if (!dm.CreateDevice(name, table, path, timeout_ms)) {
         return false;
     }
-    if (!dm.GetDmDevicePathByName(name, path)) {
-        return false;
-    }
-    if (timeout_ms > std::chrono::milliseconds::zero()) {
-        if (!WaitForFile(*path, timeout_ms)) {
-            DestroyLogicalPartition(name, {});
-            LERROR << "Timed out waiting for device path: " << *path;
-            return false;
-        }
-    }
     LINFO << "Created logical partition " << name << " on device " << *path;
     return true;
 }
@@ -194,24 +184,16 @@
                                   timeout_ms, path);
 }
 
-bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
+bool UnmapDevice(const std::string& name) {
     DeviceMapper& dm = DeviceMapper::Instance();
-    std::string path;
-    if (timeout_ms > std::chrono::milliseconds::zero()) {
-        dm.GetDmDevicePathByName(name, &path);
-    }
     if (!dm.DeleteDevice(name)) {
         return false;
     }
-    if (!path.empty() && !WaitForFileDeleted(path, timeout_ms)) {
-        LERROR << "Timed out waiting for device path to unlink: " << path;
-        return false;
-    }
     return true;
 }
 
-bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
-    if (!UnmapDevice(name, timeout_ms)) {
+bool DestroyLogicalPartition(const std::string& name) {
+    if (!UnmapDevice(name)) {
         return false;
     }
     LINFO << "Unmapped logical partition " << name;
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 6127702..ac15ce4 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -444,7 +444,7 @@
     auto metadata = builder->Export();
     if (metadata && UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
         if (change) *change = true;
-        if (!DestroyLogicalPartition(partition_name, 0s)) return false;
+        if (!DestroyLogicalPartition(partition_name)) return false;
     } else {
         LERROR << "delete partition " << overlay;
         return false;
@@ -844,7 +844,7 @@
             if (!android::base::EndsWith(name, suffix)) {
                 continue;
             }
-            if (dm.GetState(name) != DmDeviceState::INVALID && !DestroyLogicalPartition(name, 2s)) {
+            if (dm.GetState(name) != DmDeviceState::INVALID && !DestroyLogicalPartition(name)) {
                 continue;
             }
             builder->ResizePartition(builder->FindPartition(name), 0);
@@ -918,7 +918,7 @@
                         return false;
                     }
                 }
-                if (!partition_create) DestroyLogicalPartition(partition_name, 10s);
+                if (!partition_create) DestroyLogicalPartition(partition_name);
                 changed = true;
                 *partition_exists = false;
             }
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 3a33cf3..c5e477c 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -97,10 +97,10 @@
 bool fs_mgr_is_ext4(const std::string& blk_device);
 bool fs_mgr_is_f2fs(const std::string& blk_device);
 
-bool fs_mgr_teardown_verity(android::fs_mgr::FstabEntry* fstab, bool wait);
+bool fs_mgr_teardown_verity(android::fs_mgr::FstabEntry* fstab);
 
 namespace android {
 namespace fs_mgr {
-bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms);
+bool UnmapDevice(const std::string& name);
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index be8077b..efa2180 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -547,9 +547,9 @@
     return retval;
 }
 
-bool fs_mgr_teardown_verity(FstabEntry* entry, bool wait) {
+bool fs_mgr_teardown_verity(FstabEntry* entry) {
     const std::string mount_point(basename(entry->mount_point.c_str()));
-    if (!android::fs_mgr::UnmapDevice(mount_point, wait ? 1000ms : 0ms)) {
+    if (!android::fs_mgr::UnmapDevice(mount_point)) {
         return false;
     }
     LINFO << "Unmapped verity device " << mount_point;
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
index f33fc02..a1dc2dc 100644
--- a/fs_mgr/include/fs_mgr_dm_linear.h
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -68,7 +68,7 @@
 
 // Destroy the block device for a logical partition, by name. If |timeout_ms|
 // is non-zero, then this will block until the device path has been unlinked.
-bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms);
+bool DestroyLogicalPartition(const std::string& name);
 
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 21255df..e429d9f 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -29,6 +29,9 @@
         "loop_control.cpp",
     ],
 
+    static_libs: [
+        "libext2_uuid",
+    ],
     header_libs: [
         "libbase_headers",
         "liblog_headers",
@@ -46,6 +49,7 @@
     static_libs: [
         "libdm",
         "libbase",
+        "libext2_uuid",
         "libfs_mgr",
         "liblog",
     ],
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index d54b6ef..d56a4b1 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -20,12 +20,20 @@
 #include <sys/sysmacros.h>
 #include <sys/types.h>
 
+#include <functional>
+#include <thread>
+
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>
+#include <android-base/strings.h>
+#include <uuid/uuid.h>
 
 namespace android {
 namespace dm {
 
+using namespace std::literals;
+
 DeviceMapper::DeviceMapper() : fd_(-1) {
     fd_ = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
     if (fd_ < 0) {
@@ -37,13 +45,13 @@
     static DeviceMapper instance;
     return instance;
 }
+
 // Creates a new device mapper device
-bool DeviceMapper::CreateDevice(const std::string& name) {
+bool DeviceMapper::CreateDevice(const std::string& name, const std::string& uuid) {
     if (name.empty()) {
         LOG(ERROR) << "Unnamed device mapper device creation is not supported";
         return false;
     }
-
     if (name.size() >= DM_NAME_LEN) {
         LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
         return false;
@@ -51,6 +59,9 @@
 
     struct dm_ioctl io;
     InitIo(&io, name);
+    if (!uuid.empty()) {
+        snprintf(io.uuid, sizeof(io.uuid), "%s", uuid.c_str());
+    }
 
     if (ioctl(fd_, DM_DEV_CREATE, &io)) {
         PLOG(ERROR) << "DM_DEV_CREATE failed for [" << name << "]";
@@ -67,16 +78,6 @@
 }
 
 bool DeviceMapper::DeleteDevice(const std::string& name) {
-    if (name.empty()) {
-        LOG(ERROR) << "Unnamed device mapper device creation is not supported";
-        return false;
-    }
-
-    if (name.size() >= DM_NAME_LEN) {
-        LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
-        return false;
-    }
-
     struct dm_ioctl io;
     InitIo(&io, name);
 
@@ -93,9 +94,81 @@
     return true;
 }
 
-const std::unique_ptr<DmTable> DeviceMapper::table(const std::string& /* name */) const {
-    // TODO(b/110035986): Return the table, as read from the kernel instead
-    return nullptr;
+bool WaitForCondition(const std::function<bool()>& condition,
+                      const std::chrono::milliseconds& timeout_ms) {
+    auto start_time = std::chrono::steady_clock::now();
+    while (true) {
+        if (condition()) return true;
+
+        std::this_thread::sleep_for(20ms);
+
+        auto now = std::chrono::steady_clock::now();
+        auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+        if (time_elapsed > timeout_ms) return false;
+    }
+}
+
+static std::string GenerateUuid() {
+    uuid_t uuid_bytes;
+    uuid_generate(uuid_bytes);
+
+    char uuid_chars[37] = {};
+    uuid_unparse_lower(uuid_bytes, uuid_chars);
+
+    return std::string{uuid_chars};
+}
+
+bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
+                                const std::chrono::milliseconds& timeout_ms) {
+    std::string uuid = GenerateUuid();
+    if (!CreateDevice(name, uuid)) {
+        return false;
+    }
+
+    // We use the unique path for testing whether the device is ready. After
+    // that, it's safe to use the dm-N path which is compatible with callers
+    // that expect it to be formatted as such.
+    std::string unique_path;
+    if (!LoadTableAndActivate(name, table) || !GetDeviceUniquePath(name, &unique_path) ||
+        !GetDmDevicePathByName(name, path)) {
+        DeleteDevice(name);
+        return false;
+    }
+
+    if (timeout_ms <= std::chrono::milliseconds::zero()) {
+        return true;
+    }
+
+    auto condition = [&]() -> bool {
+        // If the file exists but returns EPERM or something, we consider the
+        // condition met.
+        if (access(unique_path.c_str(), F_OK) != 0) {
+            if (errno == ENOENT) return false;
+        }
+        return true;
+    };
+    if (!WaitForCondition(condition, timeout_ms)) {
+        LOG(ERROR) << "Timed out waiting for device path: " << unique_path;
+        DeleteDevice(name);
+        return false;
+    }
+    return true;
+}
+
+bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) {
+    struct dm_ioctl io;
+    InitIo(&io, name);
+    if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
+        PLOG(ERROR) << "Failed to get device path: " << name;
+        return false;
+    }
+
+    if (io.uuid[0] == '\0') {
+        LOG(ERROR) << "Device does not have a unique path: " << name;
+        return false;
+    }
+    *path = "/dev/block/mapper/by-uuid/"s + io.uuid;
+    return true;
 }
 
 DmDeviceState DeviceMapper::GetState(const std::string& name) const {
@@ -111,11 +184,8 @@
 }
 
 bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table) {
-    if (!CreateDevice(name)) {
-        return false;
-    }
-    if (!LoadTableAndActivate(name, table)) {
-        DeleteDevice(name);
+    std::string ignore_path;
+    if (!CreateDevice(name, table, &ignore_path, 0ms)) {
         return false;
     }
     return true;
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index c5881dd..7a834e2 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -52,10 +52,10 @@
   public:
     TempDevice(const std::string& name, const DmTable& table)
         : dm_(DeviceMapper::Instance()), name_(name), valid_(false) {
-        valid_ = dm_.CreateDevice(name, table);
+        valid_ = dm_.CreateDevice(name, table, &path_, 5s);
     }
     TempDevice(TempDevice&& other) noexcept
-        : dm_(other.dm_), name_(other.name_), valid_(other.valid_) {
+        : dm_(other.dm_), name_(other.name_), path_(other.path_), valid_(other.valid_) {
         other.valid_ = false;
     }
     ~TempDevice() {
@@ -70,29 +70,7 @@
         valid_ = false;
         return dm_.DeleteDevice(name_);
     }
-    bool WaitForUdev() const {
-        auto start_time = std::chrono::steady_clock::now();
-        while (true) {
-            if (!access(path().c_str(), F_OK)) {
-                return true;
-            }
-            if (errno != ENOENT) {
-                return false;
-            }
-            std::this_thread::sleep_for(50ms);
-            std::chrono::duration elapsed = std::chrono::steady_clock::now() - start_time;
-            if (elapsed >= 5s) {
-                return false;
-            }
-        }
-    }
-    std::string path() const {
-        std::string device_path;
-        if (!dm_.GetDmDevicePathByName(name_, &device_path)) {
-            return "";
-        }
-        return device_path;
-    }
+    std::string path() const { return path_; }
     const std::string& name() const { return name_; }
     bool valid() const { return valid_; }
 
@@ -109,6 +87,7 @@
   private:
     DeviceMapper& dm_;
     std::string name_;
+    std::string path_;
     bool valid_;
 };
 
@@ -139,7 +118,6 @@
     TempDevice dev("libdm-test-dm-linear", table);
     ASSERT_TRUE(dev.valid());
     ASSERT_FALSE(dev.path().empty());
-    ASSERT_TRUE(dev.WaitForUdev());
 
     auto& dm = DeviceMapper::Instance();
 
@@ -290,7 +268,6 @@
     origin_dev_ = std::make_unique<TempDevice>("libdm-test-dm-snapshot-origin", origin_table);
     ASSERT_TRUE(origin_dev_->valid());
     ASSERT_FALSE(origin_dev_->path().empty());
-    ASSERT_TRUE(origin_dev_->WaitForUdev());
 
     // chunk size = 4K blocks.
     DmTable snap_table;
@@ -302,7 +279,6 @@
     snapshot_dev_ = std::make_unique<TempDevice>("libdm-test-dm-snapshot", snap_table);
     ASSERT_TRUE(snapshot_dev_->valid());
     ASSERT_FALSE(snapshot_dev_->path().empty());
-    ASSERT_TRUE(snapshot_dev_->WaitForUdev());
 
     setup_ok_ = true;
 }
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 08376c0..9c0c2f30 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -25,6 +25,7 @@
 #include <sys/sysmacros.h>
 #include <unistd.h>
 
+#include <chrono>
 #include <memory>
 #include <string>
 #include <utility>
@@ -73,10 +74,6 @@
     // Returns 'true' on success, false otherwise.
     bool DeleteDevice(const std::string& name);
 
-    // Reads the device mapper table from the device with given anme and
-    // returns it in a DmTable object.
-    const std::unique_ptr<DmTable> table(const std::string& name) const;
-
     // Returns the current state of the underlying device mapper device
     // with given name.
     // One of INVALID, SUSPENDED or ACTIVE.
@@ -84,6 +81,33 @@
 
     // Creates a device, loads the given table, and activates it. If the device
     // is not able to be activated, it is destroyed, and false is returned.
+    // After creation, |path| contains the result of calling
+    // GetDmDevicePathByName, and the path is guaranteed to exist. If after
+    // |timeout_ms| the path is not available, the device will be deleted and
+    // this function will return false.
+    //
+    // This variant must be used when depending on the device path. The
+    // following manual sequence should not be used:
+    //
+    //   1. CreateDevice(name, table)
+    //   2. GetDmDevicePathByName(name, &path)
+    //   3. fs_mgr::WaitForFile(path, <timeout>)
+    //
+    // This sequence has a race condition where, if another process deletes a
+    // device, CreateDevice may acquire the same path. When this happens, the
+    // WaitForFile() may early-return since ueventd has not yet processed all
+    // of the outstanding udev events. The caller may unexpectedly get an
+    // ENOENT on a system call using the affected path.
+    //
+    // If |timeout_ms| is 0ms, then this function will return true whether or
+    // not |path| is available. It is the caller's responsibility to ensure
+    // there are no races.
+    bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
+                      const std::chrono::milliseconds& timeout_ms);
+
+    // Create a device and activate the given table, without waiting to acquire
+    // a valid path. If the caller will use GetDmDevicePathByName(), it should
+    // use the timeout variant above.
     bool CreateDevice(const std::string& name, const DmTable& table);
 
     // Loads the device mapper table from parameter into the underlying device
@@ -110,8 +134,21 @@
     // Returns the path to the device mapper device node in '/dev' corresponding to
     // 'name'. If the device does not exist, false is returned, and the path
     // parameter is not set.
+    //
+    // This returns a path in the format "/dev/block/dm-N" that can be easily
+    // re-used with sysfs.
+    //
+    // WaitForFile() should not be used in conjunction with this call, since it
+    // could race with ueventd.
     bool GetDmDevicePathByName(const std::string& name, std::string* path);
 
+    // Returns a device's unique path as generated by ueventd. This will return
+    // true as long as the device has been created, even if ueventd has not
+    // processed it yet.
+    //
+    // The formatting of this path is /dev/block/mapper/by-uuid/<uuid>.
+    bool GetDeviceUniquePath(const std::string& name, std::string* path);
+
     // Returns the dev_t for the named device-mapper node.
     bool GetDeviceNumber(const std::string& name, dev_t* dev);
 
@@ -158,18 +195,12 @@
     // limit we are imposing here of 256.
     static constexpr uint32_t kMaxPossibleDmDevices = 256;
 
+    bool CreateDevice(const std::string& name, const std::string& uuid = {});
     bool GetTable(const std::string& name, uint32_t flags, std::vector<TargetInfo>* table);
-
     void InitIo(struct dm_ioctl* io, const std::string& name = std::string()) const;
 
     DeviceMapper();
 
-    // Creates a device mapper device with given name.
-    // Return 'true' on success and 'false' on failure to
-    // create OR if a device mapper device with the same name already
-    // exists.
-    bool CreateDevice(const std::string& name);
-
     int fd_;
     // Non-copyable & Non-movable
     DeviceMapper(const DeviceMapper&) = delete;
diff --git a/fs_mgr/libfs_avb/Android.bp b/fs_mgr/libfs_avb/Android.bp
index a3c76ab..414a186 100644
--- a/fs_mgr/libfs_avb/Android.bp
+++ b/fs_mgr/libfs_avb/Android.bp
@@ -61,6 +61,7 @@
         "libavb",
         "libavb_host_sysdeps",
         "libdm",
+        "libext2_uuid",
         "libfs_avb",
         "libfstab",
         "libgtest_host",
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index d9650f3..4505382 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -104,31 +104,23 @@
     }
     table.set_readonly(true);
 
+    std::chrono::milliseconds timeout = {};
+    if (wait_for_verity_dev) timeout = 1s;
+
+    std::string dev_path;
     const std::string mount_point(Basename(fstab_entry->mount_point));
     const std::string device_name(GetVerityDeviceName(*fstab_entry));
     android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
-    if (!dm.CreateDevice(device_name, table)) {
+    if (!dm.CreateDevice(device_name, table, &dev_path, timeout)) {
         LERROR << "Couldn't create verity device!";
         return false;
     }
 
-    std::string dev_path;
-    if (!dm.GetDmDevicePathByName(device_name, &dev_path)) {
-        LERROR << "Couldn't get verity device path!";
-        return false;
-    }
-
     // Marks the underlying block device as read-only.
     SetBlockDeviceReadOnly(fstab_entry->blk_device);
 
     // Updates fstab_rec->blk_device to verity device name.
     fstab_entry->blk_device = dev_path;
-
-    // Makes sure we've set everything up properly.
-    if (wait_for_verity_dev && !WaitForFile(dev_path, 1s)) {
-        return false;
-    }
-
     return true;
 }
 
diff --git a/init/Android.bp b/init/Android.bp
index 4418ada..4e1162a 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -107,7 +107,6 @@
         "bootchart.cpp",
         "builtins.cpp",
         "capabilities.cpp",
-        "descriptors.cpp",
         "devices.cpp",
         "epoll.cpp",
         "firmware_handler.cpp",
@@ -254,7 +253,6 @@
         "action_manager.cpp",
         "action_parser.cpp",
         "capabilities.cpp",
-        "descriptors.cpp",
         "epoll.cpp",
         "keychords.cpp",
         "import_parser.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index 9017772..006e1bf 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -113,6 +113,7 @@
     libunwindstack \
     libbacktrace \
     libmodprobe \
+    libext2_uuid \
 
 LOCAL_SANITIZE := signed-integer-overflow
 # First stage init is weird: it may start without stdout/stderr, and no /proc.
diff --git a/init/README.md b/init/README.md
index 8179bff..2de76a9 100644
--- a/init/README.md
+++ b/init/README.md
@@ -300,7 +300,8 @@
 
 `socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]`
 > Create a UNIX domain socket named /dev/socket/_name_ and pass its fd to the
-  launched process.  _type_ must be "dgram", "stream" or "seqpacket".  User and
+  launched process.  _type_ must be "dgram", "stream" or "seqpacket".  _type_
+  may end with "+passcred" to enable SO_PASSCRED on the socket. User and
   group default to 0.  'seclabel' is the SELinux security context for the
   socket.  It defaults to the service security context, as specified by
   seclabel or computed based on the service executable file security context.
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
deleted file mode 100644
index 6265687..0000000
--- a/init/descriptors.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "descriptors.h"
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <cutils/android_get_control_file.h>
-#include <cutils/sockets.h>
-
-#include "util.h"
-
-namespace android {
-namespace init {
-
-DescriptorInfo::DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
-                               gid_t gid, int perm, const std::string& context)
-        : name_(name), type_(type), uid_(uid), gid_(gid), perm_(perm), context_(context) {
-}
-
-DescriptorInfo::~DescriptorInfo() {
-}
-
-std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info) {
-  return os << "  descriptors " << info.name_ << " " << info.type_ << " " << std::oct << info.perm_;
-}
-
-bool DescriptorInfo::operator==(const DescriptorInfo& other) const {
-  return name_ == other.name_ && type_ == other.type_ && key() == other.key();
-}
-
-void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
-  // Create
-  const std::string& contextStr = context_.empty() ? globalContext : context_;
-  int fd = Create(contextStr);
-  if (fd < 0) return;
-
-  // Publish
-  std::string publishedName = key() + name_;
-  std::for_each(publishedName.begin(), publishedName.end(),
-                [] (char& c) { c = isalnum(c) ? c : '_'; });
-
-  std::string val = std::to_string(fd);
-  setenv(publishedName.c_str(), val.c_str(), 1);
-
-  // make sure we don't close on exec
-  fcntl(fd, F_SETFD, 0);
-}
-
-void DescriptorInfo::Clean() const {
-}
-
-SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
-                       gid_t gid, int perm, const std::string& context)
-        : DescriptorInfo(name, type, uid, gid, perm, context) {
-}
-
-void SocketInfo::Clean() const {
-    std::string path = android::base::StringPrintf("%s/%s", ANDROID_SOCKET_DIR, name().c_str());
-    unlink(path.c_str());
-}
-
-int SocketInfo::Create(const std::string& context) const {
-    auto types = android::base::Split(type(), "+");
-    int flags =
-        ((types[0] == "stream" ? SOCK_STREAM : (types[0] == "dgram" ? SOCK_DGRAM : SOCK_SEQPACKET)));
-    bool passcred = types.size() > 1 && types[1] == "passcred";
-    return CreateSocket(name().c_str(), flags, passcred, perm(), uid(), gid(), context.c_str());
-}
-
-const std::string SocketInfo::key() const {
-  return ANDROID_SOCKET_ENV_PREFIX;
-}
-
-FileInfo::FileInfo(const std::string& name, const std::string& type, uid_t uid,
-                   gid_t gid, int perm, const std::string& context)
-        // defaults OK for uid,..., they are ignored for this class.
-        : DescriptorInfo(name, type, uid, gid, perm, context) {
-}
-
-int FileInfo::Create(const std::string&) const {
-  int flags = (type() == "r") ? O_RDONLY :
-              (type() == "w") ? O_WRONLY :
-                                O_RDWR;
-
-  // Make sure we do not block on open (eg: devices can chose to block on
-  // carrier detect).  Our intention is never to delay launch of a service
-  // for such a condition.  The service can perform its own blocking on
-  // carrier detect.
-  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(name().c_str(),
-                                                      flags | O_NONBLOCK)));
-
-  if (fd < 0) {
-    PLOG(ERROR) << "Failed to open file '" << name().c_str() << "'";
-    return -1;
-  }
-
-  // Fixup as we set O_NONBLOCK for open, the intent for fd is to block reads.
-  fcntl(fd, F_SETFL, flags);
-
-  LOG(INFO) << "Opened file '" << name().c_str() << "'"
-            << ", flags " << std::oct << flags << std::dec;
-
-  return fd.release();
-}
-
-const std::string FileInfo::key() const {
-  return ANDROID_FILE_ENV_PREFIX;
-}
-
-}  // namespace init
-}  // namespace android
diff --git a/init/descriptors.h b/init/descriptors.h
deleted file mode 100644
index 3bdddfe..0000000
--- a/init/descriptors.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#ifndef _INIT_DESCRIPTORS_H
-#define _INIT_DESCRIPTORS_H
-
-#include <sys/types.h>
-
-#include <string>
-
-namespace android {
-namespace init {
-
-class DescriptorInfo {
- public:
-  DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
-                 gid_t gid, int perm, const std::string& context);
-  virtual ~DescriptorInfo();
-
-  friend std::ostream& operator<<(std::ostream& os, const class DescriptorInfo& info);
-  bool operator==(const DescriptorInfo& other) const;
-
-  void CreateAndPublish(const std::string& globalContext) const;
-  virtual void Clean() const;
-
- protected:
-  const std::string& name() const { return name_; }
-  const std::string& type() const { return type_; }
-  uid_t uid() const { return uid_; }
-  gid_t gid() const { return gid_; }
-  int perm() const { return perm_; }
-  const std::string& context() const { return context_; }
-
- private:
-  std::string name_;
-  std::string type_;
-  uid_t uid_;
-  gid_t gid_;
-  int perm_;
-  std::string context_;
-
-  virtual int Create(const std::string& globalContext) const = 0;
-  virtual const std::string key() const = 0;
-};
-
-std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info);
-
-class SocketInfo : public DescriptorInfo {
- public:
-  SocketInfo(const std::string& name, const std::string& type, uid_t uid,
-             gid_t gid, int perm, const std::string& context);
-  void Clean() const override;
- private:
-  virtual int Create(const std::string& context) const override;
-  virtual const std::string key() const override;
-};
-
-class FileInfo : public DescriptorInfo {
- public:
-  FileInfo(const std::string& name, const std::string& type, uid_t uid,
-           gid_t gid, int perm, const std::string& context);
- private:
-  virtual int Create(const std::string& context) const override;
-  virtual const std::string key() const override;
-};
-
-}  // namespace init
-}  // namespace android
-
-#endif
diff --git a/init/devices.cpp b/init/devices.cpp
index e8e6cd7..f6e453a 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -22,7 +22,6 @@
 #include <unistd.h>
 
 #include <chrono>
-#include <map>
 #include <memory>
 #include <string>
 #include <thread>
@@ -111,24 +110,16 @@
 // the supplied buffer with the dm module's instantiated name.
 // If it doesn't start with a virtual block device, or there is some
 // error, return false.
-static bool FindDmDevicePartition(const std::string& path, std::string* result) {
-    result->clear();
+static bool FindDmDevice(const std::string& path, std::string* name, std::string* uuid) {
     if (!StartsWith(path, "/devices/virtual/block/dm-")) return false;
-    if (getpid() == 1) return false;  // first_stage_init has no sepolicy needs
 
-    static std::map<std::string, std::string> cache;
-    // wait_for_file will not work, the content is also delayed ...
-    for (android::base::Timer t; t.duration() < 200ms; std::this_thread::sleep_for(10ms)) {
-        if (ReadFileToString("/sys" + path + "/dm/name", result) && !result->empty()) {
-            // Got it, set cache with result, when node arrives
-            cache[path] = *result = Trim(*result);
-            return true;
-        }
+    if (!ReadFileToString("/sys" + path + "/dm/name", name)) {
+        return false;
     }
-    auto it = cache.find(path);
-    if ((it == cache.end()) || (it->second.empty())) return false;
-    // Return cached results, when node goes away
-    *result = it->second;
+    ReadFileToString("/sys" + path + "/dm/uuid", uuid);
+
+    *name = android::base::Trim(*name);
+    *uuid = android::base::Trim(*uuid);
     return true;
 }
 
@@ -325,6 +316,7 @@
     std::string device;
     std::string type;
     std::string partition;
+    std::string uuid;
 
     if (FindPlatformDevice(uevent.path, &device)) {
         // Skip /devices/platform or /devices/ if present
@@ -342,8 +334,12 @@
         type = "pci";
     } else if (FindVbdDevicePrefix(uevent.path, &device)) {
         type = "vbd";
-    } else if (FindDmDevicePartition(uevent.path, &partition)) {
-        return {"/dev/block/mapper/" + partition};
+    } else if (FindDmDevice(uevent.path, &partition, &uuid)) {
+        std::vector<std::string> symlinks = {"/dev/block/mapper/" + partition};
+        if (!uuid.empty()) {
+            symlinks.emplace_back("/dev/block/mapper/by-uuid/" + uuid);
+        }
+        return symlinks;
     } else {
         return {};
     }
@@ -379,10 +375,41 @@
     return links;
 }
 
+static void RemoveDeviceMapperLinks(const std::string& devpath) {
+    std::vector<std::string> dirs = {
+            "/dev/block/mapper",
+            "/dev/block/mapper/by-uuid",
+    };
+    for (const auto& dir : dirs) {
+        if (access(dir.c_str(), F_OK) != 0) continue;
+
+        std::unique_ptr<DIR, decltype(&closedir)> dh(opendir(dir.c_str()), closedir);
+        if (!dh) {
+            PLOG(ERROR) << "Failed to open directory " << dir;
+            continue;
+        }
+
+        struct dirent* dp;
+        std::string link_path;
+        while ((dp = readdir(dh.get())) != nullptr) {
+            if (dp->d_type != DT_LNK) continue;
+
+            auto path = dir + "/" + dp->d_name;
+            if (Readlink(path, &link_path) && link_path == devpath) {
+                unlink(path.c_str());
+            }
+        }
+    }
+}
+
 void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, bool block,
                                  int major, int minor, const std::vector<std::string>& links) const {
     if (action == "add") {
         MakeDevice(devpath, block, major, minor, links);
+    }
+
+    // We don't have full device-mapper information until a change event is fired.
+    if (action == "add" || (action == "change" && StartsWith(devpath, "/dev/block/dm-"))) {
         for (const auto& link : links) {
             if (!mkdir_recursive(Dirname(link), 0755)) {
                 PLOG(ERROR) << "Failed to create directory " << Dirname(link);
@@ -401,6 +428,9 @@
     }
 
     if (action == "remove") {
+        if (StartsWith(devpath, "/dev/block/dm-")) {
+            RemoveDeviceMapperLinks(devpath);
+        }
         for (const auto& link : links) {
             std::string link_path;
             if (Readlink(link, &link_path) && link_path == devpath) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 8623c30..3761750 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -994,10 +994,11 @@
 void StartPropertyService(Epoll* epoll) {
     property_set("ro.property_service.version", "2");
 
-    property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
-                                   false, 0666, 0, 0, nullptr);
-    if (property_set_fd == -1) {
-        PLOG(FATAL) << "start_property_service socket creation failed";
+    if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+                                   false, 0666, 0, 0, {})) {
+        property_set_fd = *result;
+    } else {
+        PLOG(FATAL) << "start_property_service socket creation failed: " << result.error();
     }
 
     listen(property_set_fd, 8);
diff --git a/init/service.cpp b/init/service.cpp
index f95b675..47f4db9 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -31,6 +31,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <cutils/sockets.h>
 #include <processgroup/processgroup.h>
 #include <selinux/selinux.h>
 
@@ -227,9 +228,11 @@
         KillProcessGroup(SIGKILL);
     }
 
-    // Remove any descriptor resources we may have created.
-    std::for_each(descriptors_.begin(), descriptors_.end(),
-                  std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
+    // Remove any socket resources we may have created.
+    for (const auto& socket : sockets_) {
+        auto path = ANDROID_SOCKET_DIR "/" + socket.name;
+        unlink(path.c_str());
+    }
 
     for (const auto& f : reap_callbacks_) {
         f(siginfo);
@@ -300,8 +303,12 @@
     LOG(INFO) << "service " << name_;
     LOG(INFO) << "  class '" << Join(classnames_, " ") << "'";
     LOG(INFO) << "  exec " << Join(args_, " ");
-    std::for_each(descriptors_.begin(), descriptors_.end(),
-                  [] (const auto& info) { LOG(INFO) << *info; });
+    for (const auto& socket : sockets_) {
+        LOG(INFO) << "  socket " << socket.name;
+    }
+    for (const auto& file : files_) {
+        LOG(INFO) << "  file " << file.name;
+    }
 }
 
 
@@ -419,8 +426,17 @@
             setenv(key.c_str(), value.c_str(), 1);
         }
 
-        std::for_each(descriptors_.begin(), descriptors_.end(),
-                      std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));
+        for (const auto& socket : sockets_) {
+            if (auto result = socket.CreateAndPublish(scon); !result) {
+                LOG(INFO) << "Could not create socket '" << socket.name << "': " << result.error();
+            }
+        }
+
+        for (const auto& file : files_) {
+            if (auto result = file.CreateAndPublish(); !result) {
+                LOG(INFO) << "Could not open file '" << file.name << "': " << result.error();
+            }
+        }
 
         if (auto result = WritePidToFiles(&writepid_files_); !result) {
             LOG(ERROR) << "failed to write pid to files: " << result.error();
diff --git a/init/service.h b/init/service.h
index cc35a8d..cdf31bb 100644
--- a/init/service.h
+++ b/init/service.h
@@ -31,7 +31,6 @@
 
 #include "action.h"
 #include "capabilities.h"
-#include "descriptors.h"
 #include "keyword_map.h"
 #include "parser.h"
 #include "service_utils.h"
@@ -151,7 +150,8 @@
 
     std::string seclabel_;
 
-    std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
+    std::vector<SocketDescriptor> sockets_;
+    std::vector<FileDescriptor> files_;
     std::vector<std::pair<std::string, std::string>> environment_vars_;
 
     Action onrestart_;  // Commands to execute on restart.
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 88ce364..0fbbeb8 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -17,6 +17,8 @@
 #include "service_parser.h"
 
 #include <linux/input.h>
+#include <stdlib.h>
+#include <sys/socket.h>
 
 #include <algorithm>
 #include <sstream>
@@ -28,6 +30,7 @@
 #include <system/thread_defs.h>
 
 #include "rlimit_parser.h"
+#include "service_utils.h"
 #include "util.h"
 
 #if defined(__ANDROID__)
@@ -344,64 +347,98 @@
     return {};
 }
 
-template <typename T>
-Result<void> ServiceParser::AddDescriptor(std::vector<std::string>&& args) {
-    int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
-    Result<uid_t> uid = 0;
-    Result<gid_t> gid = 0;
-    std::string context = args.size() > 6 ? args[6] : "";
+// name type perm [ uid gid context ]
+Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
+    SocketDescriptor socket;
+    socket.name = std::move(args[1]);
+
+    auto types = Split(args[2], "+");
+    if (types[0] == "stream") {
+        socket.type = SOCK_STREAM;
+    } else if (types[0] == "dgram") {
+        socket.type = SOCK_DGRAM;
+    } else if (types[0] == "seqpacket") {
+        socket.type = SOCK_SEQPACKET;
+    } else {
+        return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket', got '" << types[0]
+                       << "' instead.";
+    }
+
+    if (types.size() > 1) {
+        if (types.size() == 2 && types[1] == "passcred") {
+            socket.passcred = true;
+        } else {
+            return Error() << "Only 'passcred' may be used to modify the socket type";
+        }
+    }
+
+    errno = 0;
+    char* end = nullptr;
+    socket.perm = strtol(args[3].c_str(), &end, 8);
+    if (errno != 0) {
+        return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
+    }
+    if (end == args[3].c_str() || *end != '\0') {
+        errno = EINVAL;
+        return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
+    }
 
     if (args.size() > 4) {
-        uid = DecodeUid(args[4]);
+        auto uid = DecodeUid(args[4]);
         if (!uid) {
             return Error() << "Unable to find UID for '" << args[4] << "': " << uid.error();
         }
+        socket.uid = *uid;
     }
 
     if (args.size() > 5) {
-        gid = DecodeUid(args[5]);
+        auto gid = DecodeUid(args[5]);
         if (!gid) {
             return Error() << "Unable to find GID for '" << args[5] << "': " << gid.error();
         }
+        socket.gid = *gid;
     }
 
-    auto descriptor = std::make_unique<T>(args[1], args[2], *uid, *gid, perm, context);
+    socket.context = args.size() > 6 ? args[6] : "";
 
-    auto old = std::find_if(
-            service_->descriptors_.begin(), service_->descriptors_.end(),
-            [&descriptor](const auto& other) { return descriptor.get() == other.get(); });
+    auto old = std::find_if(service_->sockets_.begin(), service_->sockets_.end(),
+                            [&socket](const auto& other) { return socket.name == other.name; });
 
-    if (old != service_->descriptors_.end()) {
-        return Error() << "duplicate descriptor " << args[1] << " " << args[2];
+    if (old != service_->sockets_.end()) {
+        return Error() << "duplicate socket descriptor '" << socket.name << "'";
     }
 
-    service_->descriptors_.emplace_back(std::move(descriptor));
+    service_->sockets_.emplace_back(std::move(socket));
+
     return {};
 }
 
-// name type perm [ uid gid context ]
-Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
-    if (!StartsWith(args[2], "dgram") && !StartsWith(args[2], "stream") &&
-        !StartsWith(args[2], "seqpacket")) {
-        return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket'";
-    }
-    return AddDescriptor<SocketInfo>(std::move(args));
-}
-
-// name type perm [ uid gid context ]
+// name type
 Result<void> ServiceParser::ParseFile(std::vector<std::string>&& args) {
     if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
         return Error() << "file type must be 'r', 'w' or 'rw'";
     }
-    std::string expanded;
-    if (!expand_props(args[1], &expanded)) {
+
+    FileDescriptor file;
+    file.type = args[2];
+
+    if (!expand_props(args[1], &file.name)) {
         return Error() << "Could not expand property in file path '" << args[1] << "'";
     }
-    args[1] = std::move(expanded);
-    if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
+    if (file.name[0] != '/' || file.name.find("../") != std::string::npos) {
         return Error() << "file name must not be relative";
     }
-    return AddDescriptor<FileInfo>(std::move(args));
+
+    auto old = std::find_if(service_->files_.begin(), service_->files_.end(),
+                            [&file](const auto& other) { return other.name == file.name; });
+
+    if (old != service_->files_.end()) {
+        return Error() << "duplicate file descriptor '" << file.name << "'";
+    }
+
+    service_->files_.emplace_back(std::move(file));
+
+    return {};
 }
 
 Result<void> ServiceParser::ParseUser(std::vector<std::string>&& args) {
diff --git a/init/service_parser.h b/init/service_parser.h
index 5ad26ef..bca0739 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -81,9 +81,6 @@
     Result<void> ParseWritepid(std::vector<std::string>&& args);
     Result<void> ParseUpdatable(std::vector<std::string>&& args);
 
-    template <typename T>
-    Result<void> AddDescriptor(std::vector<std::string>&& args);
-
     bool IsValidName(const std::string& name) const;
 
     ServiceList* service_list_;
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index 34aa837..836145d 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -27,9 +27,12 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <cutils/android_get_control_file.h>
+#include <cutils/sockets.h>
 #include <processgroup/processgroup.h>
 
 #include "mount_namespace.h"
+#include "util.h"
 
 using android::base::GetProperty;
 using android::base::StartsWith;
@@ -135,8 +138,52 @@
     dup2(fd, 2);
 }
 
+void PublishDescriptor(const std::string& key, const std::string& name, int fd) {
+    std::string published_name = key + name;
+    for (auto& c : published_name) {
+        c = isalnum(c) ? c : '_';
+    }
+
+    std::string val = std::to_string(fd);
+    setenv(published_name.c_str(), val.c_str(), 1);
+}
+
 }  // namespace
 
+Result<void> SocketDescriptor::CreateAndPublish(const std::string& global_context) const {
+    const auto& socket_context = context.empty() ? global_context : context;
+    auto result = CreateSocket(name, type, passcred, perm, uid, gid, socket_context);
+    if (!result) {
+        return result.error();
+    }
+
+    PublishDescriptor(ANDROID_SOCKET_ENV_PREFIX, name, *result);
+
+    return {};
+}
+
+Result<void> FileDescriptor::CreateAndPublish() const {
+    int flags = (type == "r") ? O_RDONLY : (type == "w") ? O_WRONLY : O_RDWR;
+
+    // Make sure we do not block on open (eg: devices can chose to block on carrier detect).  Our
+    // intention is never to delay launch of a service for such a condition.  The service can
+    // perform its own blocking on carrier detect.
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(name.c_str(), flags | O_NONBLOCK)));
+
+    if (fd < 0) {
+        return ErrnoError() << "Failed to open file '" << name << "'";
+    }
+
+    // Fixup as we set O_NONBLOCK for open, the intent for fd is to block reads.
+    fcntl(fd, F_SETFL, flags);
+
+    LOG(INFO) << "Opened file '" << name << "', flags " << flags;
+
+    PublishDescriptor(ANDROID_FILE_ENV_PREFIX, name, fd.release());
+
+    return {};
+}
+
 Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, bool pre_apexd) {
     for (const auto& [nstype, path] : info.namespaces_to_enter) {
         if (auto result = EnterNamespace(nstype, path.c_str()); !result) {
diff --git a/init/service_utils.h b/init/service_utils.h
index 365cb29..befce25 100644
--- a/init/service_utils.h
+++ b/init/service_utils.h
@@ -29,6 +29,25 @@
 namespace android {
 namespace init {
 
+struct SocketDescriptor {
+    std::string name;
+    int type = 0;
+    uid_t uid = 0;
+    gid_t gid = 0;
+    int perm = 0;
+    std::string context;
+    bool passcred = false;
+
+    Result<void> CreateAndPublish(const std::string& global_context) const;
+};
+
+struct FileDescriptor {
+    std::string name;
+    std::string type;
+
+    Result<void> CreateAndPublish() const;
+};
+
 struct NamespaceInfo {
     int flags;
     // Pair of namespace type, path to name.
diff --git a/init/util.cpp b/init/util.cpp
index 058a111..8bfb755 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -34,6 +34,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/sockets.h>
@@ -77,32 +78,28 @@
  * daemon. We communicate the file descriptor's value via the environment
  * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
  */
-int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
-                 const char* socketcon) {
-    if (socketcon) {
-        if (setsockcreatecon(socketcon) == -1) {
-            PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
-            return -1;
+Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_t perm, uid_t uid,
+                         gid_t gid, const std::string& socketcon) {
+    if (!socketcon.empty()) {
+        if (setsockcreatecon(socketcon.c_str()) == -1) {
+            return ErrnoError() << "setsockcreatecon(\"" << socketcon << "\") failed";
         }
     }
 
     android::base::unique_fd fd(socket(PF_UNIX, type, 0));
     if (fd < 0) {
-        PLOG(ERROR) << "Failed to open socket '" << name << "'";
-        return -1;
+        return ErrnoError() << "Failed to open socket '" << name << "'";
     }
 
-    if (socketcon) setsockcreatecon(NULL);
+    if (!socketcon.empty()) setsockcreatecon(nullptr);
 
     struct sockaddr_un addr;
     memset(&addr, 0 , sizeof(addr));
     addr.sun_family = AF_UNIX;
-    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
-             name);
+    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR "/%s", name.c_str());
 
     if ((unlink(addr.sun_path) != 0) && (errno != ENOENT)) {
-        PLOG(ERROR) << "Failed to unlink old socket '" << name << "'";
-        return -1;
+        return ErrnoError() << "Failed to unlink old socket '" << name << "'";
     }
 
     std::string secontext;
@@ -113,8 +110,7 @@
     if (passcred) {
         int on = 1;
         if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
-            PLOG(ERROR) << "Failed to set SO_PASSCRED '" << name << "'";
-            return -1;
+            return ErrnoError() << "Failed to set SO_PASSCRED '" << name << "'";
         }
     }
 
@@ -125,19 +121,18 @@
         setfscreatecon(nullptr);
     }
 
+    auto guard = android::base::make_scope_guard([&addr] { unlink(addr.sun_path); });
+
     if (ret) {
         errno = savederrno;
-        PLOG(ERROR) << "Failed to bind socket '" << name << "'";
-        goto out_unlink;
+        return ErrnoError() << "Failed to bind socket '" << name << "'";
     }
 
     if (lchown(addr.sun_path, uid, gid)) {
-        PLOG(ERROR) << "Failed to lchown socket '" << addr.sun_path << "'";
-        goto out_unlink;
+        return ErrnoError() << "Failed to lchown socket '" << addr.sun_path << "'";
     }
     if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) {
-        PLOG(ERROR) << "Failed to fchmodat socket '" << addr.sun_path << "'";
-        goto out_unlink;
+        return ErrnoError() << "Failed to fchmodat socket '" << addr.sun_path << "'";
     }
 
     LOG(INFO) << "Created socket '" << addr.sun_path << "'"
@@ -145,11 +140,8 @@
               << ", user " << uid
               << ", group " << gid;
 
+    guard.Disable();
     return fd.release();
-
-out_unlink:
-    unlink(addr.sun_path);
-    return -1;
 }
 
 Result<std::string> ReadFile(const std::string& path) {
diff --git a/init/util.h b/init/util.h
index 1929cb5..6a12fb6 100644
--- a/init/util.h
+++ b/init/util.h
@@ -38,8 +38,8 @@
 
 static const char kColdBootDoneProp[] = "ro.cold_boot_done";
 
-int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
-                 const char* socketcon);
+Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_t perm, uid_t uid,
+                         gid_t gid, const std::string& socketcon);
 
 Result<std::string> ReadFile(const std::string& path);
 Result<void> WriteFile(const std::string& path, const std::string& content);
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 63c3793..ae9dab5 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -28,17 +28,10 @@
  *   mediadrm
  * Whose friendly names do not match the #define statements.
  *
- * Additionally, AID_OEM_RESERVED_START and AID_OEM_RESERVED_END
- * can be used to define reserved OEM ranges used for sanity checks
- * during the build process. The rules are, they must end with START/END
- * The proper convention is incrementing a number like so:
- * AID_OEM_RESERVED_START
- * AID_OEM_RESERVED_1_START
- * AID_OEM_RESERVED_2_START
- * ...
- * The same applies to the END.
- * They are not required to be in order, but must not overlap each other and
- * must define a START and END'ing range. START must be smaller than END.
+ * This file must only be used for platform (Google managed, and submitted through AOSP), AIDs.  3rd
+ * party AIDs must be added via config.fs, which will place them in the corresponding partition's
+ * passwd and group files.  There are ranges in this file reserved for AIDs for each 3rd party
+ * partition, from which the system reads passwd and group files.
  */
 
 #ifndef _ANDROID_FILESYSTEM_CONFIG_H_
@@ -141,8 +134,12 @@
 #define AID_CACHE 2001 /* cache access */
 #define AID_DIAG 2002  /* access to diagnostic resources */
 
-/* The range 2900-2999 is reserved for OEM, and must never be
- * used here */
+/* The range 2900-2999 is reserved for the vendor partition */
+/* Note that the two 'OEM' ranges pre-dated the vendor partition, so they take the legacy 'OEM'
+ * name. Additionally, they pre-dated passwd/group files, so there are users and groups named oem_#
+ * created automatically for all values in these ranges.  If there is a user/group in a passwd/group
+ * file corresponding to this range, both the oem_# and user/group names will resolve to the same
+ * value. */
 #define AID_OEM_RESERVED_START 2900
 #define AID_OEM_RESERVED_END 2999
 
@@ -159,10 +156,26 @@
 #define AID_WAKELOCK 3010     /* Allow system wakelock read/write access */
 #define AID_UHID 3011         /* Allow read/write to /dev/uhid node */
 
-/* The range 5000-5999 is also reserved for OEM, and must never be used here. */
+/* The range 5000-5999 is also reserved for vendor partition. */
 #define AID_OEM_RESERVED_2_START 5000
 #define AID_OEM_RESERVED_2_END 5999
 
+/* The range 6000-6499 is reserved for the system partition. */
+#define AID_SYSTEM_RESERVED_START 6000
+#define AID_SYSTEM_RESERVED_END 6499
+
+/* The range 6500-6999 is reserved for the odm partition. */
+#define AID_ODM_RESERVED_START 6500
+#define AID_ODM_RESERVED_END 6999
+
+/* The range 7000-7499 is reserved for the product partition. */
+#define AID_PRODUCT_RESERVED_START 7000
+#define AID_PRODUCT_RESERVED_END 7499
+
+/* The range 7500-7999 is reserved for the system_ext partition. */
+#define AID_SYSTEM_EXT_RESERVED_START 7500
+#define AID_SYSTEM_EXT_RESERVED_END 7999
+
 #define AID_EVERYBODY 9997 /* shared between all apps in the same profile */
 #define AID_MISC 9998      /* access to misc storage */
 #define AID_NOBODY 9999
diff --git a/libmeminfo/include/meminfo/procmeminfo.h b/libmeminfo/include/meminfo/procmeminfo.h
index 1fb4151..f782ec5 100644
--- a/libmeminfo/include/meminfo/procmeminfo.h
+++ b/libmeminfo/include/meminfo/procmeminfo.h
@@ -45,6 +45,9 @@
     // vector.
     const std::vector<Vma>& MapsWithPageIdle();
 
+    // Same as Maps() except, do not read the usage stats for each map.
+    const std::vector<Vma>& MapsWithoutUsageStats();
+
     // Collect all 'vma' or 'maps' from /proc/<pid>/smaps and store them in 'maps_'. Returns a
     // constant reference to the vma vector after the collection is done.
     //
@@ -88,7 +91,7 @@
     ~ProcMemInfo() = default;
 
   private:
-    bool ReadMaps(bool get_wss, bool use_pageidle = false);
+    bool ReadMaps(bool get_wss, bool use_pageidle = false, bool get_usage_stats = true);
     bool ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle);
 
     pid_t pid_;
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index 5451ca3..4c2be91 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
@@ -60,6 +61,103 @@
     EXPECT_FALSE(maps.empty());
 }
 
+TEST(ProcMemInfo, MapsUsageNotEmpty) {
+    ProcMemInfo proc_mem(pid);
+    const std::vector<Vma>& maps = proc_mem.Maps();
+    EXPECT_FALSE(maps.empty());
+    uint64_t total_pss = 0;
+    uint64_t total_rss = 0;
+    uint64_t total_uss = 0;
+    for (auto& map : maps) {
+        ASSERT_NE(0, map.usage.vss);
+        total_rss += map.usage.rss;
+        total_pss += map.usage.pss;
+        total_uss += map.usage.uss;
+    }
+
+    // Crude check that stats are actually being read.
+    EXPECT_NE(0, total_rss) << "RSS zero for all maps, that is not possible.";
+    EXPECT_NE(0, total_pss) << "PSS zero for all maps, that is not possible.";
+    EXPECT_NE(0, total_uss) << "USS zero for all maps, that is not possible.";
+}
+
+TEST(ProcMemInfo, MapsUsageEmpty) {
+    ProcMemInfo proc_mem(pid);
+    const std::vector<Vma>& maps = proc_mem.MapsWithoutUsageStats();
+    EXPECT_FALSE(maps.empty());
+    // Verify that all usage stats are zero in every map.
+    for (auto& map : maps) {
+        ASSERT_EQ(0, map.usage.vss);
+        ASSERT_EQ(0, map.usage.rss);
+        ASSERT_EQ(0, map.usage.pss);
+        ASSERT_EQ(0, map.usage.uss);
+        ASSERT_EQ(0, map.usage.swap);
+        ASSERT_EQ(0, map.usage.swap_pss);
+        ASSERT_EQ(0, map.usage.private_clean);
+        ASSERT_EQ(0, map.usage.private_dirty);
+        ASSERT_EQ(0, map.usage.shared_clean);
+        ASSERT_EQ(0, map.usage.shared_dirty);
+    }
+}
+
+TEST(ProcMemInfo, PageMapPresent) {
+    static constexpr size_t kNumPages = 20;
+    size_t pagesize = getpagesize();
+    void* ptr = mmap(nullptr, pagesize * (kNumPages + 2), PROT_READ | PROT_WRITE,
+                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    ASSERT_NE(MAP_FAILED, ptr);
+
+    // Unmap the first page and the last page so that we guarantee this
+    // map is in a map by itself.
+    ASSERT_EQ(0, munmap(ptr, pagesize));
+    uintptr_t addr = reinterpret_cast<uintptr_t>(ptr) + pagesize;
+    ASSERT_EQ(0, munmap(reinterpret_cast<void*>(addr + kNumPages * pagesize), pagesize));
+
+    ProcMemInfo proc_mem(getpid());
+    const std::vector<Vma>& maps = proc_mem.MapsWithoutUsageStats();
+    ASSERT_FALSE(maps.empty());
+
+    // Find the vma associated with our previously created map.
+    const Vma* test_vma = nullptr;
+    for (const Vma& vma : maps) {
+        if (vma.start == addr) {
+            test_vma = &vma;
+            break;
+        }
+    }
+    ASSERT_TRUE(test_vma != nullptr) << "Cannot find test map.";
+
+    // Verify that none of the pages are listed as present.
+    std::vector<uint64_t> pagemap;
+    ASSERT_TRUE(proc_mem.PageMap(*test_vma, &pagemap));
+    ASSERT_EQ(kNumPages, pagemap.size());
+    for (size_t i = 0; i < pagemap.size(); i++) {
+        EXPECT_FALSE(android::meminfo::page_present(pagemap[i]))
+                << "Page " << i << " is present and it should not be.";
+    }
+
+    // Make some of the pages present and verify that we see them
+    // as present.
+    uint8_t* data = reinterpret_cast<uint8_t*>(addr);
+    data[0] = 1;
+    data[pagesize * 5] = 1;
+    data[pagesize * 11] = 1;
+
+    ASSERT_TRUE(proc_mem.PageMap(*test_vma, &pagemap));
+    ASSERT_EQ(kNumPages, pagemap.size());
+    for (size_t i = 0; i < pagemap.size(); i++) {
+        if (i == 0 || i == 5 || i == 11) {
+            EXPECT_TRUE(android::meminfo::page_present(pagemap[i]))
+                    << "Page " << i << " is not present and it should be.";
+        } else {
+            EXPECT_FALSE(android::meminfo::page_present(pagemap[i]))
+                    << "Page " << i << " is present and it should not be.";
+        }
+    }
+
+    ASSERT_EQ(0, munmap(reinterpret_cast<void*>(addr), kNumPages * pagesize));
+}
+
 TEST(ProcMemInfo, WssEmpty) {
     // If we created the object for getting usage,
     // the working set must be empty
diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp
index a8b43c1..6f68ab4 100644
--- a/libmeminfo/procmeminfo.cpp
+++ b/libmeminfo/procmeminfo.cpp
@@ -130,6 +130,14 @@
     return maps_;
 }
 
+const std::vector<Vma>& ProcMemInfo::MapsWithoutUsageStats() {
+    if (maps_.empty() && !ReadMaps(get_wss_, false, false)) {
+        LOG(ERROR) << "Failed to read maps for Process " << pid_;
+    }
+
+    return maps_;
+}
+
 const std::vector<Vma>& ProcMemInfo::Smaps(const std::string& path) {
     if (!maps_.empty()) {
         return maps_;
@@ -213,29 +221,30 @@
     std::string pagemap_file = ::android::base::StringPrintf("/proc/%d/pagemap", pid_);
     ::android::base::unique_fd pagemap_fd(
             TEMP_FAILURE_RETRY(open(pagemap_file.c_str(), O_RDONLY | O_CLOEXEC)));
-    if (pagemap_fd < 0) {
+    if (pagemap_fd == -1) {
         PLOG(ERROR) << "Failed to open " << pagemap_file;
         return false;
     }
 
     uint64_t nr_pages = (vma.end - vma.start) / getpagesize();
-    pagemap->reserve(nr_pages);
+    pagemap->resize(nr_pages);
 
-    uint64_t idx = vma.start / getpagesize();
-    uint64_t last = idx + nr_pages;
-    uint64_t val;
-    for (; idx < last; idx++) {
-        if (pread64(pagemap_fd, &val, sizeof(uint64_t), idx * sizeof(uint64_t)) < 0) {
-            PLOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_;
-            return false;
-        }
-        pagemap->emplace_back(val);
+    size_t bytes_to_read = sizeof(uint64_t) * nr_pages;
+    off64_t start_addr = (vma.start / getpagesize()) * sizeof(uint64_t);
+    ssize_t bytes_read = pread64(pagemap_fd, pagemap->data(), bytes_to_read, start_addr);
+    if (bytes_read == -1) {
+        PLOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_;
+        return false;
+    } else if (static_cast<size_t>(bytes_read) != bytes_to_read) {
+        LOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_
+                   << ": read bytes " << bytes_read << " expected bytes " << bytes_to_read;
+        return false;
     }
 
     return true;
 }
 
-bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle) {
+bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle, bool get_usage_stats) {
     // Each object reads /proc/<pid>/maps only once. This is done to make sure programs that are
     // running for the lifetime of the system can recycle the objects and don't have to
     // unnecessarily retain and update this object in memory (which can get significantly large).
@@ -256,6 +265,10 @@
         return false;
     }
 
+    if (!get_usage_stats) {
+        return true;
+    }
+
     std::string pagemap_file = ::android::base::StringPrintf("/proc/%d/pagemap", pid_);
     ::android::base::unique_fd pagemap_fd(
             TEMP_FAILURE_RETRY(open(pagemap_file.c_str(), O_RDONLY | O_CLOEXEC)));
diff --git a/libvndksupport/Android.bp b/libvndksupport/Android.bp
index e5b536c..f4544a1 100644
--- a/libvndksupport/Android.bp
+++ b/libvndksupport/Android.bp
@@ -3,7 +3,7 @@
 cc_library {
     name: "libvndksupport",
     native_bridge_supported: true,
-    srcs: ["linker.c"],
+    srcs: ["linker.cpp"],
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libvndksupport/linker.c b/libvndksupport/linker.c
deleted file mode 100644
index 84c2132..0000000
--- a/libvndksupport/linker.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2017 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 "linker.h"
-
-#include <android/dlext.h>
-#include <dlfcn.h>
-
-#define LOG_TAG "vndksupport"
-#include <log/log.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-__attribute__((weak)) extern struct android_namespace_t* android_get_exported_namespace(const char*);
-__attribute__((weak)) extern void* android_dlopen_ext(const char*, int, const android_dlextinfo*);
-
-static const char* namespace_name = NULL;
-
-static struct android_namespace_t* get_vendor_namespace() {
-    const char* namespace_names[] = {"sphal", "default", NULL};
-    static struct android_namespace_t* vendor_namespace = NULL;
-    if (vendor_namespace == NULL) {
-        int name_idx = 0;
-        while (namespace_names[name_idx] != NULL) {
-            if (android_get_exported_namespace != NULL) {
-                vendor_namespace = android_get_exported_namespace(namespace_names[name_idx]);
-            }
-            if (vendor_namespace != NULL) {
-                namespace_name = namespace_names[name_idx];
-                break;
-            }
-            name_idx++;
-        }
-    }
-    return vendor_namespace;
-}
-
-int android_is_in_vendor_process() {
-    // Special case init, since when init runs, ld.config.<ver>.txt hasn't been
-    // loaded (sysprop service isn't up for init to know <ver>).
-    if (getpid() == 1) {
-        return 0;
-    }
-    if (android_get_exported_namespace == NULL) {
-        ALOGD("android_get_exported_namespace() not available. Assuming system process.");
-        return 0;
-    }
-
-    // In vendor process, 'vndk' namespace is not visible, whereas in system
-    // process, it is.
-    return android_get_exported_namespace("vndk") == NULL;
-}
-
-void* android_load_sphal_library(const char* name, int flag) {
-    struct android_namespace_t* vendor_namespace = get_vendor_namespace();
-    if (vendor_namespace != NULL) {
-        const android_dlextinfo dlextinfo = {
-            .flags = ANDROID_DLEXT_USE_NAMESPACE, .library_namespace = vendor_namespace,
-        };
-        void* handle = NULL;
-        if (android_dlopen_ext != NULL) {
-            handle = android_dlopen_ext(name, flag, &dlextinfo);
-        }
-        if (!handle) {
-            ALOGE("Could not load %s from %s namespace: %s.", name, namespace_name, dlerror());
-        }
-        return handle;
-    } else {
-        ALOGD("Loading %s from current namespace instead of sphal namespace.", name);
-        return dlopen(name, flag);
-    }
-}
-
-int android_unload_sphal_library(void* handle) {
-    return dlclose(handle);
-}
diff --git a/libvndksupport/linker.cpp b/libvndksupport/linker.cpp
new file mode 100644
index 0000000..cf0f618
--- /dev/null
+++ b/libvndksupport/linker.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "vndksupport"
+
+#include "linker.h"
+
+#include <android/dlext.h>
+#include <dlfcn.h>
+#include <log/log.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <initializer_list>
+
+__attribute__((weak)) extern "C" android_namespace_t* android_get_exported_namespace(const char*);
+__attribute__((weak)) extern "C" void* android_dlopen_ext(const char*, int,
+                                                          const android_dlextinfo*);
+
+namespace {
+
+struct VendorNamespace {
+    android_namespace_t* ptr = nullptr;
+    const char* name = nullptr;
+};
+
+}  // anonymous namespace
+
+static VendorNamespace get_vendor_namespace() {
+    static VendorNamespace result = ([] {
+        for (const char* name : {"sphal", "default"}) {
+            if (android_get_exported_namespace != nullptr) {
+                if (android_namespace_t* ns = android_get_exported_namespace(name)) {
+                    return VendorNamespace{ns, name};
+                }
+            }
+        }
+        return VendorNamespace{};
+    })();
+    return result;
+}
+
+int android_is_in_vendor_process() {
+    // Special case init, since when init runs, ld.config.<ver>.txt hasn't been
+    // loaded (sysprop service isn't up for init to know <ver>).
+    if (getpid() == 1) {
+        return 0;
+    }
+    if (android_get_exported_namespace == nullptr) {
+        ALOGD("android_get_exported_namespace() not available. Assuming system process.");
+        return 0;
+    }
+
+    // In vendor process, 'vndk' namespace is not visible, whereas in system
+    // process, it is.
+    return android_get_exported_namespace("vndk") == nullptr;
+}
+
+void* android_load_sphal_library(const char* name, int flag) {
+    VendorNamespace vendor_namespace = get_vendor_namespace();
+    if (vendor_namespace.ptr != nullptr) {
+        const android_dlextinfo dlextinfo = {
+                .flags = ANDROID_DLEXT_USE_NAMESPACE,
+                .library_namespace = vendor_namespace.ptr,
+        };
+        void* handle = nullptr;
+        if (android_dlopen_ext != nullptr) {
+            handle = android_dlopen_ext(name, flag, &dlextinfo);
+        }
+        if (!handle) {
+            ALOGE("Could not load %s from %s namespace: %s.", name, vendor_namespace.name,
+                  dlerror());
+        }
+        return handle;
+    } else {
+        ALOGD("Loading %s from current namespace instead of sphal namespace.", name);
+        return dlopen(name, flag);
+    }
+}
+
+int android_unload_sphal_library(void* handle) {
+    return dlclose(handle);
+}
diff --git a/libvndksupport/tests/linker_test.cpp b/libvndksupport/tests/linker_test.cpp
index 7ce27d4..d0c8ef7 100644
--- a/libvndksupport/tests/linker_test.cpp
+++ b/libvndksupport/tests/linker_test.cpp
@@ -21,11 +21,6 @@
 #include <vndksupport/linker.h>
 #include <string>
 
-// Since the test executable will be in /data and ld.config.txt does not
-// configure sphal namespace for executables in /data, the call to
-// android_load_sphal_library will always fallback to the plain dlopen from the
-// default namespace.
-
 // Let's use libEGL_<chipset>.so as a SP-HAL in test
 static std::string find_sphal_lib() {
     const char* path =
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 96ffa69..a5bfc41 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -38,6 +38,13 @@
     # Allow up to 32K FDs per process
     setrlimit nofile 32768 32768
 
+    # Create directory to keep ld.config.txt
+    mkdir /dev/linkerconfig 0755
+
+    # Generate ld.config.txt for early executed processes
+    exec -- /system/bin/linkerconfig --target /dev/linkerconfig/ld.config.txt
+    chmod 444 /dev/linkerconfig/ld.config.txt
+
     start ueventd
 
     # Run apexd-bootstrap so that APEXes that provide critical libraries