Merge "Support fastboot variable battery-soc-ok"
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index c00d955..4cbc45a 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -408,7 +408,8 @@
     for (int i = argc - 1; i >= 0; i--) {
         const char* file = argv[i];
 
-        if (android::base::EndsWithIgnoreCase(file, ".apk")) {
+        if (android::base::EndsWithIgnoreCase(file, ".apk") ||
+            android::base::EndsWithIgnoreCase(file, ".dm")) {
             struct stat sb;
             if (stat(file, &sb) != -1) total_size += sb.st_size;
             first_apk = i;
@@ -470,9 +471,9 @@
         }
 
         std::string cmd =
-                android::base::StringPrintf("%s install-write -S %" PRIu64 " %d %d_%s -",
+                android::base::StringPrintf("%s install-write -S %" PRIu64 " %d %s -",
                                             install_cmd.c_str(), static_cast<uint64_t>(sb.st_size),
-                                            session_id, i, android::base::Basename(file).c_str());
+                                            session_id, android::base::Basename(file).c_str());
 
         int localFd = adb_open(file, O_RDONLY);
         if (localFd < 0) {
diff --git a/adb/types.h b/adb/types.h
index a3e5d48..1f7008e 100644
--- a/adb/types.h
+++ b/adb/types.h
@@ -42,14 +42,14 @@
     }
 
     Block(const Block& copy) = delete;
-    Block(Block&& move) {
+    Block(Block&& move) noexcept {
         std::swap(data_, move.data_);
         std::swap(capacity_, move.capacity_);
         std::swap(size_, move.size_);
     }
 
     Block& operator=(const Block& copy) = delete;
-    Block& operator=(Block&& move) {
+    Block& operator=(Block&& move) noexcept {
         clear();
 
         std::swap(data_, move.data_);
@@ -147,12 +147,10 @@
     }
 
     IOVector(const IOVector& copy) = delete;
-    IOVector(IOVector&& move) : IOVector() {
-        *this = std::move(move);
-    }
+    IOVector(IOVector&& move) noexcept : IOVector() { *this = std::move(move); }
 
     IOVector& operator=(const IOVector& copy) = delete;
-    IOVector& operator=(IOVector&& move) {
+    IOVector& operator=(IOVector&& move) noexcept {
         chain_ = std::move(move.chain_);
         chain_length_ = move.chain_length_;
         begin_offset_ = move.begin_offset_;
diff --git a/base/include/android-base/scopeguard.h b/base/include/android-base/scopeguard.h
index e6a9d10..5a224d6 100644
--- a/base/include/android-base/scopeguard.h
+++ b/base/include/android-base/scopeguard.h
@@ -28,7 +28,7 @@
  public:
   ScopeGuard(F&& f) : f_(std::forward<F>(f)), active_(true) {}
 
-  ScopeGuard(ScopeGuard&& that) : f_(std::move(that.f_)), active_(that.active_) {
+  ScopeGuard(ScopeGuard&& that) noexcept : f_(std::move(that.f_)), active_(that.active_) {
     that.active_ = false;
   }
 
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 71025ad..cd2dc04 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -90,8 +90,8 @@
   explicit unique_fd_impl(int fd) { reset(fd); }
   ~unique_fd_impl() { reset(); }
 
-  unique_fd_impl(unique_fd_impl&& other) { reset(other.release()); }
-  unique_fd_impl& operator=(unique_fd_impl&& s) {
+  unique_fd_impl(unique_fd_impl&& other) noexcept { reset(other.release()); }
+  unique_fd_impl& operator=(unique_fd_impl&& s) noexcept {
     int fd = s.fd_;
     s.fd_ = -1;
     reset(fd, &s);
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 51585b3..3f663ef 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -27,6 +27,7 @@
 #include <android-base/unique_fd.h>
 #include <cutils/android_reboot.h>
 #include <ext4_utils/wipe.h>
+#include <fs_mgr.h>
 #include <liblp/builder.h>
 #include <liblp/liblp.h>
 #include <uuid/uuid.h>
@@ -311,7 +312,7 @@
 };
 
 PartitionBuilder::PartitionBuilder(FastbootDevice* device) {
-    auto super_device = FindPhysicalPartition(LP_METADATA_PARTITION_NAME);
+    auto super_device = FindPhysicalPartition(fs_mgr_get_super_partition_name());
     if (!super_device) {
         return;
     }
@@ -354,13 +355,7 @@
         return device->WriteFail("Partition already exists");
     }
 
-    // Make a random UUID, since they're not currently used.
-    uuid_t uuid;
-    char uuid_str[37];
-    uuid_generate_random(uuid);
-    uuid_unparse(uuid, uuid_str);
-
-    Partition* partition = builder->AddPartition(partition_name, uuid_str, 0);
+    Partition* partition = builder->AddPartition(partition_name, 0);
     if (!partition) {
         return device->WriteFail("Failed to add partition");
     }
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index a383c54..4fc3d1d 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -146,8 +146,7 @@
         if (builder->FindPartition(name)) {
             continue;
         }
-        std::string guid = GetPartitionGuid(partition);
-        if (!builder->AddPartition(name, guid, partition.attributes)) {
+        if (!builder->AddPartition(name, partition.attributes)) {
             return device->WriteFail("Unable to add partition: " + name);
         }
     }
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index 02f6f2c..528abec 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -23,6 +23,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <fs_mgr.h>
 #include <fs_mgr_dm_linear.h>
 #include <liblp/liblp.h>
 
@@ -44,7 +45,7 @@
 
 static bool OpenLogicalPartition(const std::string& name, const std::string& slot,
                                  PartitionHandle* handle) {
-    std::optional<std::string> path = FindPhysicalPartition(LP_METADATA_PARTITION_NAME);
+    std::optional<std::string> path = FindPhysicalPartition(fs_mgr_get_super_partition_name());
     if (!path) {
         return false;
     }
@@ -100,7 +101,7 @@
 
 bool LogicalPartitionExists(const std::string& name, const std::string& slot_suffix,
                             bool* is_zero_length) {
-    auto path = FindPhysicalPartition(LP_METADATA_PARTITION_NAME);
+    auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name());
     if (!path) {
         return false;
     }
@@ -149,7 +150,7 @@
     }
 
     // Next get logical partitions.
-    if (auto path = FindPhysicalPartition(LP_METADATA_PARTITION_NAME)) {
+    if (auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name())) {
         uint32_t slot_number = SlotNumberForSlotSuffix(device->GetCurrentSlot());
         if (auto metadata = ReadMetadata(path->c_str(), slot_number)) {
             for (const auto& partition : metadata->partitions) {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 1598a5c..3ab9732 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -55,6 +55,7 @@
 #include <ext4_utils/wipe.h>
 #include <fs_mgr_overlayfs.h>
 #include <libdm/dm.h>
+#include <liblp/metadata_format.h>
 #include <linux/fs.h>
 #include <linux/loop.h>
 #include <linux/magic.h>
@@ -1343,29 +1344,25 @@
              * on a system (all the memory comes from the same pool) so
              * we can assume the device number is 0.
              */
-            FILE *zram_fp;
-            FILE *zram_mcs_fp;
-
             if (fstab->recs[i].max_comp_streams >= 0) {
-               zram_mcs_fp = fopen(ZRAM_CONF_MCS, "r+");
-              if (zram_mcs_fp == NULL) {
-                LERROR << "Unable to open zram conf comp device "
-                       << ZRAM_CONF_MCS;
-                ret = -1;
-                continue;
-              }
-              fprintf(zram_mcs_fp, "%d\n", fstab->recs[i].max_comp_streams);
-              fclose(zram_mcs_fp);
+                auto zram_mcs_fp = std::unique_ptr<FILE, decltype(&fclose)>{
+                        fopen(ZRAM_CONF_MCS, "re"), fclose};
+                if (zram_mcs_fp == NULL) {
+                    LERROR << "Unable to open zram conf comp device " << ZRAM_CONF_MCS;
+                    ret = -1;
+                    continue;
+                }
+                fprintf(zram_mcs_fp.get(), "%d\n", fstab->recs[i].max_comp_streams);
             }
 
-            zram_fp = fopen(ZRAM_CONF_DEV, "r+");
+            auto zram_fp =
+                    std::unique_ptr<FILE, decltype(&fclose)>{fopen(ZRAM_CONF_DEV, "re+"), fclose};
             if (zram_fp == NULL) {
                 LERROR << "Unable to open zram conf device " << ZRAM_CONF_DEV;
                 ret = -1;
                 continue;
             }
-            fprintf(zram_fp, "%u\n", fstab->recs[i].zram_size);
-            fclose(zram_fp);
+            fprintf(zram_fp.get(), "%u\n", fstab->recs[i].zram_size);
         }
 
         if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
@@ -1544,3 +1541,7 @@
 
     return true;
 }
+
+std::string fs_mgr_get_super_partition_name(int /* slot */) {
+    return LP_METADATA_DEFAULT_PARTITION_NAME;
+}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 250793a..fc3a05c 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -732,21 +732,19 @@
 
 struct fstab *fs_mgr_read_fstab(const char *fstab_path)
 {
-    FILE *fstab_file;
     struct fstab *fstab;
 
-    fstab_file = fopen(fstab_path, "r");
+    auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(fstab_path, "re"), fclose};
     if (!fstab_file) {
         PERROR << __FUNCTION__<< "(): cannot open file: '" << fstab_path << "'";
         return nullptr;
     }
 
-    fstab = fs_mgr_read_fstab_file(fstab_file, !strcmp("/proc/mounts", fstab_path));
+    fstab = fs_mgr_read_fstab_file(fstab_file.get(), !strcmp("/proc/mounts", fstab_path));
     if (!fstab) {
         LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << fstab_path << "'";
     }
 
-    fclose(fstab_file);
     return fstab;
 }
 
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 07b2a7a..1edd573 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -53,6 +53,10 @@
     return false;
 }
 
+std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab*) {
+    return {};
+}
+
 bool fs_mgr_overlayfs_setup(const char*, const char*, bool* change) {
     if (change) *change = false;
     return false;
@@ -294,6 +298,28 @@
 
 constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0";
 
+bool fs_mgr_overlayfs_setup_dir(const std::string& dir, std::string* overlay, bool* change) {
+    auto ret = true;
+    auto top = dir + kOverlayTopDir;
+    if (setfscreatecon(kOverlayfsFileContext)) {
+        ret = false;
+        PERROR << "setfscreatecon " << kOverlayfsFileContext;
+    }
+    auto save_errno = errno;
+    if (!mkdir(top.c_str(), 0755)) {
+        if (change) *change = true;
+    } else if (errno != EEXIST) {
+        ret = false;
+        PERROR << "mkdir " << top;
+    } else {
+        errno = save_errno;
+    }
+    setfscreatecon(nullptr);
+
+    if (overlay) *overlay = std::move(top);
+    return ret;
+}
+
 bool fs_mgr_overlayfs_setup_one(const std::string& overlay, const std::string& mount_point,
                                 bool* change) {
     auto ret = true;
@@ -344,6 +370,50 @@
     return ret;
 }
 
+bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string& mount_point,
+                                   bool* change) {
+    const auto top = overlay + kOverlayTopDir;
+    auto save_errno = errno;
+    auto missing = access(top.c_str(), F_OK);
+    errno = save_errno;
+    if (missing) return false;
+
+    const auto oldpath = top + (mount_point.empty() ? "" : ("/"s + mount_point));
+    const auto newpath = oldpath + ".teardown";
+    auto ret = fs_mgr_rm_all(newpath);
+    save_errno = errno;
+    if (!rename(oldpath.c_str(), newpath.c_str())) {
+        if (change) *change = true;
+    } else if (errno != ENOENT) {
+        ret = false;
+        PERROR << "mv " << oldpath << " " << newpath;
+    } else {
+        errno = save_errno;
+    }
+    ret &= fs_mgr_rm_all(newpath, change);
+    save_errno = errno;
+    if (!rmdir(newpath.c_str())) {
+        if (change) *change = true;
+    } else if (errno != ENOENT) {
+        ret = false;
+        PERROR << "rmdir " << newpath;
+    } else {
+        errno = save_errno;
+    }
+    if (!mount_point.empty()) {
+        save_errno = errno;
+        if (!rmdir(top.c_str())) {
+            if (change) *change = true;
+        } else if ((errno != ENOENT) && (errno != ENOTEMPTY)) {
+            ret = false;
+            PERROR << "rmdir " << top;
+        } else {
+            errno = save_errno;
+        }
+    }
+    return ret;
+}
+
 bool fs_mgr_overlayfs_mount(const std::string& mount_point) {
     auto options = fs_mgr_get_overlayfs_options(mount_point);
     if (options.empty()) return false;
@@ -423,6 +493,10 @@
     return ret;
 }
 
+std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab*) {
+    return {};
+}
+
 // Returns false if setup not permitted, errno set to last error.
 // If something is altered, set *change.
 bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change) {
@@ -445,19 +519,9 @@
     auto mounts = fs_mgr_candidate_list(fstab.get(), fs_mgr_mount_point(fstab.get(), mount_point));
     if (fstab && mounts.empty()) return ret;
 
-    if (setfscreatecon(kOverlayfsFileContext)) {
-        PERROR << "setfscreatecon " << kOverlayfsFileContext;
-    }
-    auto overlay = kOverlayMountPoint + kOverlayTopDir;
-    auto save_errno = errno;
-    if (!mkdir(overlay.c_str(), 0755)) {
-        if (change) *change = true;
-    } else if (errno != EEXIST) {
-        PERROR << "mkdir " << overlay;
-    } else {
-        errno = save_errno;
-    }
-    setfscreatecon(nullptr);
+    std::string overlay;
+    ret |= fs_mgr_overlayfs_setup_dir(kOverlayMountPoint, &overlay, change);
+
     if (!fstab && mount_point && fs_mgr_overlayfs_setup_one(overlay, mount_point, change)) {
         ret = true;
     }
@@ -475,41 +539,7 @@
                                              fs_mgr_read_fstab_default(), fs_mgr_free_fstab)
                                              .get(),
                                      mount_point);
-    auto ret = true;
-    const auto overlay = kOverlayMountPoint + kOverlayTopDir;
-    const auto oldpath = overlay + (mount_point ? "/"s + mount_point : ""s);
-    const auto newpath = oldpath + ".teardown";
-    ret &= fs_mgr_rm_all(newpath);
-    auto save_errno = errno;
-    if (!rename(oldpath.c_str(), newpath.c_str())) {
-        if (change) *change = true;
-    } else if (errno != ENOENT) {
-        ret = false;
-        PERROR << "mv " << oldpath << " " << newpath;
-    } else {
-        errno = save_errno;
-    }
-    ret &= fs_mgr_rm_all(newpath, change);
-    save_errno = errno;
-    if (!rmdir(newpath.c_str())) {
-        if (change) *change = true;
-    } else if (errno != ENOENT) {
-        ret = false;
-        PERROR << "rmdir " << newpath;
-    } else {
-        errno = save_errno;
-    }
-    if (mount_point) {
-        save_errno = errno;
-        if (!rmdir(overlay.c_str())) {
-            if (change) *change = true;
-        } else if ((errno != ENOENT) && (errno != ENOTEMPTY)) {
-            ret = false;
-            PERROR << "rmdir " << overlay;
-        } else {
-            errno = save_errno;
-        }
-    }
+    auto ret = fs_mgr_overlayfs_teardown_one(kOverlayMountPoint, mount_point ?: "", change);
     if (!fs_mgr_wants_overlayfs()) {
         // After obligatory teardown to make sure everything is clean, but if
         // we didn't want overlayfs in the the first place, we do not want to
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 5fb4ebb..2727a6d 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -89,24 +89,21 @@
 {
     uint8_t key_data[ANDROID_PUBKEY_ENCODED_SIZE];
 
-    FILE* f = fopen(path, "r");
+    auto f = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path, "re"), fclose};
     if (!f) {
         LERROR << "Can't open " << path;
-        return NULL;
+        return nullptr;
     }
 
-    if (!fread(key_data, sizeof(key_data), 1, f)) {
+    if (!fread(key_data, sizeof(key_data), 1, f.get())) {
         LERROR << "Could not read key!";
-        fclose(f);
-        return NULL;
+        return nullptr;
     }
 
-    fclose(f);
-
-    RSA* key = NULL;
+    RSA* key = nullptr;
     if (!android_pubkey_decode(key_data, sizeof(key_data), &key)) {
         LERROR << "Could not parse key!";
-        return NULL;
+        return nullptr;
     }
 
     return key;
@@ -368,7 +365,6 @@
 static int metadata_find(const char *fname, const char *stag,
         unsigned int slength, off64_t *offset)
 {
-    FILE *fp = NULL;
     char tag[METADATA_TAG_MAX_LENGTH + 1];
     int rc = -1;
     int n;
@@ -380,75 +376,64 @@
         return -1;
     }
 
-    fp = fopen(fname, "r+");
+    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(fname, "re+"), fclose};
 
     if (!fp) {
         PERROR << "Failed to open " << fname;
-        goto out;
+        return -1;
     }
 
     /* check magic */
-    if (fseek(fp, start, SEEK_SET) < 0 ||
-        fread(&magic, sizeof(magic), 1, fp) != 1) {
+    if (fseek(fp.get(), start, SEEK_SET) < 0 || fread(&magic, sizeof(magic), 1, fp.get()) != 1) {
         PERROR << "Failed to read magic from " << fname;
-        goto out;
+        return -1;
     }
 
     if (magic != METADATA_MAGIC) {
         magic = METADATA_MAGIC;
 
-        if (fseek(fp, start, SEEK_SET) < 0 ||
-            fwrite(&magic, sizeof(magic), 1, fp) != 1) {
+        if (fseek(fp.get(), start, SEEK_SET) < 0 ||
+            fwrite(&magic, sizeof(magic), 1, fp.get()) != 1) {
             PERROR << "Failed to write magic to " << fname;
-            goto out;
+            return -1;
         }
 
-        rc = metadata_add(fp, start + sizeof(magic), stag, slength, offset);
+        rc = metadata_add(fp.get(), start + sizeof(magic), stag, slength, offset);
         if (rc < 0) {
             PERROR << "Failed to add metadata to " << fname;
         }
 
-        goto out;
+        return rc;
     }
 
     start += sizeof(magic);
 
     while (1) {
-        n = fscanf(fp, "%" STRINGIFY(METADATA_TAG_MAX_LENGTH) "s %u\n",
-                tag, &length);
+        n = fscanf(fp.get(), "%" STRINGIFY(METADATA_TAG_MAX_LENGTH) "s %u\n", tag, &length);
 
         if (n == 2 && strcmp(tag, METADATA_EOD)) {
             /* found a tag */
-            start = ftell(fp);
+            start = ftell(fp.get());
 
             if (!strcmp(tag, stag) && length == slength) {
                 *offset = start;
-                rc = 0;
-                goto out;
+                return 0;
             }
 
             start += length;
 
-            if (fseek(fp, length, SEEK_CUR) < 0) {
+            if (fseek(fp.get(), length, SEEK_CUR) < 0) {
                 PERROR << "Failed to seek " << fname;
-                goto out;
+                return -1;
             }
         } else {
-            rc = metadata_add(fp, start, stag, slength, offset);
+            rc = metadata_add(fp.get(), start, stag, slength, offset);
             if (rc < 0) {
                 PERROR << "Failed to write metadata to " << fname;
             }
-            goto out;
+            return rc;
         }
-   }
-
-out:
-    if (fp) {
-        fflush(fp);
-        fclose(fp);
     }
-
-    return rc;
 }
 
 static int write_verity_state(const char *fname, off64_t offset, int32_t mode)
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index cee069b..a4544b2 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -23,6 +23,7 @@
 #include <linux/dm-ioctl.h>
 
 #include <functional>
+#include <string>
 
 #include <fstab/fstab.h>
 
@@ -89,4 +90,9 @@
 #define FS_MGR_SETUP_VERITY_SUCCESS 0
 int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev);
 
+// Return the name of the super partition if it exists. If a slot number is
+// specified, the super partition for the corresponding metadata slot will be
+// returned. Otherwise, it will use the current slot.
+std::string fs_mgr_get_super_partition_name(int slot = -1);
+
 #endif /* __CORE_FS_MGR_H */
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index 251dd9b..3274e0e 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -19,8 +19,10 @@
 #include <fstab/fstab.h>
 
 #include <string>
+#include <vector>
 
 bool fs_mgr_overlayfs_mount_all(const fstab* fstab);
+std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab* fstab);
 bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
                             bool* change = nullptr);
 bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index cc61917..70823c6 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -59,7 +59,8 @@
         : dm_(DeviceMapper::Instance()), name_(name), valid_(false) {
         valid_ = dm_.CreateDevice(name, table);
     }
-    TempDevice(TempDevice&& other) : dm_(other.dm_), name_(other.name_), valid_(other.valid_) {
+    TempDevice(TempDevice&& other) noexcept
+        : dm_(other.dm_), name_(other.name_), valid_(other.valid_) {
         other.valid_ = false;
     }
     ~TempDevice() {
@@ -103,7 +104,7 @@
     TempDevice(const TempDevice&) = delete;
     TempDevice& operator=(const TempDevice&) = delete;
 
-    TempDevice& operator=(TempDevice&& other) {
+    TempDevice& operator=(TempDevice&& other) noexcept {
         name_ = other.name_;
         valid_ = other.valid_;
         other.valid_ = false;
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index 89282db..69dc065 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -35,7 +35,6 @@
         "libcrypto",
         "libcrypto_utils",
         "libsparse",
-        "libext2_uuid",
         "libext4_utils",
         "libz",
     ],
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index d9a0e9c..97b15bd 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -25,7 +25,6 @@
 #include <algorithm>
 
 #include <android-base/unique_fd.h>
-#include <uuid/uuid.h>
 
 #include "liblp/liblp.h"
 #include "reader.h"
@@ -79,9 +78,8 @@
     out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_ZERO, 0});
 }
 
-Partition::Partition(const std::string& name, const std::string& group_name,
-                     const std::string& guid, uint32_t attributes)
-    : name_(name), group_name_(group_name), guid_(guid), attributes_(attributes), size_(0) {}
+Partition::Partition(const std::string& name, const std::string& group_name, uint32_t attributes)
+    : name_(name), group_name_(group_name), attributes_(attributes), size_(0) {}
 
 void Partition::AddExtent(std::unique_ptr<Extent>&& extent) {
     size_ += extent->num_sectors() * LP_SECTOR_SIZE;
@@ -202,8 +200,8 @@
 
     for (const auto& partition : metadata.partitions) {
         std::string group_name = GetPartitionGroupName(metadata.groups[partition.group_index]);
-        Partition* builder = AddPartition(GetPartitionName(partition), group_name,
-                                          GetPartitionGuid(partition), partition.attributes);
+        Partition* builder =
+                AddPartition(GetPartitionName(partition), group_name, partition.attributes);
         if (!builder) {
             return false;
         }
@@ -329,13 +327,12 @@
     return true;
 }
 
-Partition* MetadataBuilder::AddPartition(const std::string& name, const std::string& guid,
-                                         uint32_t attributes) {
-    return AddPartition(name, "default", guid, attributes);
+Partition* MetadataBuilder::AddPartition(const std::string& name, uint32_t attributes) {
+    return AddPartition(name, "default", attributes);
 }
 
 Partition* MetadataBuilder::AddPartition(const std::string& name, const std::string& group_name,
-                                         const std::string& guid, uint32_t attributes) {
+                                         uint32_t attributes) {
     if (name.empty()) {
         LERROR << "Partition must have a non-empty name.";
         return nullptr;
@@ -348,7 +345,7 @@
         LERROR << "Could not find partition group: " << group_name;
         return nullptr;
     }
-    partitions_.push_back(std::make_unique<Partition>(name, group_name, guid, attributes));
+    partitions_.push_back(std::make_unique<Partition>(name, group_name, attributes));
     return partitions_.back().get();
 }
 
@@ -549,12 +546,6 @@
         }
 
         strncpy(part.name, partition->name().c_str(), sizeof(part.name));
-        if (uuid_parse(partition->guid().c_str(), part.guid) != 0) {
-            LERROR << "Could not parse guid " << partition->guid() << " for partition "
-                   << partition->name();
-            return nullptr;
-        }
-
         part.first_extent_index = static_cast<uint32_t>(metadata->extents.size());
         part.num_extents = static_cast<uint32_t>(partition->extents().size());
         part.attributes = partition->attributes();
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 711cc64..c916b44 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -22,16 +22,12 @@
 using namespace std;
 using namespace android::fs_mgr;
 
-static const char* TEST_GUID = "A799D1D6-669F-41D8-A3F0-EBB7572D8302";
-static const char* TEST_GUID2 = "A799D1D6-669F-41D8-A3F0-EBB7572D8303";
-
 TEST(liblp, BuildBasic) {
     unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
 
-    Partition* partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+    Partition* partition = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
     ASSERT_NE(partition, nullptr);
     EXPECT_EQ(partition->name(), "system");
-    EXPECT_EQ(partition->guid(), TEST_GUID);
     EXPECT_EQ(partition->attributes(), LP_PARTITION_ATTR_READONLY);
     EXPECT_EQ(partition->size(), 0);
     EXPECT_EQ(builder->FindPartition("system"), partition);
@@ -43,7 +39,7 @@
 TEST(liblp, ResizePartition) {
     unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
 
-    Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+    Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
     ASSERT_NE(system, nullptr);
     EXPECT_EQ(builder->ResizePartition(system, 65536), true);
     EXPECT_EQ(system->size(), 65536);
@@ -94,7 +90,7 @@
     unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
 
     // Test that we align up to one sector.
-    Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+    Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
     ASSERT_NE(system, nullptr);
     EXPECT_EQ(builder->ResizePartition(system, 10000), true);
     EXPECT_EQ(system->size(), 12288);
@@ -171,9 +167,9 @@
     BlockDeviceInfo device_info(512 * 1024 * 1024, 768 * 1024, 753664, 4096);
     unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 32 * 1024, 2);
 
-    Partition* a = builder->AddPartition("a", TEST_GUID, 0);
+    Partition* a = builder->AddPartition("a", 0);
     ASSERT_NE(a, nullptr);
-    Partition* b = builder->AddPartition("b", TEST_GUID2, 0);
+    Partition* b = builder->AddPartition("b", 0);
     ASSERT_NE(b, nullptr);
 
     // Add a bunch of small extents to each, interleaving.
@@ -214,7 +210,7 @@
     EXPECT_EQ(builder->AllocatableSpace(), allocatable);
     EXPECT_EQ(builder->UsedSpace(), 0);
 
-    Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+    Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
     ASSERT_NE(system, nullptr);
     EXPECT_EQ(builder->ResizePartition(system, allocatable), true);
     EXPECT_EQ(system->size(), allocatable);
@@ -229,8 +225,8 @@
 TEST(liblp, BuildComplex) {
     unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
 
-    Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
-    Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
+    Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
+    Partition* vendor = builder->AddPartition("vendor", LP_PARTITION_ATTR_READONLY);
     ASSERT_NE(system, nullptr);
     ASSERT_NE(vendor, nullptr);
     EXPECT_EQ(builder->ResizePartition(system, 65536), true);
@@ -263,15 +259,15 @@
 TEST(liblp, AddInvalidPartition) {
     unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
 
-    Partition* partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+    Partition* partition = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
     ASSERT_NE(partition, nullptr);
 
     // Duplicate name.
-    partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+    partition = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
     EXPECT_EQ(partition, nullptr);
 
     // Empty name.
-    partition = builder->AddPartition("", TEST_GUID, LP_PARTITION_ATTR_READONLY);
+    partition = builder->AddPartition("", LP_PARTITION_ATTR_READONLY);
     EXPECT_EQ(partition, nullptr);
 }
 
@@ -282,8 +278,8 @@
     unique_ptr<MetadataBuilder> builder =
             MetadataBuilder::New(kDiskSize, kMetadataSize, kMetadataSlots);
 
-    Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
-    Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
+    Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
+    Partition* vendor = builder->AddPartition("vendor", LP_PARTITION_ATTR_READONLY);
     ASSERT_NE(system, nullptr);
     ASSERT_NE(vendor, nullptr);
     EXPECT_EQ(builder->ResizePartition(system, 65536), true);
@@ -322,7 +318,6 @@
     for (const auto& partition : exported->partitions) {
         Partition* original = builder->FindPartition(GetPartitionName(partition));
         ASSERT_NE(original, nullptr);
-        EXPECT_EQ(original->guid(), GetPartitionGuid(partition));
         for (size_t i = 0; i < partition.num_extents; i++) {
             const auto& extent = exported->extents[partition.first_extent_index + i];
             LinearExtent* original_extent = original->extents()[i]->AsLinearExtent();
@@ -337,8 +332,8 @@
 TEST(liblp, BuilderImport) {
     unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
 
-    Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
-    Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
+    Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
+    Partition* vendor = builder->AddPartition("vendor", LP_PARTITION_ATTR_READONLY);
     ASSERT_NE(system, nullptr);
     ASSERT_NE(vendor, nullptr);
     EXPECT_EQ(builder->ResizePartition(system, 65536), true);
@@ -357,11 +352,9 @@
 
     EXPECT_EQ(system->size(), 98304);
     ASSERT_EQ(system->extents().size(), 2);
-    EXPECT_EQ(system->guid(), TEST_GUID);
     EXPECT_EQ(system->attributes(), LP_PARTITION_ATTR_READONLY);
     EXPECT_EQ(vendor->size(), 32768);
     ASSERT_EQ(vendor->extents().size(), 1);
-    EXPECT_EQ(vendor->guid(), TEST_GUID2);
     EXPECT_EQ(vendor->attributes(), LP_PARTITION_ATTR_READONLY);
 
     LinearExtent* system1 = system->extents()[0]->AsLinearExtent();
@@ -378,17 +371,7 @@
     unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
 
     std::string name = "abcdefghijklmnopqrstuvwxyz0123456789";
-    Partition* system = builder->AddPartition(name + name, TEST_GUID, LP_PARTITION_ATTR_READONLY);
-    EXPECT_NE(system, nullptr);
-
-    unique_ptr<LpMetadata> exported = builder->Export();
-    EXPECT_EQ(exported, nullptr);
-}
-
-TEST(liblp, ExportInvalidGuid) {
-    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
-
-    Partition* system = builder->AddPartition("system", "bad", LP_PARTITION_ATTR_READONLY);
+    Partition* system = builder->AddPartition(name + name, LP_PARTITION_ATTR_READONLY);
     EXPECT_NE(system, nullptr);
 
     unique_ptr<LpMetadata> exported = builder->Export();
@@ -483,7 +466,7 @@
     unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
     ASSERT_NE(builder, nullptr);
 
-    Partition* partition = builder->AddPartition("system", TEST_GUID, 0);
+    Partition* partition = builder->AddPartition("system", 0);
     ASSERT_NE(partition, nullptr);
     ASSERT_TRUE(builder->ResizePartition(partition, 512));
     EXPECT_EQ(partition->size(), 4096);
@@ -511,7 +494,7 @@
 
     ASSERT_TRUE(builder->AddGroup("google", 16384));
 
-    Partition* partition = builder->AddPartition("system", "google", TEST_GUID, 0);
+    Partition* partition = builder->AddPartition("system", "google", 0);
     ASSERT_NE(partition, nullptr);
     EXPECT_TRUE(builder->ResizePartition(partition, 8192));
     EXPECT_EQ(partition->size(), 8192);
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index f1edee7..a6044d0 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -112,8 +112,7 @@
     friend class MetadataBuilder;
 
   public:
-    Partition(const std::string& name, const std::string& group_name, const std::string& guid,
-              uint32_t attributes);
+    Partition(const std::string& name, const std::string& group_name, uint32_t attributes);
 
     // Add a raw extent.
     void AddExtent(std::unique_ptr<Extent>&& extent);
@@ -128,7 +127,6 @@
     const std::string& name() const { return name_; }
     const std::string& group_name() const { return group_name_; }
     uint32_t attributes() const { return attributes_; }
-    const std::string& guid() const { return guid_; }
     const std::vector<std::unique_ptr<Extent>>& extents() const { return extents_; }
     uint64_t size() const { return size_; }
 
@@ -137,7 +135,6 @@
 
     std::string name_;
     std::string group_name_;
-    std::string guid_;
     std::vector<std::unique_ptr<Extent>> extents_;
     uint32_t attributes_;
     uint64_t size_;
@@ -190,11 +187,11 @@
     // Add a partition, returning a handle so it can be sized as needed. If a
     // partition with the given name already exists, nullptr is returned.
     Partition* AddPartition(const std::string& name, const std::string& group_name,
-                            const std::string& guid, uint32_t attributes);
+                            uint32_t attributes);
 
     // Same as AddPartition above, but uses the default partition group which
     // has no size restrictions.
-    Partition* AddPartition(const std::string& name, const std::string& guid, uint32_t attributes);
+    Partition* AddPartition(const std::string& name, uint32_t attributes);
 
     // Delete a partition by name if it exists.
     void RemovePartition(const std::string& name);
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 51d262b..5f95dca 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -68,7 +68,6 @@
 
 // Helper to extract safe C++ strings from partition info.
 std::string GetPartitionName(const LpMetadataPartition& partition);
-std::string GetPartitionGuid(const LpMetadataPartition& partition);
 std::string GetPartitionGroupName(const LpMetadataPartitionGroup& group);
 
 // Helper to return a slot number for a slot suffix.
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 79ef2ab..7d1a2a9 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -38,7 +38,7 @@
 #define LP_METADATA_HEADER_MAGIC 0x414C5030
 
 /* Current metadata version. */
-#define LP_METADATA_MAJOR_VERSION 2
+#define LP_METADATA_MAJOR_VERSION 3
 #define LP_METADATA_MINOR_VERSION 0
 
 /* Attributes for the LpMetadataPartition::attributes field.
@@ -67,7 +67,7 @@
  *     | Geometry Backup    |
  *     +--------------------+
  */
-#define LP_METADATA_PARTITION_NAME "super"
+#define LP_METADATA_DEFAULT_PARTITION_NAME "super"
 
 /* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */
 #define LP_SECTOR_SIZE 512
@@ -232,23 +232,20 @@
      */
     char name[36];
 
-    /* 36: Globally unique identifier (GUID) of this partition. */
-    uint8_t guid[16];
-
-    /* 52: Attributes for the partition (see LP_PARTITION_ATTR_* flags above). */
+    /* 36: Attributes for the partition (see LP_PARTITION_ATTR_* flags above). */
     uint32_t attributes;
 
-    /* 56: Index of the first extent owned by this partition. The extent will
+    /* 40: Index of the first extent owned by this partition. The extent will
      * start at logical sector 0. Gaps between extents are not allowed.
      */
     uint32_t first_extent_index;
 
-    /* 60: Number of extents in the partition. Every partition must have at
+    /* 44: Number of extents in the partition. Every partition must have at
      * least one extent.
      */
     uint32_t num_extents;
 
-    /* 64: Group this partition belongs to. */
+    /* 48: Group this partition belongs to. */
     uint32_t group_index;
 } __attribute__((packed)) LpMetadataPartition;
 
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index f93852b..01de3ac 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -37,8 +37,6 @@
 static const size_t kDiskSize = 131072;
 static const size_t kMetadataSize = 512;
 static const size_t kMetadataSlots = 2;
-static const char* TEST_GUID_BASE = "A799D1D6-669F-41D8-A3F0-EBB7572D830";
-static const char* TEST_GUID = "A799D1D6-669F-41D8-A3F0-EBB7572D8302";
 
 // Helper function for creating an in-memory file descriptor. This lets us
 // simulate read/writing logical partition metadata as if we had a block device
@@ -81,7 +79,7 @@
 }
 
 static bool AddDefaultPartitions(MetadataBuilder* builder) {
-    Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_NONE);
+    Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_NONE);
     if (!system) {
         return false;
     }
@@ -171,7 +169,6 @@
     // Check partition tables.
     ASSERT_EQ(exported->partitions.size(), imported->partitions.size());
     EXPECT_EQ(GetPartitionName(exported->partitions[0]), GetPartitionName(imported->partitions[0]));
-    EXPECT_EQ(GetPartitionGuid(exported->partitions[0]), GetPartitionGuid(imported->partitions[0]));
     EXPECT_EQ(exported->partitions[0].attributes, imported->partitions[0].attributes);
     EXPECT_EQ(exported->partitions[0].first_extent_index,
               imported->partitions[0].first_extent_index);
@@ -331,18 +328,18 @@
     unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
     ASSERT_NE(builder, nullptr);
 
-    // Compute the maximum number of partitions we can fit in 1024 bytes of metadata.
-    size_t max_partitions = (kMetadataSize - sizeof(LpMetadataHeader)) / sizeof(LpMetadataPartition);
-    EXPECT_LT(max_partitions, 10);
+    // Compute the maximum number of partitions we can fit in 512 bytes of
+    // metadata. By default there is the header, and one partition group.
+    static const size_t kMaxPartitionTableSize =
+            kMetadataSize - sizeof(LpMetadataHeader) - sizeof(LpMetadataPartitionGroup);
+    size_t max_partitions = kMaxPartitionTableSize / sizeof(LpMetadataPartition);
 
     // Add this number of partitions.
     Partition* partition = nullptr;
     for (size_t i = 0; i < max_partitions; i++) {
-        std::string guid = std::string(TEST_GUID) + to_string(i);
-        partition = builder->AddPartition(to_string(i), TEST_GUID, LP_PARTITION_ATTR_NONE);
+        partition = builder->AddPartition(to_string(i), LP_PARTITION_ATTR_NONE);
         ASSERT_NE(partition, nullptr);
     }
-    ASSERT_NE(partition, nullptr);
 
     unique_ptr<LpMetadata> exported = builder->Export();
     ASSERT_NE(exported, nullptr);
@@ -354,7 +351,7 @@
     ASSERT_TRUE(FlashPartitionTable(fd, *exported.get()));
 
     // Check that adding one more partition overflows the metadata allotment.
-    partition = builder->AddPartition("final", TEST_GUID, LP_PARTITION_ATTR_NONE);
+    partition = builder->AddPartition("final", LP_PARTITION_ATTR_NONE);
     EXPECT_NE(partition, nullptr);
 
     exported = builder->Export();
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index a590037..b08f96c 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -23,7 +23,6 @@
 #include <android-base/file.h>
 #include <ext4_utils/ext4_utils.h>
 #include <openssl/sha.h>
-#include <uuid/uuid.h>
 
 #include "utility.h"
 
@@ -80,15 +79,6 @@
     SHA256_Final(out, &c);
 }
 
-std::string GetPartitionGuid(const LpMetadataPartition& partition) {
-    // 32 hex characters, four hyphens. Unfortunately libext2_uuid provides no
-    // macro to assist with buffer sizing.
-    static const size_t kGuidLen = 36;
-    char buffer[kGuidLen + 1];
-    uuid_unparse_upper(partition.guid, buffer);
-    return buffer;
-}
-
 uint32_t SlotNumberForSlotSuffix(const std::string& suffix) {
     if (suffix.empty()) {
         return 0;
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 8b1c55a..db01c1e 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -139,7 +139,7 @@
     auto fstab = fs_mgr_read_fstab("/proc/mounts");
     ASSERT_NE(fstab, nullptr);
 
-    std::unique_ptr<std::FILE, int (*)(std::FILE*)> mounts(setmntent("/proc/mounts", "r"),
+    std::unique_ptr<std::FILE, int (*)(std::FILE*)> mounts(setmntent("/proc/mounts", "re"),
                                                            endmntent);
     ASSERT_NE(mounts, nullptr);
 
diff --git a/init/README.md b/init/README.md
index b45da21..02a65d5 100644
--- a/init/README.md
+++ b/init/README.md
@@ -262,6 +262,13 @@
 > Scheduling priority of the service process. This value has to be in range
   -20 to 19. Default priority is 0. Priority is set via setpriority().
 
+`restart_period <seconds>`
+> If a non-oneshot service exits, it will be restarted at its start time plus
+  this period. It defaults to 5s to rate limit crashing services.
+  This can be increased for services that are meant to run periodically. For
+  example, it may be set to 3600 to indicate that the service should run every hour
+  or 86400 to indicate that the service should run every day.
+
 `rlimit <resource> <cur> <max>`
 > This applies the given rlimit to the service. rlimits are inherited by child
   processes, so this effectively applies the given rlimit to the process tree
@@ -298,6 +305,12 @@
   seclabel or computed based on the service executable file security context.
   For native executables see libcutils android\_get\_control\_socket().
 
+`timeout_period <seconds>`
+> Provide a timeout after which point the service will be killed. The oneshot keyword is respected
+  here, so oneshot services do not automatically restart, however all other services will.
+  This is particularly useful for creating a periodic service combined with the restart_period
+  option described above.
+
 `user <username>`
 > Change to 'username' before exec'ing this service.
   Currently defaults to root.  (??? probably should default to nobody)
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 6f97d19..eb86eb0 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -83,6 +83,7 @@
     std::string lp_metadata_partition_;
     std::vector<fstab_rec*> mount_fstab_recs_;
     std::set<std::string> required_devices_partition_names_;
+    std::string super_partition_name_;
     std::unique_ptr<DeviceHandler> device_handler_;
     UeventListener uevent_listener_;
 };
@@ -153,6 +154,8 @@
     device_handler_ = std::make_unique<DeviceHandler>(
             std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{},
             std::move(boot_devices), false);
+
+    super_partition_name_ = fs_mgr_get_super_partition_name();
 }
 
 std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
@@ -196,7 +199,7 @@
         return true;
     }
 
-    required_devices_partition_names_.emplace(LP_METADATA_PARTITION_NAME);
+    required_devices_partition_names_.emplace(super_partition_name_);
     return true;
 }
 
@@ -262,7 +265,7 @@
 
     if (lp_metadata_partition_.empty()) {
         LOG(ERROR) << "Could not locate logical partition tables in partition "
-                   << LP_METADATA_PARTITION_NAME;
+                   << super_partition_name_;
         return false;
     }
     return android::fs_mgr::CreateLogicalPartitions(lp_metadata_partition_);
@@ -275,7 +278,7 @@
     auto iter = required_devices_partition_names_.find(name);
     if (iter != required_devices_partition_names_.end()) {
         LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
-        if (IsDmLinearEnabled() && name == LP_METADATA_PARTITION_NAME) {
+        if (IsDmLinearEnabled() && name == super_partition_name_) {
             std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
             lp_metadata_partition_ = links[0];
         }
@@ -388,6 +391,12 @@
         }
     }
 
+    // heads up for instantiating required device(s) for overlayfs logic
+    const auto devices = fs_mgr_overlayfs_required_devices(device_tree_fstab_.get());
+    for (auto const& device : devices) {
+        InitMappedDevice(device);
+    }
+
     fs_mgr_overlayfs_mount_all(device_tree_fstab_.get());
 
     return true;
diff --git a/init/init.cpp b/init/init.cpp
index 47cfe32..42ec88c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -187,23 +187,34 @@
     }
 }
 
