Merge "Revert "Make native metrics logger write to statsd socket""
diff --git a/adb/Android.bp b/adb/Android.bp
index 2a88de5..9f16c40 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -41,7 +41,10 @@
 
     target: {
         android: {
-            cflags: ["-DADB_HOST=0"],
+            cflags: [
+                "-DADB_HOST=0",
+                "-Wthread-safety",
+            ],
         },
 
         host: {
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 35017f0..437720e 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -186,6 +186,48 @@
     return line;
 }
 
+std::string dump_header(const amessage* msg) {
+    unsigned command = msg->command;
+    int len = msg->data_length;
+    char cmd[9];
+    char arg0[12], arg1[12];
+    int n;
+
+    for (n = 0; n < 4; n++) {
+        int b = (command >> (n * 8)) & 255;
+        if (b < 32 || b >= 127) break;
+        cmd[n] = (char)b;
+    }
+    if (n == 4) {
+        cmd[4] = 0;
+    } else {
+        // There is some non-ASCII name in the command, so dump the hexadecimal value instead
+        snprintf(cmd, sizeof cmd, "%08x", command);
+    }
+
+    if (msg->arg0 < 256U)
+        snprintf(arg0, sizeof arg0, "%d", msg->arg0);
+    else
+        snprintf(arg0, sizeof arg0, "0x%x", msg->arg0);
+
+    if (msg->arg1 < 256U)
+        snprintf(arg1, sizeof arg1, "%d", msg->arg1);
+    else
+        snprintf(arg1, sizeof arg1, "0x%x", msg->arg1);
+
+    return android::base::StringPrintf("[%s] arg0=%s arg1=%s (len=%d) ", cmd, arg0, arg1, len);
+}
+
+std::string dump_packet(const char* name, const char* func, const apacket* p) {
+    std::string result = name;
+    result += ": ";
+    result += func;
+    result += ": ";
+    result += dump_header(&p->msg);
+    result += dump_hex(p->payload.data(), p->payload.size());
+    return result;
+}
+
 std::string perror_str(const char* msg) {
     return android::base::StringPrintf("%s: %s", msg, strerror(errno));
 }
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index f6ce8e2..ad83302 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -24,6 +24,8 @@
 
 #include <android-base/macros.h>
 
+#include "adb.h"
+
 int syntax_error(const char*, ...) __attribute__((__format__(__printf__, 1, 2)));
 
 void close_stdin();
@@ -42,6 +44,8 @@
 std::string escape_arg(const std::string& s);
 
 std::string dump_hex(const void* ptr, size_t byte_count);
+std::string dump_header(const amessage* msg);
+std::string dump_packet(const char* name, const char* func, const apacket* p);
 
 std::string perror_str(const char* msg);
 
diff --git a/adb/benchmark_device.py b/adb/benchmark_device.py
index 00c2315..e56ef5a 100755
--- a/adb/benchmark_device.py
+++ b/adb/benchmark_device.py
@@ -60,8 +60,6 @@
     if device == None:
         device = adb.get_device()
 
-    lock_max(device)
-
     remote_path = "/dev/null"
     local_path = "/tmp/adb_benchmark_temp"
 
@@ -69,7 +67,7 @@
         f.truncate(file_size_mb * 1024 * 1024)
 
     speeds = list()
-    for _ in range(0, 5):
+    for _ in range(0, 10):
         begin = time.time()
         device.push(local=local_path, remote=remote_path)
         end = time.time()
@@ -81,15 +79,13 @@
     if device == None:
         device = adb.get_device()
 
-    lock_max(device)
-
     remote_path = "/data/local/tmp/adb_benchmark_temp"
     local_path = "/tmp/adb_benchmark_temp"
 
     device.shell(["dd", "if=/dev/zero", "of=" + remote_path, "bs=1m",
                   "count=" + str(file_size_mb)])
     speeds = list()
-    for _ in range(0, 5):
+    for _ in range(0, 10):
         begin = time.time()
         device.pull(remote=remote_path, local=local_path)
         end = time.time()
@@ -101,10 +97,8 @@
     if device == None:
         device = adb.get_device()
 
-    lock_max(device)
-
     speeds = list()
-    for _ in range(0, 5):
+    for _ in range(0, 10):
         begin = time.time()
         device.shell(["dd", "if=/dev/zero", "bs=1m",
                       "count=" + str(file_size_mb)])
@@ -114,7 +108,10 @@
     analyze("shell %dMiB" % file_size_mb, speeds)
 
 def main():
-    benchmark_pull()
+    device = adb.get_device()
+    unlock(device)
+    benchmark_push(device)
+    benchmark_pull(device)
 
 if __name__ == "__main__":
     main()
diff --git a/adb/test_adb.py b/adb/test_adb.py
index 7e73818..430fc3d 100755
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -31,6 +31,7 @@
 import threading
 import time
 import unittest
+import warnings
 
 
 @contextlib.contextmanager
@@ -229,6 +230,10 @@
                                 stderr=subprocess.STDOUT)
 
         try:
+            # We get warnings for unclosed files for the subprocess's pipes,
+            # and it's somewhat cumbersome to close them, so just ignore this.
+            warnings.simplefilter("ignore", ResourceWarning)
+
             # Run the adb client and have it start the adb server.
             proc = subprocess.Popen(["adb", "-P", str(port), "start-server"],
                                     stdin=subprocess.PIPE,
diff --git a/adb/transport.cpp b/adb/transport.cpp
index cabd279..d41f9c8 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -408,42 +408,6 @@
     fd_.reset();
 }
 