-static std::optional<boot_clock::time_point> RestartProcesses() {
-    std::optional<boot_clock::time_point> next_process_restart_time;
+static std::optional<boot_clock::time_point> HandleProcessActions() {
+    std::optional<boot_clock::time_point> next_process_action_time;
     for (const auto& s : ServiceList::GetInstance()) {
+        if ((s->flags() & SVC_RUNNING) && s->timeout_period()) {
+            auto timeout_time = s->time_started() + *s->timeout_period();
+            if (boot_clock::now() > timeout_time) {
+                s->Timeout();
+            } else {
+                if (!next_process_action_time || timeout_time < *next_process_action_time) {
+                    next_process_action_time = timeout_time;
+                }
+            }
+        }
+
         if (!(s->flags() & SVC_RESTARTING)) continue;
 
-        auto restart_time = s->time_started() + 5s;
+        auto restart_time = s->time_started() + s->restart_period();
         if (boot_clock::now() > restart_time) {
             if (auto result = s->Start(); !result) {
                 LOG(ERROR) << "Could not restart process '" << s->name() << "': " << result.error();
             }
         } else {
-            if (!next_process_restart_time || restart_time < *next_process_restart_time) {
-                next_process_restart_time = restart_time;
+            if (!next_process_action_time || restart_time < *next_process_action_time) {
+                next_process_action_time = restart_time;
             }
         }
     }
-    return next_process_restart_time;
+    return next_process_action_time;
 }
 
 static Result<Success> DoControlStart(Service* service) {
@@ -570,23 +581,6 @@
     RebootSystem(ANDROID_RB_RESTART2, "bootloader");
 }
 
-static void InitKernelLogging(char* argv[]) {
-    // Make stdin/stdout/stderr all point to /dev/null.
-    int fd = open("/sys/fs/selinux/null", O_RDWR);
-    if (fd == -1) {
-        int saved_errno = errno;
-        android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
-        errno = saved_errno;
-        PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";
-    }
-    dup2(fd, 0);
-    dup2(fd, 1);
-    dup2(fd, 2);
-    if (fd > 2) close(fd);
-
-    android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
-}
-
 static void GlobalSeccomp() {
     import_kernel_cmdline(false, [](const std::string& key, const std::string& value,
                                     bool in_qemu) {
@@ -643,7 +637,8 @@
         SetupSelinux(argv);
     }
 
-    InitKernelLogging(argv);
+    // We need to set up stdin/stdout/stderr again now that we're running in init's context.
+    InitKernelLogging(argv, InitAborter);
     LOG(INFO) << "init second stage started!";
 
     // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
@@ -770,12 +765,12 @@
         }
         if (!(waiting_for_prop || Service::is_exec_service_running())) {
             if (!shutting_down) {
-                auto next_process_restart_time = RestartProcesses();
+                auto next_process_action_time = HandleProcessActions();
 
                 // If there's a process that needs restarting, wake up in time for that.
-                if (next_process_restart_time) {
+                if (next_process_action_time) {
                     epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
-                        *next_process_restart_time - boot_clock::now());
+                            *next_process_action_time - boot_clock::now());
                     if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
                 }
             }
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 40706a1..d81ca5c 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -102,9 +102,11 @@
 
     // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
     // talk to the outside world...
-    android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) {
-        RebootSystem(ANDROID_RB_RESTART2, "bootloader");
-    });
+    // We need to set up stdin/stdout/stderr for child processes forked from first
+    // stage init as part of the mount process.  This closes /dev/console if the
+    // kernel had previously opened it.
+    auto reboot_bootloader = [](const char*) { RebootSystem(ANDROID_RB_RESTART2, "bootloader"); };
+    InitKernelLogging(argv, reboot_bootloader);
 
     if (!errors.empty()) {
         for (const auto& [error_string, error_errno] : errors) {
diff --git a/init/keychords_test.cpp b/init/keychords_test.cpp
index c8c47a8..a3baeb1 100644
--- a/init/keychords_test.cpp
+++ b/init/keychords_test.cpp
@@ -47,9 +47,9 @@
   public:
     EventHandler();
     EventHandler(const EventHandler&) = delete;
-    EventHandler(EventHandler&&);
+    EventHandler(EventHandler&&) noexcept;
     EventHandler& operator=(const EventHandler&) = delete;
-    EventHandler& operator=(EventHandler&&);
+    EventHandler& operator=(EventHandler&&) noexcept;
     ~EventHandler() noexcept;
 
     bool init();
@@ -64,11 +64,11 @@
 
 EventHandler::EventHandler() : fd_(-1) {}
 
-EventHandler::EventHandler(EventHandler&& rval) : fd_(rval.fd_) {
+EventHandler::EventHandler(EventHandler&& rval) noexcept : fd_(rval.fd_) {
     rval.fd_ = -1;
 }
 
-EventHandler& EventHandler::operator=(EventHandler&& rval) {
+EventHandler& EventHandler::operator=(EventHandler&& rval) noexcept {
     fd_ = rval.fd_;
     rval.fd_ = -1;
     return *this;
diff --git a/init/reboot.cpp b/init/reboot.cpp
index b84bfd3..866f40e 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -162,7 +162,7 @@
  */
 static bool FindPartitionsToUmount(std::vector<MountEntry>* blockDevPartitions,
                                    std::vector<MountEntry>* emulatedPartitions, bool dump) {
-    std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
+    std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "re"), endmntent);
     if (fp == nullptr) {
         PLOG(ERROR) << "Failed to open /proc/mounts";
         return false;
diff --git a/init/service.cpp b/init/service.cpp
index d20e90a..a3e5953 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -627,6 +627,15 @@
     return Success();
 }
 
+Result<Success> Service::ParseRestartPeriod(const std::vector<std::string>& args) {
+    int period;
+    if (!ParseInt(args[1], &period, 5)) {
+        return Error() << "restart_period value must be an integer >= 5";
+    }
+    restart_period_ = std::chrono::seconds(period);
+    return Success();
+}
+
 Result<Success> Service::ParseSeclabel(const std::vector<std::string>& args) {
     seclabel_ = args[1];
     return Success();
@@ -650,6 +659,15 @@
     return Error() << "Invalid shutdown option";
 }
 
+Result<Success> Service::ParseTimeoutPeriod(const std::vector<std::string>& args) {
+    int period;
+    if (!ParseInt(args[1], &period, 1)) {
+        return Error() << "timeout_period value must be an integer >= 1";
+    }
+    timeout_period_ = std::chrono::seconds(period);
+    return Success();
+}
+
 template <typename T>
 Result<Success> Service::AddDescriptor(const std::vector<std::string>& args) {
     int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
@@ -757,12 +775,16 @@
                         {1,     1,    &Service::ParseOomScoreAdjust}},
         {"override",    {0,     0,    &Service::ParseOverride}},
         {"priority",    {1,     1,    &Service::ParsePriority}},
+        {"restart_period",
+                        {1,     1,    &Service::ParseRestartPeriod}},
         {"rlimit",      {3,     3,    &Service::ParseProcessRlimit}},
         {"seclabel",    {1,     1,    &Service::ParseSeclabel}},
         {"setenv",      {2,     2,    &Service::ParseSetenv}},
         {"shutdown",    {1,     1,    &Service::ParseShutdown}},
         {"sigstop",     {0,     0,    &Service::ParseSigstop}},
         {"socket",      {3,     6,    &Service::ParseSocket}},
+        {"timeout_period",
+                        {1,     1,    &Service::ParseTimeoutPeriod}},
         {"user",        {1,     1,    &Service::ParseUser}},
         {"writepid",    {1,     kMax, &Service::ParseWritepid}},
     };
@@ -1022,6 +1044,18 @@
     }
 }
 
+void Service::Timeout() {
+    // All process state flags will be taken care of in Reap(), we really just want to kill the
+    // process here when it times out.  Oneshot processes will transition to be disabled, and
+    // all other processes will transition to be restarting.
+    LOG(INFO) << "Service '" << name_ << "' expired its timeout of " << timeout_period_->count()
+              << " seconds and will now be killed";
+    if (pid_) {
+        KillProcessGroup(SIGKILL);
+        NotifyStateChange("stopping");
+    }
+}
+
 void Service::Restart() {
     if (flags_ & SVC_RUNNING) {
         /* Stop, wait, then start the service. */
diff --git a/init/service.h b/init/service.h
index ea79a07..e8d5ead 100644
--- a/init/service.h
+++ b/init/service.h
@@ -21,7 +21,9 @@
 #include <sys/resource.h>
 #include <sys/types.h>
 
+#include <chrono>
 #include <memory>
+#include <optional>
 #include <set>
 #include <string>
 #include <vector>
@@ -81,6 +83,7 @@
     void Reset();
     void Stop();
     void Terminate();
+    void Timeout();
     void Restart();
     void Reap(const siginfo_t& siginfo);
     void DumpState() const;
@@ -117,6 +120,8 @@
     bool process_cgroup_empty() const { return process_cgroup_empty_; }
     unsigned long start_order() const { return start_order_; }
     void set_sigstop(bool value) { sigstop_ = value; }
+    std::chrono::seconds restart_period() const { return restart_period_; }
+    std::optional<std::chrono::seconds> timeout_period() const { return timeout_period_; }
     const std::vector<std::string>& args() const { return args_; }
 
   private:
@@ -153,11 +158,13 @@
     Result<Success> ParseMemcgSwappiness(const std::vector<std::string>& args);
     Result<Success> ParseNamespace(const std::vector<std::string>& args);
     Result<Success> ParseProcessRlimit(const std::vector<std::string>& args);
+    Result<Success> ParseRestartPeriod(const std::vector<std::string>& args);
     Result<Success> ParseSeclabel(const std::vector<std::string>& args);
     Result<Success> ParseSetenv(const std::vector<std::string>& args);
     Result<Success> ParseShutdown(const std::vector<std::string>& args);
     Result<Success> ParseSigstop(const std::vector<std::string>& args);
     Result<Success> ParseSocket(const std::vector<std::string>& args);
+    Result<Success> ParseTimeoutPeriod(const std::vector<std::string>& args);
     Result<Success> ParseFile(const std::vector<std::string>& args);
     Result<Success> ParseUser(const std::vector<std::string>& args);
     Result<Success> ParseWritepid(const std::vector<std::string>& args);
@@ -220,6 +227,9 @@
 
     bool sigstop_ = false;
 
+    std::chrono::seconds restart_period_ = 5s;
+    std::optional<std::chrono::seconds> timeout_period_;
+
     std::vector<std::string> args_;
 
     std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
diff --git a/init/util.cpp b/init/util.cpp
index 105ac87..3781141 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -436,5 +436,21 @@
     return true;
 }
 
+void InitKernelLogging(char** argv, std::function<void(const char*)> abort_function) {
+    // Make stdin/stdout/stderr all point to /dev/null.
+    int fd = open("/dev/null", O_RDWR);
+    if (fd == -1) {
+        int saved_errno = errno;
+        android::base::InitLogging(argv, &android::base::KernelLogger, std::move(abort_function));
+        errno = saved_errno;
+        PLOG(FATAL) << "Couldn't open /dev/null";
+    }
+    dup2(fd, 0);
+    dup2(fd, 1);
+    dup2(fd, 2);
+    if (fd > 2) close(fd);
+    android::base::InitLogging(argv, &android::base::KernelLogger, std::move(abort_function));
+}
+
 }  // namespace init
 }  // namespace android
diff --git a/init/util.h b/init/util.h
index 07e4864..53f4547 100644
--- a/init/util.h
+++ b/init/util.h
@@ -64,6 +64,8 @@
 
 bool IsLegalPropertyName(const std::string& name);
 
+void InitKernelLogging(char** argv, std::function<void(const char*)> abort_function);
+
 }  // namespace init
 }  // namespace android
 
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index c42ae49..7f9a18a 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -27,15 +27,6 @@
             enabled: false,
         },
     },
-
-    multilib: {
-        lib32: {
-            suffix: "32",
-        },
-        lib64: {
-            suffix: "64",
-        },
-    },
 }
 
 libbacktrace_sources = [
@@ -108,7 +99,7 @@
     whole_static_libs: ["libdemangle"],
 }
 
-cc_library_shared {
+cc_test_library {
     name: "libbacktrace_test",
     defaults: ["libbacktrace_common"],
     host_supported: true,
@@ -121,6 +112,17 @@
     shared_libs: [
         "libunwindstack",
     ],
+    relative_install_path: "backtrace_test_libs",
+
+    target: {
+        linux_glibc: {
+            // This forces the creation of eh_frame with unwind information
+            // for host.
+            cflags: [
+                "-fcxx-exceptions"
+            ],
+        },
+    },
 }
 
 //-------------------------------------------------------------------------
@@ -128,12 +130,12 @@
 //-------------------------------------------------------------------------
 cc_test {
     name: "backtrace_test",
+    isolated: true,
     defaults: ["libbacktrace_common"],
     host_supported: true,
     srcs: [
         "backtrace_offline_test.cpp",
         "backtrace_test.cpp",
-        "GetPss.cpp",
     ],
 
     cflags: [
@@ -143,7 +145,6 @@
     ],
 
     shared_libs: [
-        "libbacktrace_test",
         "libbacktrace",
         "libbase",
         "liblog",
@@ -152,17 +153,10 @@
 
     group_static_libs: true,
 
-    target: {
-        android: {
-            cflags: ["-DENABLE_PSS_TESTS"],
-            shared_libs: [
-                "libutils",
-            ],
-        },
-        linux_glibc: {
-            static_libs: ["libutils"],
-        },
-    },
+    // So that the dlopen can find the libbacktrace_test.so.
+    ldflags: [
+        "-Wl,--rpath,${ORIGIN}/../backtrace_test_libs",
+    ],
 
     test_suites: ["device-tests"],
     data: [
diff --git a/libbacktrace/BacktraceTest.h b/libbacktrace/BacktraceTest.h
new file mode 100644
index 0000000..c38af04
--- /dev/null
+++ b/libbacktrace/BacktraceTest.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 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 _LIBBACKTRACE_BACKTRACE_TEST_H
+#define _LIBBACKTRACE_BACKTRACE_TEST_H
+
+#include <dlfcn.h>
+
+#include <gtest/gtest.h>
+
+class BacktraceTest : public ::testing::Test {
+ protected:
+  static void SetUpTestCase() {
+    dl_handle_ = dlopen("libbacktrace_test.so", RTLD_NOW | RTLD_LOCAL);
+
+    test_level_one_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
+        dlsym(dl_handle_, "test_level_one"));
+
+    test_level_two_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
+        dlsym(dl_handle_, "test_level_two"));
+
+    test_level_three_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
+        dlsym(dl_handle_, "test_level_three"));
+
+    test_level_four_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
+        dlsym(dl_handle_, "test_level_four"));
+
+    test_recursive_call_ = reinterpret_cast<int (*)(int, void (*)(void*), void*)>(
+        dlsym(dl_handle_, "test_recursive_call"));
+
+    test_get_context_and_wait_ = reinterpret_cast<void (*)(void*, volatile int*)>(
+        dlsym(dl_handle_, "test_get_context_and_wait"));
+
+    test_signal_action_ =
+        reinterpret_cast<void (*)(int, siginfo_t*, void*)>(dlsym(dl_handle_, "test_signal_action"));
+
+    test_signal_handler_ =
+        reinterpret_cast<void (*)(int)>(dlsym(dl_handle_, "test_signal_handler"));
+  }
+
+  void SetUp() override {
+    ASSERT_TRUE(dl_handle_ != nullptr);
+    ASSERT_TRUE(test_level_one_ != nullptr);
+    ASSERT_TRUE(test_level_two_ != nullptr);
+    ASSERT_TRUE(test_level_three_ != nullptr);
+    ASSERT_TRUE(test_level_four_ != nullptr);
+    ASSERT_TRUE(test_recursive_call_ != nullptr);
+    ASSERT_TRUE(test_get_context_and_wait_ != nullptr);
+    ASSERT_TRUE(test_signal_action_ != nullptr);
+    ASSERT_TRUE(test_signal_handler_ != nullptr);
+  }
+
+ public:
+  static void* dl_handle_;
+  static int (*test_level_one_)(int, int, int, int, void (*)(void*), void*);
+  static int (*test_level_two_)(int, int, int, int, void (*)(void*), void*);
+  static int (*test_level_three_)(int, int, int, int, void (*)(void*), void*);
+  static int (*test_level_four_)(int, int, int, int, void (*)(void*), void*);
+  static int (*test_recursive_call_)(int, void (*)(void*), void*);
+  static void (*test_get_context_and_wait_)(void*, volatile int*);
+  static void (*test_signal_action_)(int, siginfo_t*, void*);
+  static void (*test_signal_handler_)(int);
+};
+
+#endif  // _LIBBACKTRACE_BACKTRACE_TEST_H
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp
deleted file mode 100644
index 6d750ea..0000000
--- a/libbacktrace/GetPss.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2014 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 <inttypes.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-// This is an extremely simplified version of libpagemap.
-
-#define _BITS(x, offset, bits) (((x) >> (offset)) & ((1LL << (bits)) - 1))
-
-#define PAGEMAP_PRESENT(x)     (_BITS(x, 63, 1))
-#define PAGEMAP_SWAPPED(x)     (_BITS(x, 62, 1))
-#define PAGEMAP_SHIFT(x)       (_BITS(x, 55, 6))
-#define PAGEMAP_PFN(x)         (_BITS(x, 0, 55))
-#define PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
-#define PAGEMAP_SWAP_TYPE(x)   (_BITS(x, 0,  5))
-
-static bool ReadData(int fd, off_t place, uint64_t *data) {
-  if (lseek(fd, place * sizeof(uint64_t), SEEK_SET) < 0) {
-    return false;
-  }
-  if (read(fd, (void*)data, sizeof(uint64_t)) != (ssize_t)sizeof(uint64_t)) {
-    return false;
-  }
-  return true;
-}
-
-size_t GetPssBytes() {
-  FILE* maps = fopen("/proc/self/maps", "r");
-  if (maps == nullptr) {
-    return 0;
-  }
-
-  int pagecount_fd = open("/proc/kpagecount", O_RDONLY);
-  if (pagecount_fd == -1) {
-    fclose(maps);
-    return 0;
-  }
-
-  int pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
-  if (pagemap_fd == -1) {
-    fclose(maps);
-    close(pagecount_fd);
-    return 0;
-  }
-
-  char line[4096];
-  size_t total_pss = 0;
-  int pagesize = getpagesize();
-  while (fgets(line, sizeof(line), maps)) {
-    uintptr_t start, end;
-    if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " ", &start, &end) != 2) {
-      total_pss = 0;
-      break;
-    }
-    for (off_t page = static_cast<off_t>(start/pagesize);
-         page < static_cast<off_t>(end/pagesize); page++) {
-      uint64_t data;
-      if (ReadData(pagemap_fd, page, &data)) {
-        if (PAGEMAP_PRESENT(data) && !PAGEMAP_SWAPPED(data)) {
-          uint64_t count;
-          if (ReadData(pagecount_fd, static_cast<off_t>(PAGEMAP_PFN(data)), &count)) {
-            total_pss += (count >= 1) ? pagesize / count : 0;
-          }
-        }
-      }
-    }
-  }
-
-  fclose(maps);
-
-  close(pagecount_fd);
-  close(pagemap_fd);
-
-  return total_pss;
-}
diff --git a/libbacktrace/GetPss.h b/libbacktrace/GetPss.h
deleted file mode 100644
index 787c33d..0000000
--- a/libbacktrace/GetPss.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2014 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 _LIBBACKTRACE_GET_PSS_H
-#define _LIBBACKTRACE_GET_PSS_H
-
-size_t GetPssBytes();
-
-#endif // _LIBBACKTRACE_GET_PSS_H
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 7d1027e..662fb99 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -37,15 +37,7 @@
 
 #include <gtest/gtest.h>
 