-static std::string dump_packet(const char* name, const char* func, apacket* p) {
-    unsigned command = p->msg.command;
-    int len = p->msg.data_length;
-    char cmd[9];
-    char arg0[12], arg1[12];
-    int n;
-
-    for (n = 0; n < 4; n++) {
-        int b = (command >> (n * 8)) & 255;
-        if (b < 32 || b >= 127) break;
-        cmd[n] = (char)b;
-    }
-    if (n == 4) {
-        cmd[4] = 0;
-    } else {
-        /* There is some non-ASCII name in the command, so dump
-            * the hexadecimal value instead */
-        snprintf(cmd, sizeof cmd, "%08x", command);
-    }
-
-    if (p->msg.arg0 < 256U)
-        snprintf(arg0, sizeof arg0, "%d", p->msg.arg0);
-    else
-        snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0);
-
-    if (p->msg.arg1 < 256U)
-        snprintf(arg1, sizeof arg1, "%d", p->msg.arg1);
-    else
-        snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1);
-
-    std::string result = android::base::StringPrintf("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ", name,
-                                                     func, cmd, arg0, arg1, len);
-    result += dump_hex(p->payload.data(), p->payload.size());
-    return result;
-}
-
 void send_packet(apacket* p, atransport* t) {
     p->msg.magic = p->msg.command ^ 0xffffffff;
     // compute a checksum for connection/auth packets for compatibility reasons
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index 6cb4892..7be721a 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -137,7 +137,7 @@
         std::string cmd_name;
         if (android::base::StartsWith(command, "oem ")) {
             args = {command};
-            cmd_name = "oem";
+            cmd_name = FB_CMD_OEM;
         } else {
             args = android::base::Split(command, ":");
             cmd_name = args[0];
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e27a897..6b6e659 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -64,6 +64,7 @@
 #include <ziparchive/zip_archive.h>
 
 #include "bootimg_utils.h"
+#include "constants.h"
 #include "diagnose_usb.h"
 #include "fastboot_driver.h"
 #include "fs.h"
@@ -1697,10 +1698,10 @@
     while (!args.empty()) {
         std::string command = next_arg(&args);
 
-        if (command == "getvar") {
+        if (command == FB_CMD_GETVAR) {
             std::string variable = next_arg(&args);
             DisplayVarOrError(variable, variable);
-        } else if (command == "erase") {
+        } else if (command == FB_CMD_ERASE) {
             std::string partition = next_arg(&args);
             auto erase = [&](const std::string& partition) {
                 std::string partition_type;
@@ -1742,7 +1743,7 @@
             if (data.size() != 256) die("signature must be 256 bytes (got %zu)", data.size());
             fb->Download("signature", data);
             fb->RawCommand("signature", "installing signature");
-        } else if (command == "reboot") {
+        } else if (command == FB_CMD_REBOOT) {
             wants_reboot = true;
 
             if (args.size() == 1) {
@@ -1762,15 +1763,15 @@
 
             }
             if (!args.empty()) syntax_error("junk after reboot command");
-        } else if (command == "reboot-bootloader") {
+        } else if (command == FB_CMD_REBOOT_BOOTLOADER) {
             wants_reboot_bootloader = true;
-        } else if (command == "reboot-recovery") {
+        } else if (command == FB_CMD_REBOOT_RECOVERY) {
             wants_reboot_recovery = true;
-        } else if (command == "reboot-fastboot") {
+        } else if (command == FB_CMD_REBOOT_FASTBOOT) {
             wants_reboot_fastboot = true;
-        } else if (command == "continue") {
+        } else if (command == FB_CMD_CONTINUE) {
             fb->Continue();
-        } else if (command == "boot") {
+        } else if (command == FB_CMD_BOOT) {
             std::string kernel = next_arg(&args);
             std::string ramdisk;
             if (!args.empty()) ramdisk = next_arg(&args);
@@ -1780,7 +1781,7 @@
             auto data = LoadBootableImage(kernel, ramdisk, second_stage);
             fb->Download("boot.img", data);
             fb->Boot();
-        } else if (command == "flash") {
+        } else if (command == FB_CMD_FLASH) {
             std::string pname = next_arg(&args);
 
             std::string fname;
@@ -1827,7 +1828,7 @@
             }
             do_update(filename.c_str(), slot_override, skip_secondary || slot_all);
             wants_reboot = true;
-        } else if (command == "set_active") {
+        } else if (command == FB_CMD_SET_ACTIVE) {
             std::string slot = verify_slot(next_arg(&args), false);
             fb->SetActive(slot);
         } else if (command == "stage") {
@@ -1841,8 +1842,8 @@
         } else if (command == "get_staged") {
             std::string filename = next_arg(&args);
             fb->Upload(filename);
-        } else if (command == "oem") {
-            do_oem_command("oem", &args);
+        } else if (command == FB_CMD_OEM) {
+            do_oem_command(FB_CMD_OEM, &args);
         } else if (command == "flashing") {
             if (args.empty()) {
                 syntax_error("missing 'flashing' command");
@@ -1854,14 +1855,14 @@
             } else {
                 syntax_error("unknown 'flashing' command %s", args[0].c_str());
             }
-        } else if (command == "create-logical-partition") {
+        } else if (command == FB_CMD_CREATE_PARTITION) {
             std::string partition = next_arg(&args);
             std::string size = next_arg(&args);
             fb->CreatePartition(partition, size);
-        } else if (command == "delete-logical-partition") {
+        } else if (command == FB_CMD_DELETE_PARTITION) {
             std::string partition = next_arg(&args);
             fb->DeletePartition(partition);
-        } else if (command == "resize-logical-partition") {
+        } else if (command == FB_CMD_RESIZE_PARTITION) {
             std::string partition = next_arg(&args);
             std::string size = next_arg(&args);
             fb->ResizePartition(partition, size);
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index 62bbe52..af02637 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -37,15 +37,14 @@
 #include <bootimg.h>
 #include <inttypes.h>
 #include <sparse/sparse.h>
+
+#include "constants.h"
 #include "transport.h"
 
 class Transport;
 
 namespace fastboot {
 
-static constexpr int FB_COMMAND_SZ = 64;
-static constexpr int FB_RESPONSE_SZ = 64;
-
 enum RetCode : int {
     SUCCESS = 0,
     BAD_ARG,
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index c02ab1c..479a06a 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -747,7 +747,7 @@
 }
 
 TEST_F(Fuzz, BadCommandTooLarge) {
-    std::string s = RandomString(fastboot::FB_COMMAND_SZ + 1, rand_legal);
+    std::string s = RandomString(FB_COMMAND_SZ + 1, rand_legal);
     EXPECT_EQ(fb->RawCommand(s), DEVICE_FAIL)
             << "Device did not respond with failure after sending length " << s.size()
             << " string of random ASCII chars";
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 4934f5a..6067a7d 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -163,7 +163,7 @@
     auto candidate = fs_mgr_get_overlayfs_candidate(mount_point);
     if (candidate.empty()) return "";
 
-    return "override_creds=off,"s + kLowerdirOption + mount_point + "," + kUpperdirOption +
+    return "override_creds=off," + kLowerdirOption + mount_point + "," + kUpperdirOption +
            candidate + kUpperName + ",workdir=" + candidate + kWorkName;
 }
 
@@ -261,7 +261,7 @@
     return true;
 }
 
-bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr) {
+bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = 0) {
     auto save_errno = errno;
     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
     if (!dir) {
@@ -269,7 +269,11 @@
             errno = save_errno;
             return true;
         }
-        PERROR << "opendir " << path;
+        PERROR << "opendir " << path << " depth=" << level;
+        if ((errno == EPERM) && (level != 0)) {
+            errno = save_errno;
+            return true;
+        }
         return false;
     }
     dirent* entry;
@@ -279,23 +283,25 @@
         auto file = path + "/" + entry->d_name;
         if (entry->d_type == DT_UNKNOWN) {
             struct stat st;
+            save_errno = errno;
             if (!lstat(file.c_str(), &st) && (st.st_mode & S_IFDIR)) entry->d_type = DT_DIR;
+            errno = save_errno;
         }
         if (entry->d_type == DT_DIR) {
-            ret &= fs_mgr_rm_all(file, change);
+            ret &= fs_mgr_rm_all(file, change, level + 1);
             if (!rmdir(file.c_str())) {
                 if (change) *change = true;
             } else {
-                ret = false;
-                PERROR << "rmdir " << file;
+                if (errno != ENOENT) ret = false;
+                PERROR << "rmdir " << file << " depth=" << level;
             }
             continue;
         }
         if (!unlink(file.c_str())) {
             if (change) *change = true;
         } else {
-            ret = false;
-            PERROR << "rm " << file;
+            if (errno != ENOENT) ret = false;
+            PERROR << "rm " << file << " depth=" << level;
         }
     }
     return ret;
@@ -440,10 +446,10 @@
                                    bool* change) {
     const auto top = overlay + kOverlayTopDir;
 
-    if (!fs_mgr_access(top)) return false;
+    if (!fs_mgr_access(top)) return fs_mgr_overlayfs_teardown_scratch(overlay, change);
 
     auto cleanup_all = mount_point.empty();
-    const auto oldpath = top + (cleanup_all ? "" : ("/"s + mount_point));
+    const auto oldpath = top + (cleanup_all ? "" : ("/" + mount_point));
     const auto newpath = oldpath + ".teardown";
     auto ret = fs_mgr_rm_all(newpath);
     auto save_errno = errno;
@@ -583,8 +589,18 @@
     fsrec->fs_type = strdup(mnt_type.c_str());
     fsrec->flags = MS_RELATIME;
     fsrec->fs_options = strdup("");
-    auto mounted = fs_mgr_do_mount_one(fsrec) == 0;
     auto save_errno = errno;
+    auto mounted = fs_mgr_do_mount_one(fsrec) == 0;
+    if (!mounted) {
+        free(fsrec->fs_type);
+        if (mnt_type == "f2fs") {
+            fsrec->fs_type = strdup("ext4");
+        } else {
+            fsrec->fs_type = strdup("f2fs");
+        }
+        mounted = fs_mgr_do_mount_one(fsrec) == 0;
+        if (!mounted) save_errno = errno;
+    }
     setfscreatecon(nullptr);
     if (!mounted) rmdir(kScratchMountPoint.c_str());
     errno = save_errno;
@@ -594,6 +610,7 @@
 const std::string kMkF2fs("/system/bin/make_f2fs");
 const std::string kMkExt4("/system/bin/mke2fs");
 
+// Only a suggestion for _first_ try during mounting
 std::string fs_mgr_overlayfs_scratch_mount_type() {
     if (!access(kMkF2fs.c_str(), X_OK)) return "f2fs";
     if (!access(kMkExt4.c_str(), X_OK)) return "ext4";
@@ -671,7 +688,7 @@
 
     auto ret = system((mnt_type == "f2fs")
                               ? ((kMkF2fs + " -d1 " + scratch_device).c_str())
-                              : ((kMkExt4 + " -b 4096 -t ext4 -m 0 -M "s + kScratchMountPoint +
+                              : ((kMkExt4 + " -b 4096 -t ext4 -m 0 -M " + kScratchMountPoint +
                                   " -O has_journal " + scratch_device)
                                          .c_str()));
     if (ret) {
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 743a3fe..ea78e9b 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -261,46 +261,26 @@
     // we store a backup copy of everything.
     uint64_t reserved =
             LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count);
-    uint64_t total_reserved = reserved * 2;
+    uint64_t total_reserved = LP_PARTITION_RESERVED_BYTES + reserved * 2;
     if (device_info.size < total_reserved) {
         LERROR << "Attempting to create metadata on a block device that is too small.";
         return false;
     }
 
     // Compute the first free sector, factoring in alignment.
-    uint64_t free_area =
+    uint64_t free_area_start =
             AlignTo(total_reserved, device_info.alignment, device_info.alignment_offset);
-    uint64_t first_sector = free_area / LP_SECTOR_SIZE;
+    uint64_t first_sector = free_area_start / LP_SECTOR_SIZE;
 
-    // Compute the last free sector, which is inclusive. We subtract 1 to make
-    // sure that logical partitions won't overlap with the same sector as the
-    // backup metadata, which could happen if the block device was not aligned
-    // to LP_SECTOR_SIZE.
-    uint64_t last_sector = (device_info.size / LP_SECTOR_SIZE) - 1;
-
-    // If this check fails, it means either (1) we did not have free space to
-    // allocate a single sector, or (2) we did, but the alignment was high
-    // enough to bump the first sector out of range. Either way, we cannot
-    // continue.
-    if (first_sector > last_sector) {
-        LERROR << "Not enough space to allocate any partition tables.";
+    // There must be one logical block of free space remaining (enough for one partition).
+    uint64_t minimum_disk_size = (first_sector * LP_SECTOR_SIZE) + device_info.logical_block_size;
+    if (device_info.size < minimum_disk_size) {
+        LERROR << "Device must be at least " << minimum_disk_size << " bytes, only has "
+               << device_info.size;
         return false;
     }
 
-    // Finally, the size of the allocatable space must be a multiple of the
-    // logical block size. If we have no more free space after this
-    // computation, then we abort. Note that the last sector is inclusive,
-    // so we have to account for that.
-    uint64_t num_free_sectors = last_sector - first_sector + 1;
-    uint64_t sectors_per_block = device_info.logical_block_size / LP_SECTOR_SIZE;
-    if (num_free_sectors < sectors_per_block) {
-        LERROR << "Not enough space to allocate any partition tables.";
-        return false;
-    }
-    last_sector = first_sector + (num_free_sectors / sectors_per_block) * sectors_per_block - 1;
-
     geometry_.first_logical_sector = first_sector;
-    geometry_.last_logical_sector = last_sector;
     geometry_.metadata_max_size = metadata_max_size;
     geometry_.metadata_slot_count = metadata_slot_count;
     geometry_.alignment = device_info.alignment;
@@ -452,8 +432,10 @@
     uint64_t last_free_extent_start =
             extents.empty() ? geometry_.first_logical_sector : extents.back().end;
     last_free_extent_start = AlignSector(last_free_extent_start);
-    if (last_free_extent_start <= geometry_.last_logical_sector) {
-        free_regions.emplace_back(last_free_extent_start, geometry_.last_logical_sector + 1);
+
+    uint64_t last_sector = geometry_.block_device_size / LP_SECTOR_SIZE;
+    if (last_free_extent_start < last_sector) {
+        free_regions.emplace_back(last_free_extent_start, last_sector);
     }
 
     const uint64_t sectors_per_block = geometry_.logical_block_size / LP_SECTOR_SIZE;
@@ -523,6 +505,7 @@
         strncpy(out.name, group->name().c_str(), sizeof(out.name));
         out.maximum_size = group->maximum_size();
 
+        group_indices[group->name()] = metadata->groups.size();
         metadata->groups.push_back(out);
     }
 
@@ -546,6 +529,14 @@
         part.num_extents = static_cast<uint32_t>(partition->extents().size());
         part.attributes = partition->attributes();
 
+        auto iter = group_indices.find(partition->group_name());
+        if (iter == group_indices.end()) {
+            LERROR << "Partition " << partition->name() << " is a member of unknown group "
+                   << partition->group_name();
+            return nullptr;
+        }
+        part.group_index = iter->second;
+
         for (const auto& extent : partition->extents()) {
             extent->AddTo(metadata.get());
         }
@@ -559,7 +550,7 @@
 }
 
 uint64_t MetadataBuilder::AllocatableSpace() const {
-    return (geometry_.last_logical_sector - geometry_.first_logical_sector + 1) * LP_SECTOR_SIZE;
+    return geometry_.block_device_size - (geometry_.first_logical_sector * LP_SECTOR_SIZE);
 }
 
 uint64_t MetadataBuilder::UsedSpace() const {
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index ffa7d3b..f5d39a8 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -48,8 +48,11 @@
     LinearExtent* extent = system->extents()[0]->AsLinearExtent();
     ASSERT_NE(extent, nullptr);
     EXPECT_EQ(extent->num_sectors(), 65536 / LP_SECTOR_SIZE);
-    // The first logical sector will be (8192+1024*4)/512 = 12.
-    EXPECT_EQ(extent->physical_sector(), 24);
+    // The first logical sector will be:
+    //      (LP_PARTITION_RESERVED_BYTES + 4096*2 + 1024*4) / 512
+    // Or, in terms of sectors (reserved + geometry + metadata):
+    //      (8 + 16 + 8) = 32
+    EXPECT_EQ(extent->physical_sector(), 32);
 
     // Test resizing to the same size.
     EXPECT_EQ(builder->ResizePartition(system, 65536), true);
@@ -78,7 +81,7 @@
     extent = system->extents()[0]->AsLinearExtent();
     ASSERT_NE(extent, nullptr);
     EXPECT_EQ(extent->num_sectors(), 32768 / LP_SECTOR_SIZE);
-    EXPECT_EQ(extent->physical_sector(), 24);
+    EXPECT_EQ(extent->physical_sector(), 32);
 
     // Test shrinking to 0.
     builder->ResizePartition(system, 0);
@@ -127,7 +130,6 @@
     unique_ptr<LpMetadata> exported = builder->Export();
     ASSERT_NE(exported, nullptr);
     EXPECT_EQ(exported->geometry.first_logical_sector, 1536);
-    EXPECT_EQ(exported->geometry.last_logical_sector, 2047);
 
     // Test a large alignment offset thrown in.
     device_info.alignment_offset = 753664;
@@ -136,7 +138,6 @@
     exported = builder->Export();
     ASSERT_NE(exported, nullptr);
     EXPECT_EQ(exported->geometry.first_logical_sector, 1472);
-    EXPECT_EQ(exported->geometry.last_logical_sector, 2047);
 
     // Alignment offset without alignment doesn't mean anything.
     device_info.alignment = 0;
@@ -150,8 +151,7 @@
     ASSERT_NE(builder, nullptr);
     exported = builder->Export();
     ASSERT_NE(exported, nullptr);
-    EXPECT_EQ(exported->geometry.first_logical_sector, 150);
-    EXPECT_EQ(exported->geometry.last_logical_sector, 2045);
+    EXPECT_EQ(exported->geometry.first_logical_sector, 174);
 
     // Test a small alignment with no alignment offset.
     device_info.alignment = 11 * 1024;
@@ -160,7 +160,6 @@
     exported = builder->Export();
     ASSERT_NE(exported, nullptr);
     EXPECT_EQ(exported->geometry.first_logical_sector, 160);
-    EXPECT_EQ(exported->geometry.last_logical_sector, 2047);
 }
 
 TEST(liblp, InternalPartitionAlignment) {
@@ -206,7 +205,8 @@
     // maximum size of a metadata blob. Then, we double that space since
     // we store a backup copy of everything.
     static constexpr uint64_t geometry = 4 * 1024;
-    static constexpr uint64_t allocatable = total - (metadata * slots + geometry) * 2;
+    static constexpr uint64_t allocatable =
+            total - (metadata * slots + geometry) * 2 - LP_PARTITION_RESERVED_BYTES;
     EXPECT_EQ(builder->AllocatableSpace(), allocatable);
     EXPECT_EQ(builder->UsedSpace(), 0);
 
@@ -247,11 +247,11 @@
     ASSERT_NE(system2, nullptr);
     ASSERT_NE(vendor1, nullptr);
     EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
-    EXPECT_EQ(system1->physical_sector(), 24);
+    EXPECT_EQ(system1->physical_sector(), 32);
     EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
-    EXPECT_EQ(system2->physical_sector(), 216);
+    EXPECT_EQ(system2->physical_sector(), 224);
     EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
-    EXPECT_EQ(vendor1->physical_sector(), 152);
+    EXPECT_EQ(vendor1->physical_sector(), 160);
     EXPECT_EQ(system1->physical_sector() + system1->num_sectors(), vendor1->physical_sector());
     EXPECT_EQ(vendor1->physical_sector() + vendor1->num_sectors(), system2->physical_sector());
 }
@@ -297,8 +297,7 @@
     EXPECT_EQ(geometry.struct_size, sizeof(geometry));
     EXPECT_EQ(geometry.metadata_max_size, 1024);
     EXPECT_EQ(geometry.metadata_slot_count, 2);
-    EXPECT_EQ(geometry.first_logical_sector, 24);
-    EXPECT_EQ(geometry.last_logical_sector, 2047);
+    EXPECT_EQ(geometry.first_logical_sector, 32);
 
     static const size_t kMetadataSpace =
             ((kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE) * 2;
@@ -359,9 +358,9 @@
     LinearExtent* system2 = system->extents()[1]->AsLinearExtent();
     LinearExtent* vendor1 = vendor->extents()[0]->AsLinearExtent();
     EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
-    EXPECT_EQ(system1->physical_sector(), 24);
+    EXPECT_EQ(system1->physical_sector(), 32);
     EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
-    EXPECT_EQ(system2->physical_sector(), 216);
+    EXPECT_EQ(system2->physical_sector(), 224);
     EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
 }
 
@@ -386,7 +385,7 @@
     EXPECT_EQ(builder, nullptr);
 
     // No space to store metadata + geometry + one free sector.
-    device_info.size += LP_METADATA_GEOMETRY_SIZE * 2;
+    device_info.size += LP_PARTITION_RESERVED_BYTES + (LP_METADATA_GEOMETRY_SIZE * 2);
     builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
     EXPECT_EQ(builder, nullptr);
 
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index 8716988..dfa37fe 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -28,12 +28,17 @@
 namespace fs_mgr {
 
 std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
-    LpMetadataGeometry geometry;
-    if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
+    std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
+    if (SeekFile64(fd, 0, SEEK_SET) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << " lseek failed";
         return nullptr;
     }
-    if (SeekFile64(fd, LP_METADATA_GEOMETRY_SIZE, SEEK_SET) < 0) {
-        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << LP_METADATA_GEOMETRY_SIZE;
+    if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) {
+        PERROR << __PRETTY_FUNCTION__ << " read failed";
+        return nullptr;
+    }
+    LpMetadataGeometry geometry;
+    if (!ParseGeometry(buffer.get(), &geometry)) {
         return nullptr;
     }
     return ParseMetadata(geometry, fd);
@@ -59,7 +64,7 @@
 std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
     android::base::unique_fd fd(open(file, O_RDONLY));
     if (fd < 0) {
-        PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
+        PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
         return nullptr;
     }
     return ReadFromImageFile(fd);
@@ -72,7 +77,7 @@
     std::string everything = geometry + metadata;
 
     if (!android::base::WriteFully(fd, everything.data(), everything.size())) {
-        PERROR << __PRETTY_FUNCTION__ << "write " << everything.size() << " bytes failed";
+        PERROR << __PRETTY_FUNCTION__ << " write " << everything.size() << " bytes failed";
         return false;
     }
     return true;
@@ -81,7 +86,7 @@
 bool WriteToImageFile(const char* file, const LpMetadata& input) {
     android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
     if (fd < 0) {
-        PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
+        PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
         return false;
     }
     return WriteToImageFile(fd, input);
@@ -106,6 +111,14 @@
         LERROR << "Metadata max size must be a multiple of the block size, " << block_size;
         return;
     }
+    if (LP_METADATA_GEOMETRY_SIZE % block_size != 0) {
+        LERROR << "Geometry size is not a multiple of the block size, " << block_size;
+        return;
+    }
+    if (LP_PARTITION_RESERVED_BYTES % block_size != 0) {
+        LERROR << "Reserved size is not a multiple of the block size, " << block_size;
+        return;
+    }
 
     uint64_t num_blocks = metadata.geometry.block_device_size % block_size;
     if (num_blocks >= UINT_MAX) {
@@ -163,6 +176,11 @@
 }
 
 bool SparseBuilder::Build() {
+    if (sparse_file_add_fill(file_.get(), 0, LP_PARTITION_RESERVED_BYTES, 0) < 0) {
+        LERROR << "Could not add initial sparse block for reserved zeroes";
+        return false;
+    }
+
     std::string geometry_blob = SerializeGeometry(geometry_);
     std::string metadata_blob = SerializeMetadata(metadata_);
     metadata_blob.resize(geometry_.metadata_max_size);
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index a4ff1a7..89b219c 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 4
+#define LP_METADATA_MAJOR_VERSION 6
 #define LP_METADATA_MINOR_VERSION 0
 
 /* Attributes for the LpMetadataPartition::attributes field.
@@ -72,6 +72,11 @@
 /* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */
 #define LP_SECTOR_SIZE 512
 
+/* Amount of space reserved at the start of every super partition to avoid
+ * creating an accidental boot sector.
+ */
+#define LP_PARTITION_RESERVED_BYTES 4096
+
 /* This structure is stored at block 0 in the first 4096 bytes of the
  * partition, and again in the following block. It is never modified and
  * describes how logical partition information can be located.
@@ -104,12 +109,6 @@
      */
     uint64_t first_logical_sector;
 
-    /* 56: Last usable sector, inclusive, for allocating logical partitions.
-     * At the end of this sector will follow backup metadata slots and the
-     * backup geometry block at the very end.
-     */
-    uint64_t last_logical_sector;
-
     /* 64: Alignment for defining partitions or partition extents. For example,
      * an alignment of 1MiB will require that all partitions have a size evenly
      * divisible by 1MiB, and that the smallest unit the partition can grow by
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 220d651..2aa41f3 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -161,7 +161,6 @@
     EXPECT_EQ(exported->geometry.metadata_max_size, imported->geometry.metadata_max_size);
     EXPECT_EQ(exported->geometry.metadata_slot_count, imported->geometry.metadata_slot_count);
     EXPECT_EQ(exported->geometry.first_logical_sector, imported->geometry.first_logical_sector);
-    EXPECT_EQ(exported->geometry.last_logical_sector, imported->geometry.last_logical_sector);
     EXPECT_EQ(exported->header.major_version, imported->header.major_version);
     EXPECT_EQ(exported->header.minor_version, imported->header.minor_version);
     EXPECT_EQ(exported->header.header_size, imported->header.header_size);
@@ -207,13 +206,14 @@
     ASSERT_EQ(imported->partitions.size(), 1);
     EXPECT_EQ(GetPartitionName(imported->partitions[0]), "vendor");
 
+    uint64_t last_sector = imported->geometry.block_device_size / LP_SECTOR_SIZE;
+
     // Verify that we didn't overwrite anything in the logical paritition area.
     // We expect the disk to be filled with 0xcc on creation so we can read
     // this back and compare it.
     char expected[LP_SECTOR_SIZE];
     memset(expected, 0xcc, sizeof(expected));
-    for (uint64_t i = imported->geometry.first_logical_sector;
-         i <= imported->geometry.last_logical_sector; i++) {
+    for (uint64_t i = imported->geometry.first_logical_sector; i < last_sector; i++) {
         char buffer[LP_SECTOR_SIZE];
         ASSERT_GE(lseek(fd, i * LP_SECTOR_SIZE, SEEK_SET), 0);
         ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
@@ -261,8 +261,6 @@
 
     imported = ReadMetadata(fd, 0);
     ASSERT_NE(imported, nullptr);
-    imported->geometry.last_logical_sector--;
-    ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
 }
 
 // Test that changing one bit of metadata is enough to break the checksum.
@@ -370,9 +368,6 @@
     ASSERT_GE(lseek(fd, exported->geometry.first_logical_sector * LP_SECTOR_SIZE, SEEK_SET), 0);
     ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
     EXPECT_EQ(memcmp(expected, buffer, LP_SECTOR_SIZE), 0);
-    ASSERT_GE(lseek(fd, exported->geometry.last_logical_sector * LP_SECTOR_SIZE, SEEK_SET), 0);
-    ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
-    EXPECT_EQ(memcmp(expected, buffer, LP_SECTOR_SIZE), 0);
 }
 
 // Test that we can read and write image files.
@@ -381,6 +376,7 @@
     ASSERT_NE(builder, nullptr);
     ASSERT_TRUE(AddDefaultPartitions(builder.get()));
     unique_ptr<LpMetadata> exported = builder->Export();
+    ASSERT_NE(exported, nullptr);
 
     unique_fd fd(syscall(__NR_memfd_create, "image_file", 0));
     ASSERT_GE(fd, 0);
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 835df9b..43d8076 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -123,11 +123,11 @@
 bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry) {
     std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
     if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
-        PERROR << __PRETTY_FUNCTION__ << "lseek failed";
+        PERROR << __PRETTY_FUNCTION__ << " lseek failed";
         return false;
     }
     if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) {
-        PERROR << __PRETTY_FUNCTION__ << "read " << LP_METADATA_GEOMETRY_SIZE << " bytes failed";
+        PERROR << __PRETTY_FUNCTION__ << " read " << LP_METADATA_GEOMETRY_SIZE << " bytes failed";
         return false;
     }
     return ParseGeometry(buffer.get(), geometry);
@@ -136,11 +136,11 @@
 bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry) {
     std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
     if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) {
-        PERROR << __PRETTY_FUNCTION__ << "lseek failed, offset " << -LP_METADATA_GEOMETRY_SIZE;
+        PERROR << __PRETTY_FUNCTION__ << " lseek failed";
         return false;
     }
     if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) {
-        PERROR << __PRETTY_FUNCTION__ << "backup read " << LP_METADATA_GEOMETRY_SIZE
+        PERROR << __PRETTY_FUNCTION__ << " backup read " << LP_METADATA_GEOMETRY_SIZE
                << " bytes failed";
         return false;
     }
@@ -223,7 +223,7 @@
     // First read and validate the header.
     std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
     if (!reader->ReadFully(&metadata->header, sizeof(metadata->header))) {
-        PERROR << __PRETTY_FUNCTION__ << "read " << sizeof(metadata->header) << "bytes failed";
+        PERROR << __PRETTY_FUNCTION__ << " read " << sizeof(metadata->header) << "bytes failed";
         return nullptr;
     }
     if (!ValidateMetadataHeader(metadata->header)) {
@@ -241,7 +241,7 @@
         return nullptr;
     }
     if (!reader->ReadFully(buffer.get(), header.tables_size)) {
-        PERROR << __PRETTY_FUNCTION__ << "read " << header.tables_size << "bytes failed";
+        PERROR << __PRETTY_FUNCTION__ << " read " << header.tables_size << "bytes failed";
         return nullptr;
     }
 
@@ -312,7 +312,7 @@
                                                 uint32_t slot_number) {
     int64_t offset = GetPrimaryMetadataOffset(geometry, slot_number);
     if (SeekFile64(fd, offset, SEEK_SET) < 0) {
-        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
+        PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << offset;
         return nullptr;
     }
     return ParseMetadata(geometry, fd);
@@ -322,7 +322,7 @@
                                                uint32_t slot_number) {
     int64_t offset = GetBackupMetadataOffset(geometry, slot_number);
     if (SeekFile64(fd, offset, SEEK_SET) < 0) {
-        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
+        PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << offset;
         return nullptr;
     }
     return ParseMetadata(geometry, fd);
@@ -335,7 +335,7 @@
     }
 
     if (slot_number >= geometry.metadata_slot_count) {
-        LERROR << __PRETTY_FUNCTION__ << "invalid metadata slot number";
+        LERROR << __PRETTY_FUNCTION__ << " invalid metadata slot number";
         return nullptr;
     }
 
@@ -350,7 +350,7 @@
 std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number) {
     android::base::unique_fd fd(open(block_device, O_RDONLY));
     if (fd < 0) {
-        PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+        PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
         return nullptr;
     }
     return ReadMetadata(fd, slot_number);
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index 2f7692f..0556833 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -57,17 +57,18 @@
 }
 
 int64_t GetPrimaryGeometryOffset() {
-    return 0;
+    return LP_PARTITION_RESERVED_BYTES;
 }
 
 int64_t GetBackupGeometryOffset() {
-    return LP_METADATA_GEOMETRY_SIZE;
+    return GetPrimaryGeometryOffset() + LP_METADATA_GEOMETRY_SIZE;
 }
 
 int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
     CHECK(slot_number < geometry.metadata_slot_count);
 
-    int64_t offset = (LP_METADATA_GEOMETRY_SIZE * 2) + geometry.metadata_max_size * slot_number;
+    int64_t offset = LP_PARTITION_RESERVED_BYTES + (LP_METADATA_GEOMETRY_SIZE * 2) +
+                     geometry.metadata_max_size * slot_number;
     CHECK(offset + geometry.metadata_max_size <=
           int64_t(geometry.first_logical_sector * LP_SECTOR_SIZE));
     return offset;
@@ -75,7 +76,7 @@
 
 int64_t GetBackupMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
     CHECK(slot_number < geometry.metadata_slot_count);
-    int64_t start = LP_METADATA_GEOMETRY_SIZE * 2 +
+    int64_t start = LP_PARTITION_RESERVED_BYTES + (LP_METADATA_GEOMETRY_SIZE * 2) +
                     int64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
     return start + int64_t(geometry.metadata_max_size * slot_number);
 }
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index ff50e09..8baf9e7 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -37,18 +37,17 @@
                                    16384,
                                    4,
                                    10000,
-                                   80000,
                                    0,
                                    0,
                                    1024 * 1024,
                                    4096};
-    EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 8192);
-    EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 8192 + 16384);
-    EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 8192 + 16384 * 2);
-    EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 3), 8192 + 16384 * 3);
+    static const uint64_t start = LP_PARTITION_RESERVED_BYTES;
+    EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), start + 8192);
+    EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), start + 8192 + 16384);
+    EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), start + 8192 + 16384 * 2);
+    EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 3), start + 8192 + 16384 * 3);
 
-    static const uint64_t backup_start = 8192 + 16384 * 4;
-
+    static const uint64_t backup_start = start + 8192 + 16384 * 4;
     EXPECT_EQ(GetBackupMetadataOffset(geometry, 3), backup_start + 16384 * 3);
     EXPECT_EQ(GetBackupMetadataOffset(geometry, 2), backup_start + 16384 * 2);
     EXPECT_EQ(GetBackupMetadataOffset(geometry, 1), backup_start + 16384 * 1);
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 0c0cc49..f857d8c 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -43,8 +43,9 @@
 static bool CompareGeometry(const LpMetadataGeometry& g1, const LpMetadataGeometry& g2) {
     return g1.metadata_max_size == g2.metadata_max_size &&
            g1.metadata_slot_count == g2.metadata_slot_count &&
-           g1.first_logical_sector == g2.first_logical_sector &&
-           g1.last_logical_sector == g2.last_logical_sector;
+           g1.block_device_size == g2.block_device_size &&
+           g1.logical_block_size == g2.logical_block_size &&
+           g1.first_logical_sector == g2.first_logical_sector;
 }
 
 std::string SerializeMetadata(const LpMetadata& input) {
@@ -86,15 +87,11 @@
         return false;
     }
 
-    *blob = SerializeMetadata(metadata);
-
     const LpMetadataHeader& header = metadata.header;
     const LpMetadataGeometry& geometry = metadata.geometry;
-    // Validate the usable sector range.
-    if (geometry.first_logical_sector > geometry.last_logical_sector) {
-        LERROR << "Logical partition metadata has invalid sector range.";
-        return false;
-    }
+
+    *blob = SerializeMetadata(metadata);
+
     // Make sure we're writing within the space reserved.
     if (blob->size() > geometry.metadata_max_size) {
         LERROR << "Logical partition metadata is too large. " << blob->size() << " > "
@@ -128,11 +125,12 @@
     }
 
     // Make sure all linear extents have a valid range.
+    uint64_t last_sector = geometry.block_device_size / LP_SECTOR_SIZE;
     for (const auto& extent : metadata.extents) {
         if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
             uint64_t physical_sector = extent.target_data;
             if (physical_sector < geometry.first_logical_sector ||
-                physical_sector + extent.num_sectors > geometry.last_logical_sector) {
+                physical_sector + extent.num_sectors > last_sector) {
                 LERROR << "Extent table entry is out of bounds.";
                 return false;
             }
@@ -146,11 +144,11 @@
                                  const std::function<bool(int, const std::string&)>& writer) {
     int64_t primary_offset = GetPrimaryMetadataOffset(geometry, slot_number);
     if (SeekFile64(fd, primary_offset, SEEK_SET) < 0) {
-        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << primary_offset;
+        PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << primary_offset;
         return false;
     }
     if (!writer(fd, blob)) {
-        PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
+        PERROR << __PRETTY_FUNCTION__ << " write " << blob.size() << " bytes failed";
         return false;
     }
     return true;
@@ -162,16 +160,16 @@
     int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number);
     int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_SET);
     if (abs_offset == (int64_t)-1) {
-        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << backup_offset;
+        PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << backup_offset;
         return false;
     }
     if (abs_offset >= int64_t(geometry.first_logical_sector) * LP_SECTOR_SIZE) {
-        PERROR << __PRETTY_FUNCTION__ << "backup offset " << abs_offset
-               << " is within logical partition bounds, sector " << geometry.last_logical_sector;
+        PERROR << __PRETTY_FUNCTION__ << " backup offset " << abs_offset
+               << " is within logical partition bounds, sector " << geometry.first_logical_sector;
         return false;
     }
     if (!writer(fd, blob)) {
-        PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed";
+        PERROR << __PRETTY_FUNCTION__ << " backup write " << blob.size() << " bytes failed";
         return false;
     }
     return true;
@@ -207,22 +205,33 @@
         return false;
     }
 
-    // Write geometry to the first and last 4096 bytes of the device.
+    // Write zeroes to the first block.
+    std::string zeroes(LP_PARTITION_RESERVED_BYTES, 0);
+    if (SeekFile64(fd, 0, SEEK_SET) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset 0";
+        return false;
+    }
+    if (!android::base::WriteFully(fd, zeroes.data(), zeroes.size())) {
+        PERROR << __PRETTY_FUNCTION__ << " write " << zeroes.size() << " bytes failed";
+        return false;
+    }
+
+    // Write geometry to the primary and backup locations.
     std::string blob = SerializeGeometry(metadata.geometry);
     if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
-        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset 0";
+        PERROR << __PRETTY_FUNCTION__ << " lseek failed: primary geometry";
         return false;
     }
     if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
-        PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
+        PERROR << __PRETTY_FUNCTION__ << " write " << blob.size() << " bytes failed";
         return false;
     }
     if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) {
-        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << -LP_METADATA_GEOMETRY_SIZE;
+        PERROR << __PRETTY_FUNCTION__ << " lseek failed: backup geometry";
         return false;
     }
     if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
-        PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed";
+        PERROR << __PRETTY_FUNCTION__ << " backup write " << blob.size() << " bytes failed";
         return false;
     }
 
@@ -305,7 +314,7 @@
 bool FlashPartitionTable(const std::string& block_device, const LpMetadata& metadata) {
     android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
     if (fd < 0) {
-        PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+        PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
         return false;
     }
     if (!FlashPartitionTable(fd, metadata)) {
@@ -319,7 +328,7 @@
                           uint32_t slot_number) {
     android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
     if (fd < 0) {
-        PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+        PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
         return false;
     }
     if (!UpdatePartitionTable(fd, metadata, slot_number)) {
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 970e05c..14f82c7 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -58,6 +58,7 @@
         "Elf.cpp",
         "ElfInterface.cpp",
         "ElfInterfaceArm.cpp",
+        "Global.cpp",
         "JitDebug.cpp",
         "Log.cpp",
         "MapInfo.cpp",
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
index 17e2526..ac55fee 100644
--- a/libunwindstack/DexFiles.cpp
+++ b/libunwindstack/DexFiles.cpp
@@ -43,10 +43,10 @@
   uint64_t dex_file;
 };
 
-DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : memory_(memory) {}
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : Global(memory) {}
 
 DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
-    : memory_(memory), search_libs_(search_libs) {}
+    : Global(memory, search_libs) {}
 
 DexFiles::~DexFiles() {
   for (auto& entry : files_) {
@@ -117,6 +117,11 @@
   return true;
 }
 
+bool DexFiles::ReadVariableData(uint64_t ptr_offset) {
+  entry_addr_ = (this->*read_entry_ptr_func_)(ptr_offset);
+  return entry_addr_ != 0;
+}
+
 void DexFiles::Init(Maps* maps) {
   if (initialized_) {
     return;
@@ -124,36 +129,7 @@
   initialized_ = true;
   entry_addr_ = 0;
 
-  const std::string dex_debug_name("__dex_debug_descriptor");
-  for (MapInfo* info : *maps) {
-    if (!(info->flags & PROT_READ) || info->offset != 0) {
-      continue;
-    }
-
-    if (!search_libs_.empty()) {
-      bool found = false;
-      const char* lib = basename(info->name.c_str());
-      for (const std::string& name : search_libs_) {
-        if (name == lib) {
-          found = true;
-          break;
-        }
-      }
-      if (!found) {
-        continue;
-      }
-    }
-
-    Elf* elf = info->GetElf(memory_, true);
-    uint64_t ptr;
-    // Find first non-empty list (libart might be loaded multiple times).
-    if (elf->GetGlobalVariable(dex_debug_name, &ptr) && ptr != 0) {
-      entry_addr_ = (this->*read_entry_ptr_func_)(ptr + info->start);
-      if (entry_addr_ != 0) {
-        break;
-      }
-    }
-  }
+  FindAndReadVariable(maps, "__dex_debug_descriptor");
 }
 
 DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
diff --git a/libunwindstack/Global.cpp b/libunwindstack/Global.cpp
new file mode 100644
index 0000000..b449c7e
--- /dev/null
+++ b/libunwindstack/Global.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 <sys/mman.h>
+
+#include <string>
+#include <vector>
+
+#include <unwindstack/Global.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+Global::Global(std::shared_ptr<Memory>& memory) : memory_(memory) {}
+Global::Global(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
+    : memory_(memory), search_libs_(search_libs) {}
+
+uint64_t Global::GetVariableOffset(MapInfo* info, const std::string& variable) {
+  if (!search_libs_.empty()) {
+    bool found = false;
+    const char* lib = basename(info->name.c_str());
+    for (const std::string& name : search_libs_) {
+      if (name == lib) {
+        found = true;
+        break;
+      }
+    }
+    if (!found) {
+      return 0;
+    }
+  }
+
+  Elf* elf = info->GetElf(memory_, true);
+  uint64_t ptr;
+  // Find first non-empty list (libraries might be loaded multiple times).
+  if (elf->GetGlobalVariable(variable, &ptr) && ptr != 0) {
+    return ptr + info->start;
+  }
+  return 0;
+}
+
+void Global::FindAndReadVariable(Maps* maps, const char* var_str) {
+  std::string variable(var_str);
+  // When looking for global variables, do not arbitrarily search every
+  // readable map. Instead look for a specific pattern that must exist.
+  // The pattern should be a readable map, followed by a read-write
+  // map with a non-zero offset.
+  // For example:
+  //   f0000-f1000 0 r-- /system/lib/libc.so
+  //   f1000-f2000 1000 r-x /system/lib/libc.so
+  //   f2000-f3000 2000 rw- /system/lib/libc.so
+  // This also works:
+  //   f0000-f2000 0 r-- /system/lib/libc.so
+  //   f2000-f3000 2000 rw- /system/lib/libc.so
+  MapInfo* map_start = nullptr;
+  for (MapInfo* info : *maps) {
+    if (map_start != nullptr) {
+      if (map_start->name == info->name) {
+        if (info->offset != 0 &&
+            (info->flags & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) {
+          uint64_t ptr = GetVariableOffset(map_start, variable);
+          if (ptr != 0 && ReadVariableData(ptr)) {
+            break;
+          } else {
+            // Failed to find the global variable, do not bother trying again.
+            map_start = nullptr;
+          }
+        }
+      } else {
+        map_start = nullptr;
+      }
+    }
+    if (map_start == nullptr && (info->flags & PROT_READ) && info->offset == 0 &&
+        !info->name.empty()) {
+      map_start = info;
+    }
+  }
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index 821aacf..fe680d7 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -69,10 +69,10 @@
   uint64_t first_entry;
 };
 
-JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : memory_(memory) {}
+JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {}
 
 JitDebug::JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
-    : memory_(memory), search_libs_(search_libs) {}
+    : Global(memory, search_libs) {}
 
 JitDebug::~JitDebug() {
   for (auto* elf : elf_list_) {
@@ -165,6 +165,11 @@
   }
 }
 
+bool JitDebug::ReadVariableData(uint64_t ptr) {
+  entry_addr_ = (this->*read_descriptor_func_)(ptr);
+  return entry_addr_ != 0;
+}
+
 void JitDebug::Init(Maps* maps) {
   if (initialized_) {
     return;
@@ -172,36 +177,7 @@
   // Regardless of what happens below, consider the init finished.
   initialized_ = true;
 
-  const std::string descriptor_name("__jit_debug_descriptor");
-  for (MapInfo* info : *maps) {
-    if (!(info->flags & PROT_READ) || info->offset != 0) {
-      continue;
-    }
-
-    if (!search_libs_.empty()) {
-      bool found = false;
-      const char* lib = basename(info->name.c_str());
-      for (std::string& name : search_libs_) {
-        if (strcmp(name.c_str(), lib) == 0) {
-          found = true;
-          break;
-        }
-      }
-      if (!found) {
-        continue;
-      }
-    }
-
-    Elf* elf = info->GetElf(memory_, true);
-    uint64_t descriptor_addr;
-    // Find first non-empty entry (libart might be loaded multiple times).
-    if (elf->GetGlobalVariable(descriptor_name, &descriptor_addr) && descriptor_addr != 0) {
-      entry_addr_ = (this->*read_descriptor_func_)(descriptor_addr + info->start);
-      if (entry_addr_ != 0) {
-        break;
-      }
-    }
-  }
+  FindAndReadVariable(maps, "__jit_debug_descriptor");
 }
 
 Elf* JitDebug::GetElf(Maps* maps, uint64_t pc) {
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
index 26f5d35..c2fde74 100644
--- a/libunwindstack/include/unwindstack/DexFiles.h
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -25,16 +25,18 @@
 #include <unordered_map>
 #include <vector>
 
+#include <unwindstack/Global.h>
+#include <unwindstack/Memory.h>
+
 namespace unwindstack {
 
 // Forward declarations.
 class DexFile;
 class Maps;
 struct MapInfo;
-class Memory;
 enum ArchEnum : uint8_t;
 
-class DexFiles {
+class DexFiles : public Global {
  public:
   explicit DexFiles(std::shared_ptr<Memory>& memory);
   DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
@@ -60,8 +62,7 @@
 
   bool ReadEntry64();
 
-  std::shared_ptr<Memory> memory_;
-  std::vector<std::string> search_libs_;
+  bool ReadVariableData(uint64_t ptr_offset) override;
 
   std::mutex lock_;
   bool initialized_ = false;
diff --git a/libunwindstack/include/unwindstack/Global.h b/libunwindstack/include/unwindstack/Global.h
new file mode 100644
index 0000000..70e3ddd
--- /dev/null
+++ b/libunwindstack/include/unwindstack/Global.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_GLOBAL_H
+#define _LIBUNWINDSTACK_GLOBAL_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Maps;
+struct MapInfo;
+
+class Global {
+ public:
+  explicit Global(std::shared_ptr<Memory>& memory);
+  Global(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
+  virtual ~Global() = default;
+
+ protected:
+  uint64_t GetVariableOffset(MapInfo* info, const std::string& variable);
+  void FindAndReadVariable(Maps* maps, const char* variable);
+
+  virtual bool ReadVariableData(uint64_t offset) = 0;
+
+  std::shared_ptr<Memory> memory_;
+  std::vector<std::string> search_libs_;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_GLOBAL_H
diff --git a/libunwindstack/include/unwindstack/JitDebug.h b/libunwindstack/include/unwindstack/JitDebug.h
index 0bcd0b0..ccb473f 100644
--- a/libunwindstack/include/unwindstack/JitDebug.h
+++ b/libunwindstack/include/unwindstack/JitDebug.h
@@ -24,15 +24,17 @@
 #include <string>
 #include <vector>
 
+#include <unwindstack/Global.h>
+#include <unwindstack/Memory.h>
+
 namespace unwindstack {
 
 // Forward declarations.
 class Elf;
 class Maps;
-class Memory;
 enum ArchEnum : uint8_t;
 
-class JitDebug {
+class JitDebug : public Global {
  public:
   explicit JitDebug(std::shared_ptr<Memory>& memory);
   JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
@@ -45,11 +47,9 @@
  private:
   void Init(Maps* maps);
 
-  std::shared_ptr<Memory> memory_;
   uint64_t entry_addr_ = 0;
   bool initialized_ = false;
   std::vector<Elf*> elf_list_;
-  std::vector<std::string> search_libs_;
 
   std::mutex lock_;
 
@@ -62,6 +62,8 @@
   uint64_t ReadEntry32Pack(uint64_t* start, uint64_t* size);
   uint64_t ReadEntry32Pad(uint64_t* start, uint64_t* size);
   uint64_t ReadEntry64(uint64_t* start, uint64_t* size);
+
+  bool ReadVariableData(uint64_t ptr_offset) override;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
index c6d7f33..3ac3ca6 100644
--- a/libunwindstack/tests/DexFilesTest.cpp
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -44,15 +44,15 @@
     dex_files_->SetArch(ARCH_ARM);
 
     maps_.reset(
-        new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
-                       "4000-6000 r--s 00000000 00:00 0\n"
-                       "6000-8000 -wxs 00000000 00:00 0\n"
-                       "a000-c000 r--p 00000000 00:00 0\n"
-                       "c000-f000 rw-p 00000000 00:00 0\n"
-                       "f000-11000 r--p 00000000 00:00 0\n"
-                       "100000-110000 rw-p 0000000 00:00 0\n"
-                       "200000-210000 rw-p 0000000 00:00 0\n"
-                       "300000-400000 rw-p 0000000 00:00 0\n"));
+        new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n"
+                       "4000-6000 r--s 00000000 00:00 0 /fake/elf\n"
+                       "6000-8000 -wxs 00000000 00:00 0 /fake/elf\n"
+                       "a000-c000 r--p 00000000 00:00 0 /fake/elf2\n"
+                       "c000-f000 rw-p 00001000 00:00 0 /fake/elf2\n"
+                       "f000-11000 r--p 00000000 00:00 0 /fake/elf3\n"
+                       "100000-110000 rw-p 0001000 00:00 0 /fake/elf3\n"
+                       "200000-210000 rw-p 0002000 00:00 0 /fake/elf3\n"
+                       "300000-400000 rw-p 0003000 00:00 0 /fake/elf3\n"));
     ASSERT_TRUE(maps_->Parse());
 
     // Global variable in a section that is not readable.
@@ -96,8 +96,9 @@
   void WriteDex(uint64_t dex_file);
 
   static constexpr size_t kMapGlobalNonReadable = 2;
-  static constexpr size_t kMapGlobalSetToZero = 4;
+  static constexpr size_t kMapGlobalSetToZero = 3;
   static constexpr size_t kMapGlobal = 5;
+  static constexpr size_t kMapGlobalRw = 6;
   static constexpr size_t kMapDexFileEntries = 7;
   static constexpr size_t kMapDexFiles = 8;
 
@@ -256,6 +257,9 @@
   map_info->name = "/system/lib/libart.so";
   dex_files_.reset(new DexFiles(process_memory_, libs));
   dex_files_->SetArch(ARCH_ARM);
+  // Set the rw map to the same name or this will not scan this entry.
+  map_info = maps_->Get(kMapGlobalRw);
+  map_info->name = "/system/lib/libart.so";
   // Make sure that clearing out copy of the libs doesn't affect the
   // DexFiles object.
   libs.clear();
@@ -271,7 +275,7 @@
   MapInfo* info = maps_->Get(kMapDexFiles);
 
   // First global variable found, but value is zero.
-  WriteDescriptor32(0xc800, 0);
+  WriteDescriptor32(0xa800, 0);
 
   WriteDescriptor32(0xf800, 0x200000);
   WriteEntry32(0x200000, 0, 0, 0x300000);
@@ -286,7 +290,7 @@
   dex_files_->SetArch(ARCH_ARM);
   method_name = "fail";
   method_offset = 0x123;
-  WriteDescriptor32(0xc800, 0x100000);
+  WriteDescriptor32(0xa800, 0x100000);
   dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("fail", method_name);
   EXPECT_EQ(0x123U, method_offset);
@@ -298,7 +302,7 @@
   MapInfo* info = maps_->Get(kMapDexFiles);
 
   // First global variable found, but value is zero.
-  WriteDescriptor64(0xc800, 0);
+  WriteDescriptor64(0xa800, 0);
 
   WriteDescriptor64(0xf800, 0x200000);
   WriteEntry64(0x200000, 0, 0, 0x300000);
@@ -314,7 +318,7 @@
   dex_files_->SetArch(ARCH_ARM64);
   method_name = "fail";
   method_offset = 0x123;
-  WriteDescriptor64(0xc800, 0x100000);
+  WriteDescriptor64(0xa800, 0x100000);
   dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("fail", method_name);
   EXPECT_EQ(0x123U, method_offset);
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index 66f0859..4598526 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -43,15 +43,16 @@
     jit_debug_->SetArch(ARCH_ARM);
 
     maps_.reset(
-        new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
-                       "4000-6000 r--s 00000000 00:00 0\n"
-                       "6000-8000 -wxs 00000000 00:00 0\n"
-                       "a000-c000 --xp 00000000 00:00 0\n"
-                       "c000-f000 rw-p 00000000 00:00 0\n"
-                       "f000-11000 r--p 00000000 00:00 0\n"
-                       "12000-14000 r--p 00000000 00:00 0\n"
-                       "100000-110000 rw-p 0000000 00:00 0\n"
-                       "200000-210000 rw-p 0000000 00:00 0\n"));
+        new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf1\n"
+                       "4000-6000 r--s 00000000 00:00 0 /fake/elf1\n"
+                       "6000-8000 -wxs 00000000 00:00 0 /fake/elf1\n"
+                       "a000-c000 --xp 00000000 00:00 0 /fake/elf2\n"
+                       "c000-f000 rw-p 00001000 00:00 0 /fake/elf2\n"
+                       "f000-11000 r--p 00000000 00:00 0 /fake/elf3\n"
+                       "11000-12000 rw-p 00001000 00:00 0 /fake/elf3\n"
+                       "12000-14000 r--p 00000000 00:00 0 /fake/elf4\n"
+                       "100000-110000 rw-p 0001000 00:00 0 /fake/elf4\n"
+                       "200000-210000 rw-p 0002000 00:00 0 /fake/elf4\n"));
     ASSERT_TRUE(maps_->Parse());
 
     MapInfo* map_info = maps_->Get(3);
@@ -74,7 +75,7 @@
     interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
     map_info->elf.reset(elf);
 
-    map_info = maps_->Get(6);
+    map_info = maps_->Get(7);
     ASSERT_TRUE(map_info != nullptr);
     memory = new MemoryFake;
     elf = new ElfFake(memory);
@@ -397,6 +398,8 @@
   // Change the name of the map that includes the value and verify this works.
   MapInfo* map_info = maps_->Get(5);
   map_info->name = "/system/lib/libart.so";
+  map_info = maps_->Get(6);
+  map_info->name = "/system/lib/libart.so";
   jit_debug_.reset(new JitDebug(process_memory_, libs));
   // Make sure that clearing our copy of the libs doesn't affect the
   // JitDebug object.
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt
index 55aaaf6..5657373 100644
--- a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt
@@ -1,3 +1,4 @@
 d0250000-d2600000 r-xp 0 00:00 0 <anonymous:d0250000>
 e466e000-e4ae8000 r-xp 0 00:00 0 libart.so
+e4ae8000-e4ae9000 rw-p 1000 00:00 0 libart.so
 e7d91000-e7e31000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt b/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
index f25c781..3cd9d40 100644
--- a/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
+++ b/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
@@ -2,7 +2,9 @@
 dfe4e000-dfe7b000 r-xp 0 00:00 0   libarttestd.so
 e0447000-e0448000 r-xp 2000 00:00 0   137-cfi.odex
 e2796000-e4796000 r-xp 0 00:00 0   anonymous:e2796000
-e648e000-e690f000 r-xp 00000000 00:00 0  libart.so
+e648e000-e690f000 r-xp 0 00:00 0  libart.so
+e690f000-e6910000 rw-p 1000 00:00 0  libart.so
 ed306000-ed801000 r-xp 0 00:00 0   libartd.so
+ed801000-ed802000 rw-p 1000 00:00 0   libartd.so
 eda88000-edb23000 r-xp 0 00:00 0   libc.so
 ede4e000-ede50000 r-xp 0 00:00 0   anonymous:ede4e000
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt b/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
index db4f9f7..a8d215c 100644
--- a/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
@@ -3,4 +3,5 @@
 ec606000-ec607000 r-xp 2000 00:00 0   137-cfi.odex
 ee74c000-f074c000 r-xp 0 00:00 0   anonymous:ee74c000
 f6be1000-f732b000 r-xp 0 00:00 0   libartd.so
+f732b000-f732c000 rw-p 1000 00:00 0   libartd.so
 f734b000-f74fc000 r-xp 0 00:00 0   libc.so
diff --git a/libutils/include/utils/Errors.h b/libutils/include/utils/Errors.h
index 7aafe42..1e03677 100644
--- a/libutils/include/utils/Errors.h
+++ b/libutils/include/utils/Errors.h
@@ -14,22 +14,19 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_ERRORS_H
-#define ANDROID_ERRORS_H
+#pragma once
 
-#include <sys/types.h>
 #include <errno.h>
+#include <stdint.h>
+#include <sys/types.h>
 
 namespace android {
 
-// use this type to return error codes
-#ifdef _WIN32
-typedef int         status_t;
-#else
-typedef int32_t     status_t;
-#endif
-
-/* the MS C runtime lacks a few error codes */
+/**
+ * The type used to return success/failure from frameworks APIs.
+ * See the anonymous enum below for valid values.
+ */
+typedef int32_t status_t;
 
 /*
  * Error codes. 
@@ -82,7 +79,3 @@
 #endif
 
 }  // namespace android
-
-// ---------------------------------------------------------------------------
-    
-#endif // ANDROID_ERRORS_H
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e4e1650..393e204 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -124,6 +124,7 @@
 LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/lib64 $(TARGET_ROOT_OUT)/odm/lib64
 LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/overlay $(TARGET_ROOT_OUT)/odm/overlay
 LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/priv-app $(TARGET_ROOT_OUT)/odm/priv-app
+LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/usr $(TARGET_ROOT_OUT)/odm/usr
 
 ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
   LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 21d234f..ea83ef9 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -275,6 +275,13 @@
     chown root root /apex
     restorecon /apex
 
+    # Start logd before any other services run to ensure we capture all of their logs.
+    start logd
+    # Start essential services.
+    start servicemanager
+    start hwservicemanager
+    start vndservicemanager
+
 # 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
@@ -331,11 +338,6 @@
     #     /vendor/build.prop and
     #     /factory/factory.prop
     load_system_props
-    # start essential services
-    start logd
-    start servicemanager
-    start hwservicemanager
-    start vndservicemanager
     start vold
     exec - system system -- /system/bin/vdc checkpoint markBootAttempt