-extern "C" {
-// Prototypes for functions in the test library.
-int test_level_one(int, int, int, int, void (*)(void*), void*);
-int test_level_two(int, int, int, int, void (*)(void*), void*);
-int test_level_three(int, int, int, int, void (*)(void*), void*);
-int test_level_four(int, int, int, int, void (*)(void*), void*);
-int test_recursive_call(int, void (*)(void*), void*);
-void test_get_context_and_wait(void* context, volatile int* exit_flag);
-}
+#include "BacktraceTest.h"
 
 struct FunctionSymbol {
   std::string name;
@@ -56,12 +48,13 @@
 static std::vector<FunctionSymbol> GetFunctionSymbols() {
   std::vector<FunctionSymbol> symbols = {
       {"unknown_start", 0, 0},
-      {"test_level_one", reinterpret_cast<uint64_t>(&test_level_one), 0},
-      {"test_level_two", reinterpret_cast<uint64_t>(&test_level_two), 0},
-      {"test_level_three", reinterpret_cast<uint64_t>(&test_level_three), 0},
-      {"test_level_four", reinterpret_cast<uint64_t>(&test_level_four), 0},
-      {"test_recursive_call", reinterpret_cast<uint64_t>(&test_recursive_call), 0},
-      {"test_get_context_and_wait", reinterpret_cast<uint64_t>(&test_get_context_and_wait), 0},
+      {"test_level_one", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_one_), 0},
+      {"test_level_two", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_two_), 0},
+      {"test_level_three", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_three_), 0},
+      {"test_level_four", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_four_), 0},
+      {"test_recursive_call", reinterpret_cast<uint64_t>(&BacktraceTest::test_recursive_call_), 0},
+      {"test_get_context_and_wait",
+       reinterpret_cast<uint64_t>(&BacktraceTest::test_get_context_and_wait_), 0},
       {"unknown_end", static_cast<uint64_t>(-1), static_cast<uint64_t>(-1)},
   };
   std::sort(
@@ -100,7 +93,7 @@
 static void* OfflineThreadFunc(void* arg) {
   OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg);
   fn_arg->tid = android::base::GetThreadId();
-  test_get_context_and_wait(&fn_arg->ucontext, &fn_arg->exit_flag);
+  BacktraceTest::test_get_context_and_wait_(&fn_arg->ucontext, &fn_arg->exit_flag);
   return nullptr;
 }
 
@@ -109,7 +102,7 @@
 }
 
 // This test is disable because it is for generating test data.
-TEST(libbacktrace, DISABLED_generate_offline_testdata) {
+TEST_F(BacktraceTest, DISABLED_generate_offline_testdata) {
   // Create a thread to generate the needed stack and registers information.
   const size_t stack_size = 16 * 1024;
   void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -304,22 +297,22 @@
 }
 
 // For now, these tests can only run on the given architectures.
-TEST(libbacktrace, offline_eh_frame) {
+TEST_F(BacktraceTest, offline_eh_frame) {
   BacktraceOfflineTest("arm64", "libbacktrace_test_eh_frame.so");
   BacktraceOfflineTest("x86_64", "libbacktrace_test_eh_frame.so");
 }
 
-TEST(libbacktrace, offline_debug_frame) {
+TEST_F(BacktraceTest, offline_debug_frame) {
   BacktraceOfflineTest("arm", "libbacktrace_test_debug_frame.so");
   BacktraceOfflineTest("x86", "libbacktrace_test_debug_frame.so");
 }
 
-TEST(libbacktrace, offline_gnu_debugdata) {
+TEST_F(BacktraceTest, offline_gnu_debugdata) {
   BacktraceOfflineTest("arm", "libbacktrace_test_gnu_debugdata.so");
   BacktraceOfflineTest("x86", "libbacktrace_test_gnu_debugdata.so");
 }
 
-TEST(libbacktrace, offline_arm_exidx) {
+TEST_F(BacktraceTest, offline_arm_exidx) {
   BacktraceOfflineTest("arm", "libbacktrace_test_arm_exidx.so");
 }
 
@@ -373,32 +366,32 @@
 
 // This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
 // overlap with each other, which appears in /system/lib/libart.so.
-TEST(libbacktrace, offline_unwind_mix_eh_frame_and_arm_exidx) {
+TEST_F(BacktraceTest, offline_unwind_mix_eh_frame_and_arm_exidx) {
   LibUnwindingTest("arm", "offline_testdata_for_libart", "libart.so");
 }
 
-TEST(libbacktrace, offline_debug_frame_with_load_bias) {
+TEST_F(BacktraceTest, offline_debug_frame_with_load_bias) {
   LibUnwindingTest("arm", "offline_testdata_for_libandroid_runtime", "libandroid_runtime.so");
 }
 
-TEST(libbacktrace, offline_try_armexidx_after_debug_frame) {
+TEST_F(BacktraceTest, offline_try_armexidx_after_debug_frame) {
   LibUnwindingTest("arm", "offline_testdata_for_libGLESv2_adreno", "libGLESv2_adreno.so");
 }
 
-TEST(libbacktrace, offline_cie_with_P_augmentation) {
+TEST_F(BacktraceTest, offline_cie_with_P_augmentation) {
   // Make sure we can unwind through functions with CIE entry containing P augmentation, which
   // makes unwinding library reading personality handler from memory. One example is
   // /system/lib64/libskia.so.
   LibUnwindingTest("arm64", "offline_testdata_for_libskia", "libskia.so");
 }
 
-TEST(libbacktrace, offline_empty_eh_frame_hdr) {
+TEST_F(BacktraceTest, offline_empty_eh_frame_hdr) {
   // Make sure we can unwind through libraries with empty .eh_frame_hdr section. One example is
   // /vendor/lib64/egl/eglSubDriverAndroid.so.
   LibUnwindingTest("arm64", "offline_testdata_for_eglSubDriverAndroid", "eglSubDriverAndroid.so");
 }
 
-TEST(libbacktrace, offline_max_frames_limit) {
+TEST_F(BacktraceTest, offline_max_frames_limit) {
   // The length of callchain can reach 256 when recording an application.
   ASSERT_GE(MAX_BACKTRACE_FRAMES, 256);
 }
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 06a32c7..f4191b9 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <malloc.h>
 #include <pthread.h>
 #include <signal.h>
 #include <stdint.h>
@@ -55,6 +56,7 @@
 
 // For the THREAD_SIGNAL definition.
 #include "BacktraceCurrent.h"
+#include "BacktraceTest.h"
 #include "backtrace_testlib.h"
 
 // Number of microseconds per milliseconds.
@@ -95,6 +97,23 @@
 static void VerifyMaxDump(Backtrace* backtrace, create_func_t create_func = nullptr,
                           map_create_func_t map_func = nullptr);
 
+void* BacktraceTest::dl_handle_;
+int (*BacktraceTest::test_level_one_)(int, int, int, int, void (*)(void*), void*);
+int (*BacktraceTest::test_level_two_)(int, int, int, int, void (*)(void*), void*);
+int (*BacktraceTest::test_level_three_)(int, int, int, int, void (*)(void*), void*);
+int (*BacktraceTest::test_level_four_)(int, int, int, int, void (*)(void*), void*);
+int (*BacktraceTest::test_recursive_call_)(int, void (*)(void*), void*);
+void (*BacktraceTest::test_get_context_and_wait_)(void*, volatile int*);
+void (*BacktraceTest::test_signal_action_)(int, siginfo_t*, void*);
+void (*BacktraceTest::test_signal_handler_)(int);
+
+extern "C" bool GetInitialArgs(const char*** args, size_t* num_args) {
+  static const char* initial_args[] = {"--slow_threshold_ms=8000", "--deadline_threshold_ms=15000"};
+  *args = initial_args;
+  *num_args = 2;
+  return true;
+}
+
 static uint64_t NanoTime() {
   struct timespec t = { 0, 0 };
   clock_gettime(CLOCK_MONOTONIC, &t);
@@ -250,7 +269,7 @@
   return false;
 }
 
-TEST(libbacktrace, local_no_unwind_frames) {
+TEST_F(BacktraceTest, local_no_unwind_frames) {
   // Verify that a local unwind does not include any frames within
   // libunwind or libbacktrace.
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
@@ -270,7 +289,7 @@
   }
 }
 
-TEST(libbacktrace, local_unwind_frames) {
+TEST_F(BacktraceTest, local_unwind_frames) {
   // Verify that a local unwind with the skip frames disabled does include
   // frames within the backtrace libraries.
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
@@ -302,8 +321,8 @@
                                                << DumpFrames(backtrace.get());
 }
 
-TEST(libbacktrace, local_trace) {
-  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
+TEST_F(BacktraceTest, local_trace) {
+  ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
 }
 
 static void VerifyIgnoreFrames(Backtrace* bt_all, Backtrace* bt_ign1, Backtrace* bt_ign2,
@@ -357,12 +376,12 @@
   VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), "VerifyLevelIgnoreFrames");
 }
 
-TEST(libbacktrace, local_trace_ignore_frames) {
-  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, nullptr), 0);
+TEST_F(BacktraceTest, local_trace_ignore_frames) {
+  ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelIgnoreFrames, nullptr), 0);
 }
 
-TEST(libbacktrace, local_max_trace) {
-  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, nullptr), 0);
+TEST_F(BacktraceTest, local_max_trace) {
+  ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, VerifyMaxBacktrace, nullptr), 0);
 }
 
 static void VerifyProcTest(pid_t pid, pid_t tid, bool (*ReadyFunc)(Backtrace*),
@@ -402,10 +421,10 @@
   ASSERT_TRUE(verified) << "Last backtrace:\n" << last_dump;
 }
 
-TEST(libbacktrace, ptrace_trace) {
+TEST_F(BacktraceTest, ptrace_trace) {
   pid_t pid;
   if ((pid = fork()) == 0) {
-    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+    ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyLevelDump,
@@ -416,10 +435,10 @@
   ASSERT_EQ(waitpid(pid, &status, 0), pid);
 }
 
-TEST(libbacktrace, ptrace_max_trace) {
+TEST_F(BacktraceTest, ptrace_max_trace) {
   pid_t pid;
   if ((pid = fork()) == 0) {
-    ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, nullptr, nullptr), 0);
+    ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, nullptr, nullptr), 0);
     _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump, Backtrace::Create,
@@ -446,10 +465,10 @@
   VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), nullptr);
 }
 
-TEST(libbacktrace, ptrace_ignore_frames) {
+TEST_F(BacktraceTest, ptrace_ignore_frames) {
   pid_t pid;
   if ((pid = fork()) == 0) {
-    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+    ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames,
@@ -462,7 +481,7 @@
 
 // Create a process with multiple threads and dump all of the threads.
 static void* PtraceThreadLevelRun(void*) {
-  EXPECT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+  EXPECT_NE(BacktraceTest::test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
   return nullptr;
 }
 
@@ -483,7 +502,7 @@
   }
 }
 
-TEST(libbacktrace, ptrace_threads) {
+TEST_F(BacktraceTest, ptrace_threads) {
   pid_t pid;
   if ((pid = fork()) == 0) {
     for (size_t i = 0; i < NUM_PTRACE_THREADS; i++) {
@@ -494,7 +513,7 @@
       pthread_t thread;
       ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, nullptr) == 0);
     }
-    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+    ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
 
@@ -532,8 +551,8 @@
   VerifyLevelDump(backtrace.get());
 }
 
-TEST(libbacktrace, thread_current_level) {
-  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, nullptr), 0);
+TEST_F(BacktraceTest, thread_current_level) {
+  ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelThread, nullptr), 0);
 }
 
 static void VerifyMaxThread(void*) {
@@ -545,19 +564,19 @@
   VerifyMaxDump(backtrace.get());
 }
 
-TEST(libbacktrace, thread_current_max) {
-  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, nullptr), 0);
+TEST_F(BacktraceTest, thread_current_max) {
+  ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, VerifyMaxThread, nullptr), 0);
 }
 
 static void* ThreadLevelRun(void* data) {
   thread_t* thread = reinterpret_cast<thread_t*>(data);
 
   thread->tid = android::base::GetThreadId();
-  EXPECT_NE(test_level_one(1, 2, 3, 4, ThreadSetState, data), 0);
+  EXPECT_NE(BacktraceTest::test_level_one_(1, 2, 3, 4, ThreadSetState, data), 0);
   return nullptr;
 }
 
-TEST(libbacktrace, thread_level_trace) {
+TEST_F(BacktraceTest, thread_level_trace) {
   pthread_attr_t attr;
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -607,7 +626,7 @@
   EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
 }
 
-TEST(libbacktrace, thread_ignore_frames) {
+TEST_F(BacktraceTest, thread_ignore_frames) {
   pthread_attr_t attr;
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -644,11 +663,12 @@
   thread_t* thread = reinterpret_cast<thread_t*>(data);
 
   thread->tid = android::base::GetThreadId();
-  EXPECT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, ThreadSetState, data), 0);
+  EXPECT_NE(BacktraceTest::test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, ThreadSetState, data),
+            0);
   return nullptr;
 }
 
-TEST(libbacktrace, thread_max_trace) {
+TEST_F(BacktraceTest, thread_max_trace) {
   pthread_attr_t attr;
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -742,17 +762,17 @@
   }
 }
 
-TEST(libbacktrace, thread_multiple_dump) {
+TEST_F(BacktraceTest, thread_multiple_dump) {
   MultipleThreadDumpTest(false);
 }
 
-TEST(libbacktrace, thread_multiple_dump_same_map) {
+TEST_F(BacktraceTest, thread_multiple_dump_same_map) {
   MultipleThreadDumpTest(true);
 }
 
 // This test is for UnwindMaps that should share the same map cursor when
 // multiple maps are created for the current process at the same time.
-TEST(libbacktrace, simultaneous_maps) {
+TEST_F(BacktraceTest, simultaneous_maps) {
   BacktraceMap* map1 = BacktraceMap::Create(getpid());
   BacktraceMap* map2 = BacktraceMap::Create(getpid());
   BacktraceMap* map3 = BacktraceMap::Create(getpid());
@@ -779,7 +799,7 @@
   delete map3;
 }
 
-TEST(libbacktrace, fillin_erases) {
+TEST_F(BacktraceTest, fillin_erases) {
   BacktraceMap* back_map = BacktraceMap::Create(getpid());
 
   backtrace_map_t map;
@@ -798,7 +818,7 @@
   ASSERT_EQ("", map.name);
 }
 
-TEST(libbacktrace, format_test) {
+TEST_F(BacktraceTest, format_test) {
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(backtrace.get() != nullptr);
 
@@ -969,7 +989,7 @@
   ASSERT_TRUE(test_it == test_maps.end());
 }
 
-TEST(libbacktrace, verify_map_remote) {
+TEST_F(BacktraceTest, verify_map_remote) {
   pid_t pid;
   CreateRemoteProcess(&pid);
 
@@ -1069,7 +1089,7 @@
   delete[] expected;
 }
 
-TEST(libbacktrace, thread_read) {
+TEST_F(BacktraceTest, thread_read) {
   pthread_attr_t attr;
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -1120,7 +1140,7 @@
   }
 }
 
-TEST(libbacktrace, process_read) {
+TEST_F(BacktraceTest, process_read) {
   g_ready = 0;
   pid_t pid;
   if ((pid = fork()) == 0) {
@@ -1187,29 +1207,23 @@
 }
 
 static void CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
-  std::string system_dir;
-
-#if defined(__BIONIC__)
-  system_dir = "/system/lib";
-#else
-  const char* host_out_env = getenv("ANDROID_HOST_OUT");
-  ASSERT_TRUE(host_out_env != nullptr);
-  system_dir = std::string(host_out_env) + "/lib";
-#endif
-
-#if defined(__LP64__)
-  system_dir += "64";
-#endif
+  std::string test_lib(testing::internal::GetArgvs()[0]);
+  auto const value = test_lib.find_last_of('/');
+  if (value == std::string::npos) {
+    test_lib = "../backtrace_test_libs/";
+  } else {
+    test_lib = test_lib.substr(0, value + 1) + "../backtrace_test_libs/";
+  }
+  test_lib += "libbacktrace_test.so";
 
   *tmp_so_name = std::string(tmp_dir) + "/libbacktrace_test.so";
-  std::string cp_cmd =
-      android::base::StringPrintf("cp %s/libbacktrace_test.so %s", system_dir.c_str(), tmp_dir);
+  std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
 
   // Copy the shared so to a tempory directory.
   ASSERT_EQ(0, system(cp_cmd.c_str()));
 }
 
-TEST(libbacktrace, check_unreadable_elf_local) {
+TEST_F(BacktraceTest, check_unreadable_elf_local) {
   TemporaryDir td;
   std::string tmp_so_name;
   ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@@ -1251,7 +1265,7 @@
   VerifyFunctionsFound(found_functions);
 }
 
-TEST(libbacktrace, check_unreadable_elf_remote) {
+TEST_F(BacktraceTest, check_unreadable_elf_remote) {
   TemporaryDir td;
   std::string tmp_so_name;
   ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@@ -1390,7 +1404,7 @@
 
 typedef int (*test_func_t)(int, int, int, int, void (*)(void*), void*);
 
-TEST(libbacktrace, unwind_through_unreadable_elf_local) {
+TEST_F(BacktraceTest, unwind_through_unreadable_elf_local) {
   TemporaryDir td;
   std::string tmp_so_name;
   ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@@ -1405,11 +1419,9 @@
 
   ASSERT_NE(test_func(1, 2, 3, 4, VerifyUnreadableElfBacktrace, reinterpret_cast<void*>(test_func)),
             0);
-
-  ASSERT_TRUE(dlclose(lib_handle) == 0);
 }
 
-TEST(libbacktrace, unwind_through_unreadable_elf_remote) {
+TEST_F(BacktraceTest, unwind_through_unreadable_elf_remote) {
   TemporaryDir td;
   std::string tmp_so_name;
   ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@@ -1428,7 +1440,6 @@
     exit(0);
   }
   ASSERT_TRUE(pid > 0);
-  ASSERT_TRUE(dlclose(lib_handle) == 0);
 
   uint64_t start = NanoTime();
   bool done = false;
@@ -1465,7 +1476,7 @@
   ASSERT_TRUE(done) << "Test function never found in unwind.";
 }
 
-TEST(libbacktrace, unwind_thread_doesnt_exist) {
+TEST_F(BacktraceTest, unwind_thread_doesnt_exist) {
   std::unique_ptr<Backtrace> backtrace(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, 99999999));
   ASSERT_TRUE(backtrace.get() != nullptr);
@@ -1473,18 +1484,18 @@
   ASSERT_EQ(BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST, backtrace->GetError().error_code);
 }
 
-TEST(libbacktrace, local_get_function_name_before_unwind) {
+TEST_F(BacktraceTest, local_get_function_name_before_unwind) {
   std::unique_ptr<Backtrace> backtrace(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(backtrace.get() != nullptr);
 
   // Verify that trying to get a function name before doing an unwind works.
-  uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
+  uint64_t cur_func_offset = reinterpret_cast<uint64_t>(test_level_one_) + 1;
   uint64_t offset;
   ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
 }
 
-TEST(libbacktrace, remote_get_function_name_before_unwind) {
+TEST_F(BacktraceTest, remote_get_function_name_before_unwind) {
   pid_t pid;
   CreateRemoteProcess(&pid);
 
@@ -1492,7 +1503,7 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
 
   // Verify that trying to get a function name before doing an unwind works.
-  uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
+  uint64_t cur_func_offset = reinterpret_cast<uint64_t>(test_level_one_) + 1;
   uint64_t offset;
   ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
 
@@ -1579,7 +1590,7 @@
   ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset, &map));
   ASSERT_EQ(std::string(""), backtrace->GetFunctionName(0, &offset));
 
-  uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
+  uint64_t cur_func_offset = reinterpret_cast<uint64_t>(BacktraceTest::test_level_one_) + 1;
   // Now verify the device map flag actually causes the function name to be empty.
   backtrace->FillInMap(cur_func_offset, &map);
   ASSERT_TRUE((map.flags & PROT_DEVICE_MAP) == 0);
@@ -1628,7 +1639,7 @@
   ASSERT_EQ(0U, backtrace->NumFrames());
 }
 
-TEST(libbacktrace, unwind_disallow_device_map_local) {
+TEST_F(BacktraceTest, unwind_disallow_device_map_local) {
   void* device_map;
   SetupDeviceMap(&device_map);
 
@@ -1642,7 +1653,7 @@
   munmap(device_map, DEVICE_MAP_SIZE);
 }
 
-TEST(libbacktrace, unwind_disallow_device_map_remote) {
+TEST_F(BacktraceTest, unwind_disallow_device_map_remote) {
   void* device_map;
   SetupDeviceMap(&device_map);
 
@@ -1698,13 +1709,13 @@
   pid_t pid;
   if ((pid = fork()) == 0) {
     if (use_action) {
-      ScopedSignalHandler ssh(SIGUSR1, test_signal_action);
+      ScopedSignalHandler ssh(SIGUSR1, BacktraceTest::test_signal_action_);
 
-      test_level_one(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
+      BacktraceTest::test_level_one_(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
     } else {
-      ScopedSignalHandler ssh(SIGUSR1, test_signal_handler);
+      ScopedSignalHandler ssh(SIGUSR1, BacktraceTest::test_signal_handler_);
 
-      test_level_one(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
+      BacktraceTest::test_level_one_(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
     }
   }
   ASSERT_NE(-1, pid);
@@ -1805,11 +1816,11 @@
   FinishRemoteProcess(pid);
 }
 
-TEST(libbacktrace, unwind_remote_through_signal_using_handler) {
+TEST_F(BacktraceTest, unwind_remote_through_signal_using_handler) {
   UnwindThroughSignal(false, Backtrace::Create, BacktraceMap::Create);
 }
 
-TEST(libbacktrace, unwind_remote_through_signal_using_action) {
+TEST_F(BacktraceTest, unwind_remote_through_signal_using_action) {
   UnwindThroughSignal(true, Backtrace::Create, BacktraceMap::Create);
 }
 
@@ -1822,49 +1833,41 @@
   ASSERT_EQ(0U, backtrace->GetFrame(0)->num);
 }
 
-TEST(libbacktrace, unwind_frame_skip_numbering) {
+TEST_F(BacktraceTest, unwind_frame_skip_numbering) {
   TestFrameSkipNumbering(Backtrace::Create, BacktraceMap::Create);
 }
 
-#if defined(ENABLE_PSS_TESTS)
-#include "GetPss.h"
-
 #define MAX_LEAK_BYTES (32*1024UL)
 
 static void CheckForLeak(pid_t pid, pid_t tid) {
   std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
 
-  // Do a few runs to get the PSS stable.
-  for (size_t i = 0; i < 100; i++) {
-    Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
-    ASSERT_TRUE(backtrace != nullptr);
-    ASSERT_TRUE(backtrace->Unwind(0));
-    VERIFY_NO_ERROR(backtrace->GetError().error_code);
-    delete backtrace;
-  }
-  size_t stable_pss = GetPssBytes();
-  ASSERT_TRUE(stable_pss != 0);
-
   // Loop enough that even a small leak should be detectable.
+  size_t first_allocated_bytes = 0;
+  size_t last_allocated_bytes = 0;
   for (size_t i = 0; i < 4096; i++) {
     Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
     ASSERT_TRUE(backtrace != nullptr);
     ASSERT_TRUE(backtrace->Unwind(0));
     VERIFY_NO_ERROR(backtrace->GetError().error_code);
     delete backtrace;
-  }
-  size_t new_pss = GetPssBytes();
-  ASSERT_TRUE(new_pss != 0);
-  if (new_pss > stable_pss) {
-    ASSERT_LE(new_pss - stable_pss, MAX_LEAK_BYTES);
+
+    size_t allocated_bytes = mallinfo().uordblks;
+    if (first_allocated_bytes == 0) {
+      first_allocated_bytes = allocated_bytes;
+    } else if (last_allocated_bytes > first_allocated_bytes) {
+      // Check that the memory did not increase too much over the first loop.
+      ASSERT_LE(last_allocated_bytes - first_allocated_bytes, MAX_LEAK_BYTES);
+    }
+    last_allocated_bytes = allocated_bytes;
   }
 }
 
-TEST(libbacktrace, check_for_leak_local) {
+TEST_F(BacktraceTest, check_for_leak_local) {
   CheckForLeak(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD);
 }
 
-TEST(libbacktrace, check_for_leak_local_thread) {
+TEST_F(BacktraceTest, check_for_leak_local_thread) {
   thread_t thread_data = { 0, 0, 0, nullptr };
   pthread_t thread;
   ASSERT_TRUE(pthread_create(&thread, nullptr, ThreadLevelRun, &thread_data) == 0);
@@ -1880,7 +1883,7 @@
   ASSERT_TRUE(pthread_join(thread, nullptr) == 0);
 }
 
-TEST(libbacktrace, check_for_leak_remote) {
+TEST_F(BacktraceTest, check_for_leak_remote) {
   pid_t pid;
   CreateRemoteProcess(&pid);
 
@@ -1888,4 +1891,3 @@
 
   FinishRemoteProcess(pid);
 }
-#endif
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index 2e2bf87..574a386 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -72,7 +72,7 @@
   explicit MapString(const std::string& str)
       : alloc(new std::string(str)), str(alloc->data(), alloc->length()) {
   }
-  MapString(MapString&& rval)
+  MapString(MapString&& rval) noexcept
       : alloc(rval.alloc), str(rval.data(), rval.length()) {
     rval.alloc = NULL;
   }
diff --git a/libmemunreachable/ScopedPipe.h b/libmemunreachable/ScopedPipe.h
index adabfd8..b9dead5 100644
--- a/libmemunreachable/ScopedPipe.h
+++ b/libmemunreachable/ScopedPipe.h
@@ -33,12 +33,12 @@
   }
   ~ScopedPipe() { Close(); }
 
-  ScopedPipe(ScopedPipe&& other) {
+  ScopedPipe(ScopedPipe&& other) noexcept {
     SetReceiver(other.ReleaseReceiver());
     SetSender(other.ReleaseSender());
   }
 
-  ScopedPipe& operator=(ScopedPipe&& other) {
+  ScopedPipe& operator=(ScopedPipe&& other) noexcept {
     SetReceiver(other.ReleaseReceiver());
     SetSender(other.ReleaseSender());
     return *this;
diff --git a/libmemunreachable/Tarjan.h b/libmemunreachable/Tarjan.h
index 355679f..f3ab652 100644
--- a/libmemunreachable/Tarjan.h
+++ b/libmemunreachable/Tarjan.h
@@ -38,7 +38,7 @@
 
   Node(T* ptr, Allocator<Node> allocator)
       : references_in(allocator), references_out(allocator), ptr(ptr){};
-  Node(Node&& rhs) = default;
+  Node(Node&& rhs) noexcept = default;
   void Edge(Node<T>* ref) {
     references_out.emplace(ref);
     ref->references_in.emplace(this);
diff --git a/libstats/include/stats_event_list.h b/libstats/include/stats_event_list.h
index 5d174ae..a9832db 100644
--- a/libstats/include/stats_event_list.h
+++ b/libstats/include/stats_event_list.h
@@ -24,6 +24,8 @@
 #endif
 void reset_log_context(android_log_context ctx);
 int write_to_logger(android_log_context context, log_id_t id);
+void note_log_drop();
+void stats_log_close();
 
 #ifdef __cplusplus
 }
diff --git a/libstats/stats_event_list.c b/libstats/stats_event_list.c
index 3d746db..735088a 100644
--- a/libstats/stats_event_list.c
+++ b/libstats/stats_event_list.c
@@ -119,6 +119,18 @@
     return retValue;
 }
 
+void note_log_drop() {
+    statsdLoggerWrite.noteDrop();
+}
+
+void stats_log_close() {
+    statsd_writer_init_lock();
+    if (statsdLoggerWrite.close) {
+        (*statsdLoggerWrite.close)();
+    }
+    statsd_writer_init_unlock();
+}
+
 /* log_init_lock assumed */
 static int __write_to_statsd_initialize_locked() {
     if (!statsdLoggerWrite.open || ((*statsdLoggerWrite.open)() < 0)) {
diff --git a/libstats/statsd_writer.c b/libstats/statsd_writer.c
index 9953bba..afe401f 100644
--- a/libstats/statsd_writer.c
+++ b/libstats/statsd_writer.c
@@ -38,6 +38,7 @@
 #define min(x, y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
 
 static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
+static atomic_int dropped = 0;
 
 void statsd_writer_init_lock() {
     /*
@@ -59,14 +60,16 @@
 static int statsdOpen();
 static void statsdClose();
 static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr);
+static void statsdNoteDrop();
 
 struct android_log_transport_write statsdLoggerWrite = {
-    .name = "statsd",
-    .sock = -EBADF,
-    .available = statsdAvailable,
-    .open = statsdOpen,
-    .close = statsdClose,
-    .write = statsdWrite,
+        .name = "statsd",
+        .sock = -EBADF,
+        .available = statsdAvailable,
+        .open = statsdOpen,
+        .close = statsdClose,
+        .write = statsdWrite,
+        .noteDrop = statsdNoteDrop,
 };
 
 /* log_init_lock assumed */
@@ -131,6 +134,10 @@
     return 1;
 }
 
+static void statsdNoteDrop() {
+    atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
+}
+
 static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) {
     ssize_t ret;
     int sock;
@@ -138,7 +145,6 @@
     struct iovec newVec[nr + headerLength];
     android_log_header_t header;
     size_t i, payloadSize;
-    static atomic_int dropped;
 
     sock = atomic_load(&statsdLoggerWrite.sock);
     if (sock < 0) switch (sock) {
@@ -252,8 +258,6 @@
 
     if (ret > (ssize_t)sizeof(header)) {
         ret -= sizeof(header);
-    } else if (ret == -EAGAIN) {
-        atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
     }
 
     return ret;
diff --git a/libstats/statsd_writer.h b/libstats/statsd_writer.h
index 82e14e0..7289441 100644
--- a/libstats/statsd_writer.h
+++ b/libstats/statsd_writer.h
@@ -38,6 +38,8 @@
     void (*close)();    /* free up resources */
     /* write log to transport, returns number of bytes propagated, or -errno */
     int (*write)(struct timespec* ts, struct iovec* vec, size_t nr);
+    /* note one log drop */
+    void (*noteDrop)();
 };
 
 #endif  // ANDROID_STATS_LOG_STATS_WRITER_H
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index be2145d..970e05c 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -178,6 +178,7 @@
         "tests/JitDebugTest.cpp",
         "tests/LocalUnwinderTest.cpp",
         "tests/LogFake.cpp",
+        "tests/MapInfoCreateMemoryTest.cpp",
         "tests/MapInfoGetElfTest.cpp",
         "tests/MapInfoGetLoadBiasTest.cpp",
         "tests/MapsTest.cpp",
@@ -188,6 +189,7 @@
         "tests/MemoryOfflineBufferTest.cpp",
         "tests/MemoryOfflineTest.cpp",
         "tests/MemoryRangeTest.cpp",
+        "tests/MemoryRangesTest.cpp",
         "tests/MemoryRemoteTest.cpp",
         "tests/MemoryTest.cpp",
         "tests/RegsInfoTest.cpp",
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 39378a3..64005ae 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -102,7 +102,54 @@
   if (!(flags & PROT_READ)) {
     return nullptr;
   }
-  return new MemoryRange(process_memory, start, end - start, 0);
+
+  // Need to verify that this elf is valid. It's possible that
+  // only part of the elf file to be mapped into memory is in the executable
+  // map. In this case, there will be another read-only map that includes the
+  // first part of the elf file. This is done if the linker rosegment
+  // option is used.
+  std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start, end - start, 0));
+  bool valid;
+  uint64_t max_size;
+  Elf::GetInfo(memory.get(), &valid, &max_size);
+  if (valid) {
+    // Valid elf, we are done.
+    return memory.release();
+  }
+
+  if (name.empty() || maps_ == nullptr) {
+    return nullptr;
+  }
+
+  // Find the read-only map that has the same name and has an offset closest
+  // to the current offset but less than the offset of the current map.
+  // For shared libraries, there should be a r-x map that has a non-zero
+  // offset and then a r-- map that has a zero offset.
+  // For shared libraries loaded from an apk, there should be a r-x map that
+  // has a non-zero offset and then a r-- map that has a non-zero offset less
+  // than the offset from the r-x map.
+  uint64_t closest_offset = 0;
+  MapInfo* ro_map_info = nullptr;
+  for (auto map_info : *maps_) {
+    if (map_info->flags == PROT_READ && map_info->name == name && map_info->offset < offset &&
+        map_info->offset >= closest_offset) {
+      ro_map_info = map_info;
+      closest_offset = ro_map_info->offset;
+    }
+  }
+
+  if (ro_map_info != nullptr) {
+    // Make sure that relative pc values are corrected properly.
+    elf_offset = offset - closest_offset;
+
+    MemoryRanges* ranges = new MemoryRanges;
+    ranges->Insert(new MemoryRange(process_memory, ro_map_info->start,
+                                   ro_map_info->end - ro_map_info->start, 0));
+    ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset));
+
+    return ranges;
+  }
+  return nullptr;
 }
 
 Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata) {
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index e676a5a..8729871 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -66,13 +66,13 @@
         if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
           flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
         }
-        maps_.push_back(new MapInfo(start, end, pgoff, flags, name));
+        maps_.push_back(new MapInfo(this, start, end, pgoff, flags, name));
       });
 }
 
 void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
                const std::string& name, uint64_t load_bias) {
-  MapInfo* map_info = new MapInfo(start, end, offset, flags, name);
+  MapInfo* map_info = new MapInfo(this, start, end, offset, flags, name);
   map_info->load_bias = load_bias;
   maps_.push_back(map_info);
 }
@@ -97,7 +97,7 @@
         if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
           flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
         }
-        maps_.push_back(new MapInfo(start, end, pgoff, flags, name));
+        maps_.push_back(new MapInfo(this, start, end, pgoff, flags, name));
       });
 }
 
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index beb2aad..cfa8c6d 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -316,6 +316,18 @@
   return memory_->Read(read_addr, dst, read_length);
 }
 
+void MemoryRanges::Insert(MemoryRange* memory) {
+  maps_.emplace(memory->offset() + memory->length(), memory);
+}
+
+size_t MemoryRanges::Read(uint64_t addr, void* dst, size_t size) {
+  auto entry = maps_.upper_bound(addr);
+  if (entry != maps_.end()) {
+    return entry->second->Read(addr, dst, size);
+  }
+  return 0;
+}
+
 bool MemoryOffline::Init(const std::string& file, uint64_t offset) {
   auto memory_file = std::make_shared<MemoryFileAtOffset>();
   if (!memory_file->Init(file, offset)) {
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index ac0df41..9755c48 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -29,20 +29,25 @@
 namespace unwindstack {
 
 // Forward declarations.
+class Maps;
 class Memory;
 
 struct MapInfo {
-  MapInfo() = default;
-  MapInfo(uint64_t start, uint64_t end) : start(start), end(end) {}
-  MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const char* name)
-      : start(start),
+  MapInfo(Maps* maps) : maps_(maps) {}
+  MapInfo(Maps* maps, uint64_t start, uint64_t end) : maps_(maps), start(start), end(end) {}
+  MapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
+          const char* name)
+      : maps_(maps),
+        start(start),
         end(end),
         offset(offset),
         flags(flags),
         name(name),
         load_bias(static_cast<uint64_t>(-1)) {}
-  MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name)
-      : start(start),
+  MapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
+          const std::string& name)
+      : maps_(maps),
+        start(start),
         end(end),
         offset(offset),
         flags(flags),
@@ -50,6 +55,8 @@
         load_bias(static_cast<uint64_t>(-1)) {}
   ~MapInfo() = default;
 
+  Maps* maps_ = nullptr;
+
   uint64_t start = 0;
   uint64_t end = 0;
   uint64_t offset = 0;
@@ -69,14 +76,14 @@
 
   uint64_t GetLoadBias(const std::shared_ptr<Memory>& process_memory);
 
+  Memory* CreateMemory(const std::shared_ptr<Memory>& process_memory);
+
  private:
   MapInfo(const MapInfo&) = delete;
   void operator=(const MapInfo&) = delete;
 
   Memory* GetFileMemory();
 
-  Memory* CreateMemory(const std::shared_ptr<Memory>& process_memory);
-
   // Protect the creation of the elf object.
   std::mutex mutex_;
 };
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index dee5e98..9c425cb 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -22,6 +22,7 @@
 #include <unistd.h>
 
 #include <atomic>
+#include <map>
 #include <memory>
 #include <string>
 #include <vector>
@@ -119,6 +120,9 @@
 
   size_t Read(uint64_t addr, void* dst, size_t size) override;
 
+  uint64_t offset() { return offset_; }
+  uint64_t length() { return length_; }
+
  private:
   std::shared_ptr<Memory> memory_;
   uint64_t begin_;
@@ -126,6 +130,19 @@
   uint64_t offset_;
 };
 
+class MemoryRanges : public Memory {
+ public:
+  MemoryRanges() = default;
+  virtual ~MemoryRanges() = default;
+
+  void Insert(MemoryRange* memory);
+
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+ private:
+  std::map<uint64_t, std::unique_ptr<MemoryRange>> maps_;
+};
+
 class MemoryOffline : public Memory {
  public:
   MemoryOffline() = default;
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
index 4dd8cb0..40f9f8e 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -120,7 +120,7 @@
             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
 
   MemoryFake memory;
-  MapInfo info(0, 0x10000, 0, 0x5, tf.path);
+  MapInfo info(nullptr, 0, 0x10000, 0, 0x5, tf.path);
   std::unique_ptr<DexFile> dex_file(DexFile::Create(0x500, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 }
@@ -134,7 +134,7 @@
             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
 
   MemoryFake memory;
-  MapInfo info(0x100, 0x10000, 0, 0x5, tf.path);
+  MapInfo info(nullptr, 0x100, 0x10000, 0, 0x5, tf.path);
   std::unique_ptr<DexFile> dex_file(DexFile::Create(0x600, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 }
@@ -148,7 +148,7 @@
             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
 
   MemoryFake memory;
-  MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path);
+  MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, tf.path);
   std::unique_ptr<DexFile> dex_file(DexFile::Create(0x400, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 }
@@ -156,7 +156,7 @@
 TEST(DexFileTest, create_using_memory_empty_file) {
   MemoryFake memory;
   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
-  MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+  MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "");
   std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 }
@@ -164,7 +164,7 @@
 TEST(DexFileTest, create_using_memory_file_does_not_exist) {
   MemoryFake memory;
   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
-  MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
+  MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
   std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 }
@@ -178,7 +178,7 @@
 
   MemoryFake memory;
   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
-  MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
+  MapInfo info(nullptr, 0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
   std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 
@@ -200,7 +200,7 @@
 TEST(DexFileTest, get_method) {
   MemoryFake memory;
   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
-  MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+  MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "");
   std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 
@@ -227,7 +227,7 @@
 TEST(DexFileTest, get_method_empty) {
   MemoryFake memory;
   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
-  MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+  MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "");
   std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 
diff --git a/libunwindstack/tests/ElfCacheTest.cpp b/libunwindstack/tests/ElfCacheTest.cpp
index 89331ea..1afd4ef 100644
--- a/libunwindstack/tests/ElfCacheTest.cpp
+++ b/libunwindstack/tests/ElfCacheTest.cpp
@@ -79,8 +79,8 @@
 
   uint64_t start = 0x1000;
   uint64_t end = 0x20000;
-  MapInfo info1(start, end, 0, 0x5, tf.path);
-  MapInfo info2(start, end, 0, 0x5, tf.path);
+  MapInfo info1(nullptr, start, end, 0, 0x5, tf.path);
+  MapInfo info2(nullptr, start, end, 0, 0x5, tf.path);
 
   Elf* elf1 = info1.GetElf(memory_, true);
   ASSERT_TRUE(elf1->valid());
@@ -120,17 +120,17 @@
   uint64_t start = 0x1000;
   uint64_t end = 0x20000;
   // Will have an elf at offset 0 in file.
-  MapInfo info0_1(start, end, 0, 0x5, tf.path);
-  MapInfo info0_2(start, end, 0, 0x5, tf.path);
+  MapInfo info0_1(nullptr, start, end, 0, 0x5, tf.path);
+  MapInfo info0_2(nullptr, start, end, 0, 0x5, tf.path);
   // Will have an elf at offset 0x100 in file.
-  MapInfo info100_1(start, end, 0x100, 0x5, tf.path);
-  MapInfo info100_2(start, end, 0x100, 0x5, tf.path);
+  MapInfo info100_1(nullptr, start, end, 0x100, 0x5, tf.path);
+  MapInfo info100_2(nullptr, start, end, 0x100, 0x5, tf.path);
   // Will have an elf at offset 0x200 in file.
-  MapInfo info200_1(start, end, 0x200, 0x5, tf.path);
-  MapInfo info200_2(start, end, 0x200, 0x5, tf.path);
+  MapInfo info200_1(nullptr, start, end, 0x200, 0x5, tf.path);
+  MapInfo info200_2(nullptr, start, end, 0x200, 0x5, tf.path);
   // Will have an elf at offset 0 in file.
-  MapInfo info300_1(start, end, 0x300, 0x5, tf.path);
-  MapInfo info300_2(start, end, 0x300, 0x5, tf.path);
+  MapInfo info300_1(nullptr, start, end, 0x300, 0x5, tf.path);
+  MapInfo info300_2(nullptr, start, end, 0x300, 0x5, tf.path);
 
   Elf* elf0_1 = info0_1.GetElf(memory_, true);
   ASSERT_TRUE(elf0_1->valid());
@@ -217,10 +217,10 @@
   uint64_t start = 0x1000;
   uint64_t end = 0x20000;
   // Multiple info sections at different offsets will have non-zero elf offsets.
-  MapInfo info300_1(start, end, 0x300, 0x5, tf.path);
-  MapInfo info300_2(start, end, 0x300, 0x5, tf.path);
-  MapInfo info400_1(start, end, 0x400, 0x5, tf.path);
-  MapInfo info400_2(start, end, 0x400, 0x5, tf.path);
+  MapInfo info300_1(nullptr, start, end, 0x300, 0x5, tf.path);
+  MapInfo info300_2(nullptr, start, end, 0x300, 0x5, tf.path);
+  MapInfo info400_1(nullptr, start, end, 0x400, 0x5, tf.path);
+  MapInfo info400_2(nullptr, start, end, 0x400, 0x5, tf.path);
 
   Elf* elf300_1 = info300_1.GetElf(memory_, true);
   ASSERT_TRUE(elf300_1->valid());
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 55fe16f..9a117b2 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -297,7 +297,7 @@
   elf.FakeSetInterface(interface);
 
   elf.FakeSetValid(true);
-  MapInfo map_info(0x1000, 0x2000);
+  MapInfo map_info(nullptr, 0x1000, 0x2000);
 
   ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
 
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 866b5b4..2a73c7e 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -32,8 +32,10 @@
 
 #include <unwindstack/Elf.h>
 #include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 
+#include "ElfTestUtils.h"
 #include "MemoryFake.h"
 
 namespace unwindstack {
@@ -94,7 +96,7 @@
 TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_;
 
 TEST_F(MapInfoCreateMemoryTest, end_le_start) {
-  MapInfo info(0x100, 0x100, 0, 0, elf_.path);
+  MapInfo info(nullptr, 0x100, 0x100, 0, 0, elf_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() == nullptr);
@@ -112,7 +114,7 @@
 // Verify that if the offset is non-zero but there is no elf at the offset,
 // that the full file is used.
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
-  MapInfo info(0x100, 0x200, 0x100, 0, elf_.path);
+  MapInfo info(nullptr, 0x100, 0x200, 0x100, 0, elf_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
@@ -133,7 +135,7 @@
 // Verify that if the offset is non-zero and there is an elf at that
 // offset, that only part of the file is used.
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
-  MapInfo info(0x100, 0x200, 0x100, 0, elf_at_100_.path);
+  MapInfo info(nullptr, 0x100, 0x200, 0x100, 0, elf_at_100_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
@@ -156,7 +158,7 @@
 // embedded elf is bigger than the initial map, the new object is larger
 // than the original map size. Do this for a 32 bit elf and a 64 bit elf.
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
-  MapInfo info(0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path);
+  MapInfo info(nullptr, 0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
@@ -172,7 +174,7 @@
 }
 
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
-  MapInfo info(0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path);
+  MapInfo info(nullptr, 0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
@@ -192,27 +194,24 @@
   // Set up some memory so that a valid local memory object would
   // be returned if the file mapping fails, but the device check is incorrect.
   std::vector<uint8_t> buffer(1024);
-  MapInfo info;
-  info.start = reinterpret_cast<uint64_t>(buffer.data());
-  info.end = info.start + buffer.size();
-  info.offset = 0;
+  uint64_t start = reinterpret_cast<uint64_t>(buffer.data());
+  MapInfo info(nullptr, start, start + buffer.size(), 0, 0x8000, "/dev/something");
 
-  info.flags = 0x8000;
-  info.name = "/dev/something";
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() == nullptr);
 }
 
 TEST_F(MapInfoCreateMemoryTest, process_memory) {
-  MapInfo info;
-  info.start = 0x2000;
-  info.end = 0x3000;
-  info.offset = 0;
+  MapInfo info(nullptr, 0x2000, 0x3000, 0, PROT_READ, "");
+
+  Elf32_Ehdr ehdr = {};
+  TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+  std::vector<uint8_t> buffer(1024);
+  memcpy(buffer.data(), &ehdr, sizeof(ehdr));
 
   // Verify that the the process_memory object is used, so seed it
   // with memory.
-  std::vector<uint8_t> buffer(1024);
-  for (size_t i = 0; i < buffer.size(); i++) {
+  for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
     buffer[i] = i % 256;
   }
   memory_->SetMemory(info.start, buffer.data(), buffer.size());
@@ -222,7 +221,8 @@
 
   memset(buffer.data(), 0, buffer.size());
   ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size()));
-  for (size_t i = 0; i < buffer.size(); i++) {
+  ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr)));
+  for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
     ASSERT_EQ(i % 256, buffer[i]) << "Failed at byte " << i;
   }
 
@@ -230,4 +230,87 @@
   ASSERT_FALSE(memory->ReadFully(buffer.size(), buffer.data(), 1));
 }
 
+TEST_F(MapInfoCreateMemoryTest, valid_rosegment_zero_offset) {
+  Maps maps;
+  maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0);
+  maps.Add(0x1000, 0x2600, 0, PROT_READ, "/only/in/memory.so", 0);
+  maps.Add(0x3000, 0x5000, 0x4000, PROT_READ | PROT_EXEC, "/only/in/memory.so", 0);
+
+  Elf32_Ehdr ehdr = {};
+  TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+  memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
+  memory_->SetMemoryBlock(0x1000 + sizeof(ehdr), 0x1600 - sizeof(ehdr), 0xab);
+
+  // Set the memory in the r-x map.
+  memory_->SetMemoryBlock(0x3000, 0x2000, 0x5d);
+
+  MapInfo* map_info = maps.Find(0x3000);
+  ASSERT_TRUE(map_info != nullptr);
+
+  std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
+  ASSERT_TRUE(mem.get() != nullptr);
+  EXPECT_EQ(0x4000UL, map_info->elf_offset);
+  EXPECT_EQ(0x4000UL, map_info->offset);
+
+  // Verify that reading values from this memory works properly.
+  std::vector<uint8_t> buffer(0x4000);
+  size_t bytes = mem->Read(0, buffer.data(), buffer.size());
+  ASSERT_EQ(0x1600UL, bytes);
+  ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr)));
+  for (size_t i = sizeof(ehdr); i < bytes; i++) {
+    ASSERT_EQ(0xab, buffer[i]) << "Failed at byte " << i;
+  }
+
+  bytes = mem->Read(0x4000, buffer.data(), buffer.size());
+  ASSERT_EQ(0x2000UL, bytes);
+  for (size_t i = 0; i < bytes; i++) {
+    ASSERT_EQ(0x5d, buffer[i]) << "Failed at byte " << i;
+  }
+}
+
+TEST_F(MapInfoCreateMemoryTest, valid_rosegment_non_zero_offset) {
+  Maps maps;
+  maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0);
+  maps.Add(0x1000, 0x2000, 0, PROT_READ, "/only/in/memory.apk", 0);
+  maps.Add(0x2000, 0x3000, 0x1000, PROT_READ | PROT_EXEC, "/only/in/memory.apk", 0);
+  maps.Add(0x3000, 0x4000, 0xa000, PROT_READ, "/only/in/memory.apk", 0);
+  maps.Add(0x4000, 0x5000, 0xb000, PROT_READ | PROT_EXEC, "/only/in/memory.apk", 0);
+
+  Elf32_Ehdr ehdr = {};
+  TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+
+  // Setup an elf at offset 0x1000 in memory.
+  memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
+  memory_->SetMemoryBlock(0x1000 + sizeof(ehdr), 0x2000 - sizeof(ehdr), 0x12);
+  memory_->SetMemoryBlock(0x2000, 0x1000, 0x23);
+
+  // Setup an elf at offset 0x3000 in memory..
+  memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
+  memory_->SetMemoryBlock(0x3000 + sizeof(ehdr), 0x4000 - sizeof(ehdr), 0x34);
+  memory_->SetMemoryBlock(0x4000, 0x1000, 0x43);
+
+  MapInfo* map_info = maps.Find(0x4000);
+  ASSERT_TRUE(map_info != nullptr);
+
+  std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
+  ASSERT_TRUE(mem.get() != nullptr);
+  EXPECT_EQ(0x1000UL, map_info->elf_offset);
+  EXPECT_EQ(0xb000UL, map_info->offset);
+
+  // Verify that reading values from this memory works properly.
+  std::vector<uint8_t> buffer(0x4000);
+  size_t bytes = mem->Read(0, buffer.data(), buffer.size());
+  ASSERT_EQ(0x1000UL, bytes);
+  ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr)));
+  for (size_t i = sizeof(ehdr); i < bytes; i++) {
+    ASSERT_EQ(0x34, buffer[i]) << "Failed at byte " << i;
+  }
+
+  bytes = mem->Read(0x1000, buffer.data(), buffer.size());
+  ASSERT_EQ(0x1000UL, bytes);
+  for (size_t i = 0; i < bytes; i++) {
+    ASSERT_EQ(0x43, buffer[i]) << "Failed at byte " << i;
+  }
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index 861b82f..918c028 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -69,7 +69,7 @@
 };
 
 TEST_F(MapInfoGetElfTest, invalid) {
-  MapInfo info(0x1000, 0x2000, 0, PROT_READ, "");
+  MapInfo info(nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
 
   // The map is empty, but this should still create an invalid elf object.
   Elf* elf = info.GetElf(process_memory_, false);
@@ -78,7 +78,7 @@
 }
 
 TEST_F(MapInfoGetElfTest, valid32) {
-  MapInfo info(0x3000, 0x4000, 0, PROT_READ, "");
+  MapInfo info(nullptr, 0x3000, 0x4000, 0, PROT_READ, "");
 
   Elf32_Ehdr ehdr;
   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
@@ -92,7 +92,7 @@
 }
 
 TEST_F(MapInfoGetElfTest, valid64) {
-  MapInfo info(0x8000, 0x9000, 0, PROT_READ, "");
+  MapInfo info(nullptr, 0x8000, 0x9000, 0, PROT_READ, "");
 
   Elf64_Ehdr ehdr;
   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
@@ -106,7 +106,7 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) {
-  MapInfo info(0x4000, 0x8000, 0, PROT_READ, "");
+  MapInfo info(nullptr, 0x4000, 0x8000, 0, PROT_READ, "");
 
   TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
@@ -122,7 +122,7 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) {
-  MapInfo info(0x6000, 0x8000, 0, PROT_READ, "");
+  MapInfo info(nullptr, 0x6000, 0x8000, 0, PROT_READ, "");
 
   TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
@@ -138,7 +138,7 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
-  MapInfo info(0x2000, 0x3000, 0, PROT_READ, "");
+  MapInfo info(nullptr, 0x2000, 0x3000, 0, PROT_READ, "");
 
   TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
@@ -154,7 +154,7 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
-  MapInfo info(0x5000, 0x8000, 0, PROT_READ, "");
+  MapInfo info(nullptr, 0x5000, 0x8000, 0, PROT_READ, "");
 
   TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
@@ -170,7 +170,7 @@
 }
 
 TEST_F(MapInfoGetElfTest, end_le_start) {
-  MapInfo info(0x1000, 0x1000, 0, PROT_READ, elf_.path);
+  MapInfo info(nullptr, 0x1000, 0x1000, 0, PROT_READ, elf_.path);
 
   Elf32_Ehdr ehdr;
   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
@@ -197,7 +197,7 @@
 // Verify that if the offset is non-zero but there is no elf at the offset,
 // that the full file is used.
 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
-  MapInfo info(0x1000, 0x2000, 0x100, PROT_READ, elf_.path);
+  MapInfo info(nullptr, 0x1000, 0x2000, 0x100, PROT_READ, elf_.path);
 
   std::vector<uint8_t> buffer(0x1000);
   memset(buffer.data(), 0, buffer.size());
@@ -226,7 +226,7 @@
 // Verify that if the offset is non-zero and there is an elf at that
 // offset, that only part of the file is used.
 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
-  MapInfo info(0x1000, 0x2000, 0x2000, PROT_READ, elf_.path);
+  MapInfo info(nullptr, 0x1000, 0x2000, 0x2000, PROT_READ, elf_.path);
 
   std::vector<uint8_t> buffer(0x4000);
   memset(buffer.data(), 0, buffer.size());
@@ -256,7 +256,7 @@
 // embedded elf is bigger than the initial map, the new object is larger
 // than the original map size. Do this for a 32 bit elf and a 64 bit elf.
 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
-  MapInfo info(0x5000, 0x6000, 0x1000, PROT_READ, elf_.path);
+  MapInfo info(nullptr, 0x5000, 0x6000, 0x1000, PROT_READ, elf_.path);
 
   std::vector<uint8_t> buffer(0x4000);
   memset(buffer.data(), 0, buffer.size());
@@ -284,7 +284,7 @@
 }
 
 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
-  MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ, elf_.path);
+  MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, elf_.path);
 
   std::vector<uint8_t> buffer(0x4000);
   memset(buffer.data(), 0, buffer.size());
@@ -312,7 +312,7 @@
 }
 
 TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
-  MapInfo info(0x9000, 0xa000, 0x1000, 0, "");
+  MapInfo info(nullptr, 0x9000, 0xa000, 0x1000, 0, "");
 
   // Create valid elf data in process memory only.
   Elf64_Ehdr ehdr;
@@ -333,7 +333,8 @@
 }
 
 TEST_F(MapInfoGetElfTest, check_device_maps) {
-  MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP, "/dev/something");
+  MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP,
+               "/dev/something");
 
   // Create valid elf data in process memory for this to verify that only
   // the name is causing invalid elf data.
@@ -378,7 +379,7 @@
   wait = true;
   // Create all of the threads and have them do the GetElf at the same time
   // to make it likely that a race will occur.
-  MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ, "");
+  MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, "");
   for (size_t i = 0; i < kNumConcurrentThreads; i++) {
     std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
       while (wait)
diff --git a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
index 7e64a8a..f5ac6cb 100644
--- a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
+++ b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
@@ -50,7 +50,7 @@
     process_memory_.reset(memory_);
     elf_ = new ElfFake(new MemoryFake);
     elf_container_.reset(elf_);
-    map_info_.reset(new MapInfo(0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, ""));
+    map_info_.reset(new MapInfo(nullptr, 0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, ""));
   }
 
   void MultipleThreadTest(uint64_t expected_load_bias);
@@ -63,7 +63,7 @@
 };
 
 TEST_F(MapInfoGetLoadBiasTest, no_elf_and_no_valid_elf_in_memory) {
-  MapInfo info(0x1000, 0x2000, 0, PROT_READ, "");
+  MapInfo info(nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
 
   EXPECT_EQ(0U, info.GetLoadBias(process_memory_));
 }
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
index 9622ba5..6bdd0b2 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -63,7 +63,7 @@
 }
 
 TEST(MapsTest, verify_parse_line) {
-  MapInfo info;
+  MapInfo info(nullptr);
 
   VerifyLine("01-02 rwxp 03 04:05 06\n", &info);
   EXPECT_EQ(1U, info.start);
@@ -136,7 +136,7 @@
 }
 
 TEST(MapsTest, verify_large_values) {
-  MapInfo info;
+  MapInfo info(nullptr);
 #if defined(__LP64__)
   VerifyLine("fabcdef012345678-f12345678abcdef8 rwxp f0b0d0f010305070 00:00 0\n", &info);
   EXPECT_EQ(0xfabcdef012345678UL, info.start);
diff --git a/libunwindstack/tests/MemoryFake.cpp b/libunwindstack/tests/MemoryFake.cpp
index 60936cd..5695dfc 100644
--- a/libunwindstack/tests/MemoryFake.cpp
+++ b/libunwindstack/tests/MemoryFake.cpp
@@ -23,6 +23,17 @@
 
 namespace unwindstack {
 
+void MemoryFake::SetMemoryBlock(uint64_t addr, size_t length, uint8_t value) {
+  for (size_t i = 0; i < length; i++, addr++) {
+    auto entry = data_.find(addr);
+    if (entry != data_.end()) {
+      entry->second = value;
+    } else {
+      data_.insert({addr, value});
+    }
+  }
+}
+
 void MemoryFake::SetMemory(uint64_t addr, const void* memory, size_t length) {
   const uint8_t* src = reinterpret_cast<const uint8_t*>(memory);
   for (size_t i = 0; i < length; i++, addr++) {
diff --git a/libunwindstack/tests/MemoryFake.h b/libunwindstack/tests/MemoryFake.h
index 764a6c3..20610a5 100644
--- a/libunwindstack/tests/MemoryFake.h
+++ b/libunwindstack/tests/MemoryFake.h
@@ -36,6 +36,8 @@
 
   void SetMemory(uint64_t addr, const void* memory, size_t length);
 
+  void SetMemoryBlock(uint64_t addr, size_t length, uint8_t value);
+
   void SetData8(uint64_t addr, uint8_t value) {
     SetMemory(addr, &value, sizeof(value));
   }
diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp
index cb1a0c9..2bac95b 100644
--- a/libunwindstack/tests/MemoryRangeTest.cpp
+++ b/libunwindstack/tests/MemoryRangeTest.cpp
@@ -15,7 +15,6 @@
  */
 
 #include <stdint.h>
-#include <string.h>
 
 #include <memory>
 #include <vector>
@@ -28,30 +27,34 @@
 
 namespace unwindstack {
 
-TEST(MemoryRangeTest, read) {
-  std::vector<uint8_t> src(1024);
-  memset(src.data(), 0x4c, 1024);
-  MemoryFake* memory_fake = new MemoryFake;
-  std::shared_ptr<Memory> process_memory(memory_fake);
-  memory_fake->SetMemory(9001, src);
+class MemoryRangeTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    process_memory_.reset();
+    memory_fake_ = new MemoryFake;
+    process_memory_.reset(memory_fake_);
+  }
 
-  MemoryRange range(process_memory, 9001, src.size(), 0);
+  std::shared_ptr<Memory> process_memory_;
+  MemoryFake* memory_fake_ = nullptr;
+};
+
+TEST_F(MemoryRangeTest, read_fully) {
+  memory_fake_->SetMemoryBlock(9000, 2048, 0x4c);
+
+  MemoryRange range(process_memory_, 9001, 1024, 0);
 
   std::vector<uint8_t> dst(1024);
-  ASSERT_TRUE(range.ReadFully(0, dst.data(), src.size()));
-  for (size_t i = 0; i < 1024; i++) {
+  ASSERT_TRUE(range.ReadFully(0, dst.data(), dst.size()));
+  for (size_t i = 0; i < dst.size(); i++) {
     ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
   }
 }
 
-TEST(MemoryRangeTest, read_near_limit) {
-  std::vector<uint8_t> src(4096);
-  memset(src.data(), 0x4c, 4096);
-  MemoryFake* memory_fake = new MemoryFake;
-  std::shared_ptr<Memory> process_memory(memory_fake);
-  memory_fake->SetMemory(1000, src);
+TEST_F(MemoryRangeTest, read_fully_near_limit) {
+  memory_fake_->SetMemoryBlock(0, 8192, 0x4c);
 
-  MemoryRange range(process_memory, 1000, 1024, 0);
+  MemoryRange range(process_memory_, 1000, 1024, 0);
 
   std::vector<uint8_t> dst(1024);
   ASSERT_TRUE(range.ReadFully(1020, dst.data(), 4));
@@ -68,7 +71,7 @@
   ASSERT_TRUE(range.ReadFully(1020, dst.data(), 4));
 }
 
-TEST(MemoryRangeTest, read_overflow) {
+TEST_F(MemoryRangeTest, read_fully_overflow) {
   std::vector<uint8_t> buffer(100);
 
   std::shared_ptr<Memory> process_memory(new MemoryFakeAlwaysReadZero);
@@ -76,19 +79,28 @@
   ASSERT_FALSE(overflow->ReadFully(UINT64_MAX - 10, buffer.data(), 100));
 }
 
-TEST(MemoryRangeTest, Read) {
-  std::vector<uint8_t> src(4096);
-  memset(src.data(), 0x4c, 4096);
-  MemoryFake* memory_fake = new MemoryFake;
-  std::shared_ptr<Memory> process_memory(memory_fake);
-  memory_fake->SetMemory(1000, src);
+TEST_F(MemoryRangeTest, read) {
+  memory_fake_->SetMemoryBlock(0, 4096, 0x4c);
 
-  MemoryRange range(process_memory, 1000, 1024, 0);
+  MemoryRange range(process_memory_, 1000, 1024, 0);
+
   std::vector<uint8_t> dst(1024);
-  ASSERT_EQ(4U, range.Read(1020, dst.data(), 1024));
+  ASSERT_EQ(4U, range.Read(1020, dst.data(), dst.size()));
   for (size_t i = 0; i < 4; i++) {
     ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
   }
 }
 
+TEST_F(MemoryRangeTest, read_non_zero_offset) {
+  memory_fake_->SetMemoryBlock(1000, 1024, 0x12);
+
+  MemoryRange range(process_memory_, 1000, 1024, 400);
+
+  std::vector<uint8_t> dst(1024);
+  ASSERT_EQ(1024U, range.Read(400, dst.data(), dst.size()));
+  for (size_t i = 0; i < dst.size(); i++) {
+    ASSERT_EQ(0x12U, dst[i]) << "Failed at byte " << i;
+  }
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRangesTest.cpp b/libunwindstack/tests/MemoryRangesTest.cpp
new file mode 100644
index 0000000..d24fcd2
--- /dev/null
+++ b/libunwindstack/tests/MemoryRangesTest.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Memory.h>
+
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class MemoryRangesTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    MemoryFake* memory = new MemoryFake;
+    process_memory_.reset(memory);
+    memory->SetMemoryBlock(1000, 5000, 0x15);
+    memory->SetMemoryBlock(6000, 12000, 0x26);
+    memory->SetMemoryBlock(14000, 20000, 0x37);
+    memory->SetMemoryBlock(20000, 22000, 0x48);
+
+    ranges_.reset(new MemoryRanges);
+    ranges_->Insert(new MemoryRange(process_memory_, 15000, 100, 4000));
+    ranges_->Insert(new MemoryRange(process_memory_, 10000, 2000, 2000));
+    ranges_->Insert(new MemoryRange(process_memory_, 3000, 1000, 0));
+    ranges_->Insert(new MemoryRange(process_memory_, 19000, 1000, 6000));
+    ranges_->Insert(new MemoryRange(process_memory_, 20000, 1000, 7000));
+  }
+
+  std::shared_ptr<Memory> process_memory_;
+  std::unique_ptr<MemoryRanges> ranges_;
+};
+
+TEST_F(MemoryRangesTest, read) {
+  std::vector<uint8_t> dst(2000);
+  size_t bytes = ranges_->Read(0, dst.data(), dst.size());
+  ASSERT_EQ(1000UL, bytes);
+  for (size_t i = 0; i < bytes; i++) {
+    ASSERT_EQ(0x15U, dst[i]) << "Failed at byte " << i;
+  }
+
+  bytes = ranges_->Read(2000, dst.data(), dst.size());
+  ASSERT_EQ(2000UL, bytes);
+  for (size_t i = 0; i < bytes; i++) {
+    ASSERT_EQ(0x26U, dst[i]) << "Failed at byte " << i;
+  }
+
+  bytes = ranges_->Read(4000, dst.data(), dst.size());
+  ASSERT_EQ(100UL, bytes);
+  for (size_t i = 0; i < bytes; i++) {
+    ASSERT_EQ(0x37U, dst[i]) << "Failed at byte " << i;
+  }
+}
+
+TEST_F(MemoryRangesTest, read_fail) {
+  std::vector<uint8_t> dst(4096);
+  ASSERT_EQ(0UL, ranges_->Read(1000, dst.data(), dst.size()));
+  ASSERT_EQ(0UL, ranges_->Read(5000, dst.data(), dst.size()));
+  ASSERT_EQ(0UL, ranges_->Read(8000, dst.data(), dst.size()));
+}
+
+TEST_F(MemoryRangesTest, read_across_ranges) {
+  // The MemoryRanges object does not support reading across a range,
+  // so this will only read in the first range.
+  std::vector<uint8_t> dst(4096);
+  size_t bytes = ranges_->Read(6000, dst.data(), dst.size());
+  ASSERT_EQ(1000UL, bytes);
+  for (size_t i = 0; i < bytes; i++) {
+    ASSERT_EQ(0x37U, dst[i]) << "Failed at byte " << i;
+  }
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 90c3fe6..00264c2 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -182,7 +182,7 @@
   RegsX86_64 regs_x86_64;
   RegsMips regs_mips;
   RegsMips64 regs_mips64;
-  MapInfo map_info(0x1000, 0x2000);
+  MapInfo map_info(nullptr, 0x1000, 0x2000);
   Elf* invalid_elf = new Elf(nullptr);
   map_info.elf.reset(invalid_elf);
 
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 2428f68..4369030 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -58,51 +58,54 @@
  protected:
   static void SetUpTestCase() {
     maps_.FakeClear();
-    MapInfo* info = new MapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
+    MapInfo* info =
+        new MapInfo(&maps_, 0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
     ElfFake* elf = new ElfFake(new MemoryFake);
     info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
-    info = new MapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
+    info = new MapInfo(&maps_, 0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
     maps_.FakeAddMapInfo(info);
 
-    info = new MapInfo(0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
+    info = new MapInfo(&maps_, 0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
                        "/dev/fake_device");
     maps_.FakeAddMapInfo(info);
 
-    info = new MapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so");
+    info = new MapInfo(&maps_, 0x20000, 0x22000, 0, PROT_READ | PROT_WRITE,
+                       "/system/fake/libunwind.so");
     elf = new ElfFake(new MemoryFake);
     info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
-    info = new MapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
+    info = new MapInfo(&maps_, 0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
     elf = new ElfFake(new MemoryFake);
     info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
-    info = new MapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
+    info = new MapInfo(&maps_, 0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
     elf = new ElfFake(new MemoryFake);
     info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
-    info = new MapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
+    info = new MapInfo(&maps_, 0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
     elf = new ElfFake(new MemoryFake);
     info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
-    info = new MapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
+    info = new MapInfo(&maps_, 0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
     maps_.FakeAddMapInfo(info);
 
-    info = new MapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
+    info = new MapInfo(&maps_, 0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                       "/fake/fake.vdex");
     info->load_bias = 0;
     maps_.FakeAddMapInfo(info);
 
-    info = new MapInfo(0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+    info = new MapInfo(&maps_, 0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
                        "/fake/fake_load_bias.so");
     elf = new ElfFake(new MemoryFake);
     info->elf.reset(elf);
@@ -110,7 +113,7 @@
     elf->FakeSetLoadBias(0x5000);
     maps_.FakeAddMapInfo(info);
 
-    info = new MapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+    info = new MapInfo(&maps_, 0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
                        "/fake/fake_offset.oat");
     elf = new ElfFake(new MemoryFake);
     info->elf.reset(elf);
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 583c6b9..5feb2aa 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -62,11 +62,17 @@
 }
 
 // Move Constructor.
-FileMap::FileMap(FileMap&& other)
-    : mFileName(other.mFileName), mBasePtr(other.mBasePtr), mBaseLength(other.mBaseLength),
-      mDataOffset(other.mDataOffset), mDataPtr(other.mDataPtr), mDataLength(other.mDataLength)
+FileMap::FileMap(FileMap&& other) noexcept
+    : mFileName(other.mFileName),
+      mBasePtr(other.mBasePtr),
+      mBaseLength(other.mBaseLength),
+      mDataOffset(other.mDataOffset),
+      mDataPtr(other.mDataPtr),
+      mDataLength(other.mDataLength)
 #if defined(__MINGW32__)
-      , mFileHandle(other.mFileHandle), mFileMapping(other.mFileMapping)
+      ,
+      mFileHandle(other.mFileHandle),
+      mFileMapping(other.mFileMapping)
 #endif
 {
     other.mFileName = nullptr;
@@ -79,7 +85,7 @@
 }
 
 // Move assign operator.
-FileMap& FileMap::operator=(FileMap&& other) {
+FileMap& FileMap::operator=(FileMap&& other) noexcept {
     mFileName = other.mFileName;
     mBasePtr = other.mBasePtr;
     mBaseLength = other.mBaseLength;
diff --git a/libutils/include/utils/FileMap.h b/libutils/include/utils/FileMap.h
index 8d402a3..f9f8f3c 100644
--- a/libutils/include/utils/FileMap.h
+++ b/libutils/include/utils/FileMap.h
@@ -52,8 +52,8 @@
 public:
     FileMap(void);
 
-    FileMap(FileMap&& f);
-    FileMap& operator=(FileMap&& f);
+    FileMap(FileMap&& f) noexcept;
+    FileMap& operator=(FileMap&& f) noexcept;
 
     /*
      * Create a new mapping on an open file.
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 3abce17..1571129 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -56,7 +56,7 @@
 
     sp(T* other);  // NOLINT(implicit)
     sp(const sp<T>& other);
-    sp(sp<T>&& other);
+    sp(sp<T>&& other) noexcept;
     template<typename U> sp(U* other);  // NOLINT(implicit)
     template<typename U> sp(const sp<U>& other);  // NOLINT(implicit)
     template<typename U> sp(sp<U>&& other);  // NOLINT(implicit)
@@ -67,7 +67,7 @@
 
     sp& operator = (T* other);
     sp& operator = (const sp<T>& other);
-    sp& operator = (sp<T>&& other);
+    sp& operator=(sp<T>&& other) noexcept;
 
     template<typename U> sp& operator = (const sp<U>& other);
     template<typename U> sp& operator = (sp<U>&& other);
@@ -125,9 +125,8 @@
         m_ptr->incStrong(this);
 }
 
-template<typename T>
-sp<T>::sp(sp<T>&& other)
-        : m_ptr(other.m_ptr) {
+template <typename T>
+sp<T>::sp(sp<T>&& other) noexcept : m_ptr(other.m_ptr) {
     other.m_ptr = nullptr;
 }
 
@@ -169,8 +168,8 @@
     return *this;
 }
 
-template<typename T>
-sp<T>& sp<T>::operator =(sp<T>&& other) {
+template <typename T>
+sp<T>& sp<T>::operator=(sp<T>&& other) noexcept {
     T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
     if (oldPtr) oldPtr->decStrong(this);
     if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
diff --git a/libziparchive/include/ziparchive/zip_writer.h b/libziparchive/include/ziparchive/zip_writer.h
index c350a27..0e0caf1 100644
--- a/libziparchive/include/ziparchive/zip_writer.h
+++ b/libziparchive/include/ziparchive/zip_writer.h
@@ -91,10 +91,10 @@
   explicit ZipWriter(FILE* f);
 
   // Move constructor.
-  ZipWriter(ZipWriter&& zipWriter);
+  ZipWriter(ZipWriter&& zipWriter) noexcept;
 
   // Move assignment.
-  ZipWriter& operator=(ZipWriter&& zipWriter);
+  ZipWriter& operator=(ZipWriter&& zipWriter) noexcept;
 
   /**
    * Starts a new zip entry with the given path and flags.
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index f8d1356..6a3db6b 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -903,7 +903,7 @@
     return FileWriter(fd, declared_length);
   }
 
-  FileWriter(FileWriter&& other)
+  FileWriter(FileWriter&& other) noexcept
       : fd_(other.fd_),
         declared_length_(other.declared_length_),
         total_bytes_written_(other.total_bytes_written_) {
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index 6ad3366..ed1d135 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -97,7 +97,7 @@
   }
 }
 
-ZipWriter::ZipWriter(ZipWriter&& writer)
+ZipWriter::ZipWriter(ZipWriter&& writer) noexcept
     : file_(writer.file_),
       seekable_(writer.seekable_),
       current_offset_(writer.current_offset_),
@@ -109,7 +109,7 @@
   writer.state_ = State::kError;
 }
 
-ZipWriter& ZipWriter::operator=(ZipWriter&& writer) {
+ZipWriter& ZipWriter::operator=(ZipWriter&& writer) noexcept {
   file_ = writer.file_;
   seekable_ = writer.seekable_;
   current_offset_ = writer.current_offset_;
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index 58c2ba8..6840ed0 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -265,7 +265,7 @@
     }
     content.erase(pos);
     uid_t ret;
-    if (!android::base::ParseInt(content, &ret, uid_t(0))) {
+    if (!android::base::ParseUint(content, &ret, uid_t(0))) {
         return -1;
     }
     return ret;
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index d6b8ab3..469f6dc 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -531,7 +531,7 @@
         name = std::string_view(alloc->c_str(), alloc->size());
     }
 
-    explicit TagNameKey(TagNameKey&& rval)
+    explicit TagNameKey(TagNameKey&& rval) noexcept
         : alloc(rval.alloc), name(rval.name.data(), rval.name.length()) {
         rval.alloc = nullptr;
     }
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index b68dc34..a4c3955 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -77,7 +77,7 @@
 #
 # create some directories (some are mount points) and symlinks
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
-    sbin dev proc sys system data odm oem acct config storage mnt $(BOARD_ROOT_EXTRA_FOLDERS)); \
+    sbin dev proc sys system data odm oem acct config storage mnt apex $(BOARD_ROOT_EXTRA_FOLDERS)); \
     ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
     ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
     ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 2a70a4a..6a6a8f9 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -269,6 +269,12 @@
     # that they can be chown'd to system:system later on boot
     write /sys/class/leds/vibrator/trigger "transient"
 
+    # Setup APEX mount point and its security context
+    mount tmpfs tmpfs /apex nodev noexec nosuid
+    chmod 0755 /apex
+    chown root root /apex
+    restorecon /apex
+
 # Healthd can trigger a full boot from charger mode by signaling this
 # property when the power button is held.
 on property:sys.boot_from_charger_mode=1
@@ -524,6 +530,8 @@
 
     mkdir /data/anr 0775 system system
 
+    mkdir /data/apex 0770 root root
+
     # NFC: create data/nfc for nv storage
     mkdir /data/nfc 0770 nfc nfc
     mkdir /data/nfc/param 0770 nfc nfc
diff --git a/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp b/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
index 0849ee9..98cbcc3 100644
--- a/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
+++ b/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
@@ -112,7 +112,8 @@
             }
         }
     }
-    KmParamSet(KmParamSet&& other) : keymaster_key_param_set_t{other.params, other.length} {
+    KmParamSet(KmParamSet&& other) noexcept
+        : keymaster_key_param_set_t{other.params, other.length} {
         other.length = 0;
         other.params = nullptr;
     }