Merge "[GPU Service] Add independent AID for gpu service."
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index 2dcfb53..b72ed16 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -97,8 +97,12 @@
     }
 }
 
+bool dev_is_overlayfs(const std::string& dev) {
+    return (dev == "overlay") || (dev == "overlayfs");
+}
+
 bool make_block_device_writable(const std::string& dev) {
-    if ((dev == "overlay") || (dev == "overlayfs")) return true;
+    if (dev_is_overlayfs(dev)) return true;
     int fd = unix_open(dev.c_str(), O_RDONLY | O_CLOEXEC);
     if (fd == -1) {
         return false;
@@ -161,6 +165,10 @@
         return true;
     }
     bool is_root = strcmp(dir, "/") == 0;
+    if (is_root && dev_is_overlayfs(find_mount("/system", false))) {
+        dir = "/system";
+        is_root = false;
+    }
     std::string dev = find_mount(dir, is_root);
     if (is_root && dev.empty()) {
         // The fstab entry will be /system if the device switched roots during
diff --git a/fastboot/constants.h b/fastboot/constants.h
index 705da33..81f0560 100644
--- a/fastboot/constants.h
+++ b/fastboot/constants.h
@@ -64,3 +64,4 @@
 #define FB_VAR_OFF_MODE_CHARGE_STATE "off-mode-charge"
 #define FB_VAR_BATTERY_VOLTAGE "battery-voltage"
 #define FB_VAR_BATTERY_SOC_OK "battery-soc-ok"
+#define FB_VAR_SUPER_PARTITION_NAME "super-partition-name"
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 11c838a..08744ec 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -99,7 +99,8 @@
             {FB_VAR_OFF_MODE_CHARGE_STATE, {GetOffModeChargeState, nullptr}},
             {FB_VAR_BATTERY_VOLTAGE, {GetBatteryVoltage, nullptr}},
             {FB_VAR_BATTERY_SOC_OK, {GetBatterySoCOk, nullptr}},
-            {FB_VAR_HW_REVISION, {GetHardwareRevision, nullptr}}};
+            {FB_VAR_HW_REVISION, {GetHardwareRevision, nullptr}},
+            {FB_VAR_SUPER_PARTITION_NAME, {GetSuperPartitionName, nullptr}}};
 
     if (args.size() < 2) {
         return device->WriteFail("Missing argument");
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 66b90bf..7c9e1d0 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -148,13 +148,40 @@
     // image.
     std::string slot_suffix = device->GetCurrentSlot();
     uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
-    if (wipe || !ReadMetadata(super_name, slot_number)) {
+    std::unique_ptr<LpMetadata> old_metadata = ReadMetadata(super_name, slot_number);
+    if (wipe || !old_metadata) {
         if (!FlashPartitionTable(super_name, *new_metadata.get())) {
             return device->WriteFail("Unable to flash new partition table");
         }
         return device->WriteOkay("Successfully flashed partition table");
     }
 
+    std::set<std::string> partitions_to_keep;
+    for (const auto& partition : old_metadata->partitions) {
+        // Preserve partitions in the other slot, but not the current slot.
+        std::string partition_name = GetPartitionName(partition);
+        if (!slot_suffix.empty() && GetPartitionSlotSuffix(partition_name) == slot_suffix) {
+            continue;
+        }
+        partitions_to_keep.emplace(partition_name);
+    }
+
+    // Do not preserve the scratch partition.
+    partitions_to_keep.erase("scratch");
+
+    if (!partitions_to_keep.empty()) {
+        std::unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(*new_metadata.get());
+        if (!builder->ImportPartitions(*old_metadata.get(), partitions_to_keep)) {
+            return device->WriteFail(
+                    "Old partitions are not compatible with the new super layout; wipe needed");
+        }
+
+        new_metadata = builder->Export();
+        if (!new_metadata) {
+            return device->WriteFail("Unable to build new partition table; wipe needed");
+        }
+    }
+
     // Write the new table to every metadata slot.
     bool ok = true;
     for (size_t i = 0; i < new_metadata->geometry.metadata_slot_count; i++) {
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
index cbd2856..601af34 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -24,7 +24,9 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <ext4_utils/ext4_utils.h>
+#include <fs_mgr.h>
 #include <healthhalutils/HealthHalUtils.h>
+#include <liblp/liblp.h>
 
 #include "fastboot_device.h"
 #include "flashing.h"
@@ -35,6 +37,7 @@
 using ::android::hardware::fastboot::V1_0::FileSystemType;
 using ::android::hardware::fastboot::V1_0::Result;
 using ::android::hardware::fastboot::V1_0::Status;
+using namespace android::fs_mgr;
 
 constexpr char kFastbootProtocolVersion[] = "0.4";
 
@@ -417,3 +420,10 @@
     *message = android::base::GetProperty("ro.revision", "");
     return true;
 }
+
+bool GetSuperPartitionName(FastbootDevice* device, const std::vector<std::string>& /* args */,
+                           std::string* message) {
+    uint32_t slot_number = SlotNumberForSlotSuffix(device->GetCurrentSlot());
+    *message = fs_mgr_get_super_partition_name(slot_number);
+    return true;
+}
diff --git a/fastboot/device/variables.h b/fastboot/device/variables.h
index 59b71e8..015a4c5 100644
--- a/fastboot/device/variables.h
+++ b/fastboot/device/variables.h
@@ -59,6 +59,8 @@
                        std::string* message);
 bool GetBatterySoCOk(FastbootDevice* device, const std::vector<std::string>& args,
                      std::string* message);
+bool GetSuperPartitionName(FastbootDevice* device, const std::vector<std::string>& args,
+                           std::string* message);
 
 // Helpers for getvar all.
 std::vector<std::vector<std::string>> GetAllPartitionArgsWithSlot(FastbootDevice* device);
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 3c6b1b7..625e047 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1129,25 +1129,6 @@
     return fb->GetVar("is-userspace", &value) == fastboot::SUCCESS && value == "yes";
 }
 
-static bool if_partition_exists(const std::string& partition, const std::string& slot) {
-    std::string has_slot;
-    std::string partition_name = partition;
-
-    if (fb->GetVar("has-slot:" + partition, &has_slot) == fastboot::SUCCESS && has_slot == "yes") {
-        if (slot == "") {
-            std::string current_slot = get_current_slot();
-            if (current_slot == "") {
-                die("Failed to identify current slot");
-            }
-            partition_name += "_" + current_slot;
-        } else {
-            partition_name += "_" + slot;
-        }
-    }
-    std::string partition_size;
-    return fb->GetVar("partition-size:" + partition_name, &partition_size) == fastboot::SUCCESS;
-}
-
 static void reboot_to_userspace_fastboot() {
     fb->RebootTo("fastboot");
 
@@ -1200,6 +1181,15 @@
 void FlashAllTool::Flash() {
     DumpInfo();
     CheckRequirements();
+
+    // Change the slot first, so we boot into the correct recovery image when
+    // using fastbootd.
+    if (slot_override_ == "all") {
+        set_active("a");
+    } else {
+        set_active(slot_override_);
+    }
+
     DetermineSecondarySlot();
     CollectImages();
 
@@ -1223,12 +1213,6 @@
 
     // Flash OS images, resizing logical partitions as needed.
     FlashImages(os_images_);
-
-    if (slot_override_ == "all") {
-        set_active("a");
-    } else {
-        set_active(slot_override_);
-    }
 }
 
 void FlashAllTool::CheckRequirements() {
@@ -1243,7 +1227,7 @@
     if (skip_secondary_) {
         return;
     }
-    if (slot_override_ != "") {
+    if (slot_override_ != "" && slot_override_ != "all") {
         secondary_slot_ = get_other_slot(slot_override_);
     } else {
         secondary_slot_ = get_other_slot();
@@ -1304,10 +1288,6 @@
 }
 
 void FlashAllTool::UpdateSuperPartition() {
-    if (!if_partition_exists("super", "")) {
-        return;
-    }
-
     int fd = source_.OpenFile("super_empty.img");
     if (fd < 0) {
         return;
@@ -1318,9 +1298,14 @@
     if (!is_userspace_fastboot()) {
         die("Failed to boot into userspace; one or more components might be unbootable.");
     }
-    fb->Download("super", fd, get_file_size(fd));
 
-    std::string command = "update-super:super";
+    std::string super_name;
+    if (fb->GetVar("super-partition-name", &super_name) != fastboot::RetCode::SUCCESS) {
+        super_name = "super";
+    }
+    fb->Download(super_name, fd, get_file_size(fd));
+
+    std::string command = "update-super:" + super_name;
     if (wipe_) {
         command += ":wipe";
     }
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index fc3a05c..e89c91c 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -403,10 +403,13 @@
 static bool is_dt_fstab_compatible() {
     std::string dt_value;
     std::string file_name = get_android_dt_dir() + "/fstab/compatible";
-    if (read_dt_file(file_name, &dt_value)) {
-        if (dt_value == "android,fstab") {
-            return true;
-        }
+
+    if (read_dt_file(file_name, &dt_value) && dt_value == "android,fstab") {
+        // If there's no status property or its set to "ok" or "okay", then we use the DT fstab.
+        std::string status_value;
+        std::string status_file_name = get_android_dt_dir() + "/fstab/status";
+        return !read_dt_file(status_file_name, &status_value) || status_value == "ok" ||
+               status_value == "okay";
     }
 
     return false;
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 3cd33b1..4007ad9 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -184,22 +184,26 @@
         if (!builder) {
             return false;
         }
-
-        for (size_t i = 0; i < partition.num_extents; i++) {
-            const LpMetadataExtent& extent = metadata.extents[partition.first_extent_index + i];
-            if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
-                auto copy = std::make_unique<LinearExtent>(extent.num_sectors, extent.target_source,
-                                                           extent.target_data);
-                builder->AddExtent(std::move(copy));
-            } else if (extent.target_type == LP_TARGET_TYPE_ZERO) {
-                auto copy = std::make_unique<ZeroExtent>(extent.num_sectors);
-                builder->AddExtent(std::move(copy));
-            }
-        }
+        ImportExtents(builder, metadata, partition);
     }
     return true;
 }
 
+void MetadataBuilder::ImportExtents(Partition* dest, const LpMetadata& metadata,
+                                    const LpMetadataPartition& source) {
+    for (size_t i = 0; i < source.num_extents; i++) {
+        const LpMetadataExtent& extent = metadata.extents[source.first_extent_index + i];
+        if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
+            auto copy = std::make_unique<LinearExtent>(extent.num_sectors, extent.target_source,
+                                                       extent.target_data);
+            dest->AddExtent(std::move(copy));
+        } else if (extent.target_type == LP_TARGET_TYPE_ZERO) {
+            auto copy = std::make_unique<ZeroExtent>(extent.num_sectors);
+            dest->AddExtent(std::move(copy));
+        }
+    }
+}
+
 static bool VerifyDeviceProperties(const BlockDeviceInfo& device_info) {
     if (device_info.logical_block_size % LP_SECTOR_SIZE != 0) {
         LERROR << "Block device " << device_info.partition_name
@@ -471,13 +475,18 @@
     return free_regions;
 }
 
-bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size) {
+bool MetadataBuilder::ValidatePartitionSizeChange(Partition* partition, uint64_t old_size,
+                                                  uint64_t new_size) {
     PartitionGroup* group = FindGroup(partition->group_name());
     CHECK(group);
 
+    if (new_size <= old_size) {
+        return true;
+    }
+
     // Figure out how much we need to allocate, and whether our group has
     // enough space remaining.
-    uint64_t space_needed = aligned_size - partition->size();
+    uint64_t space_needed = new_size - old_size;
     if (group->maximum_size() > 0) {
         uint64_t group_size = TotalSizeOfGroup(group);
         if (group_size >= group->maximum_size() ||
@@ -488,7 +497,11 @@
             return false;
         }
     }
+    return true;
+}
 
+bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size) {
+    uint64_t space_needed = aligned_size - partition->size();
     uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE;
     DCHECK(sectors_needed * LP_SECTOR_SIZE == space_needed);
 
@@ -704,6 +717,10 @@
     uint64_t aligned_size = AlignTo(requested_size, geometry_.logical_block_size);
     uint64_t old_size = partition->size();
 
+    if (!ValidatePartitionSizeChange(partition, old_size, aligned_size)) {
+        return false;
+    }
+
     if (aligned_size > old_size) {
         if (!GrowPartition(partition, aligned_size)) {
             return false;
@@ -750,5 +767,74 @@
     }
 }
 
+static bool CompareBlockDevices(const LpMetadataBlockDevice& first,
+                                const LpMetadataBlockDevice& second) {
+    // Note: we don't compare alignment, since it's a performance thing and
+    // won't affect whether old extents continue to work.
+    return first.first_logical_sector == second.first_logical_sector && first.size == second.size &&
+           GetBlockDevicePartitionName(first) == GetBlockDevicePartitionName(second);
+}
+
+bool MetadataBuilder::ImportPartitions(const LpMetadata& metadata,
+                                       const std::set<std::string>& partition_names) {
+    // The block device list must be identical. We do not try to be clever and
+    // allow ordering changes or changes that don't affect partitions. This
+    // process is designed to allow the most common flashing scenarios and more
+    // complex ones should require a wipe.
+    if (metadata.block_devices.size() != block_devices_.size()) {
+        LINFO << "Block device tables does not match.";
+        return false;
+    }
+    for (size_t i = 0; i < metadata.block_devices.size(); i++) {
+        const LpMetadataBlockDevice& old_device = metadata.block_devices[i];
+        const LpMetadataBlockDevice& new_device = block_devices_[i];
+        if (!CompareBlockDevices(old_device, new_device)) {
+            LINFO << "Block device tables do not match";
+            return false;
+        }
+    }
+
+    // Import named partitions. Note that we do not attempt to merge group
+    // information here. If the device changed its group names, the old
+    // partitions will fail to merge. The same could happen if the group
+    // allocation sizes change.
+    for (const auto& partition : metadata.partitions) {
+        std::string partition_name = GetPartitionName(partition);
+        if (partition_names.find(partition_name) == partition_names.end()) {
+            continue;
+        }
+        if (!ImportPartition(metadata, partition)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool MetadataBuilder::ImportPartition(const LpMetadata& metadata,
+                                      const LpMetadataPartition& source) {
+    std::string partition_name = GetPartitionName(source);
+    Partition* partition = FindPartition(partition_name);
+    if (!partition) {
+        std::string group_name = GetPartitionGroupName(metadata.groups[source.group_index]);
+        partition = AddPartition(partition_name, group_name, source.attributes);
+        if (!partition) {
+            return false;
+        }
+    }
+    if (partition->size() > 0) {
+        LINFO << "Importing partition table would overwrite non-empty partition: "
+              << partition_name;
+        return false;
+    }
+
+    ImportExtents(partition, metadata, source);
+
+    if (!ValidatePartitionSizeChange(partition, 0, partition->size())) {
+        partition->RemoveExtents();
+        return false;
+    }
+    return true;
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index c27e300..35cab38 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -632,3 +632,64 @@
     EXPECT_EQ(metadata->extents[2].target_data, 1472);
     EXPECT_EQ(metadata->extents[2].target_source, 2);
 }
+
+TEST(liblp, ImportPartitionsOk) {
+    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
+    ASSERT_NE(builder, nullptr);
+
+    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);
+    EXPECT_EQ(builder->ResizePartition(vendor, 32768), true);
+    EXPECT_EQ(builder->ResizePartition(system, 98304), true);
+
+    unique_ptr<LpMetadata> exported = builder->Export();
+    ASSERT_NE(exported, nullptr);
+
+    builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
+    ASSERT_NE(builder, nullptr);
+
+    ASSERT_TRUE(builder->ImportPartitions(*exported.get(), {"vendor"}));
+    EXPECT_NE(builder->FindPartition("vendor"), nullptr);
+    EXPECT_EQ(builder->FindPartition("system"), nullptr);
+
+    unique_ptr<LpMetadata> new_metadata = builder->Export();
+    ASSERT_NE(new_metadata, nullptr);
+
+    ASSERT_EQ(exported->partitions.size(), static_cast<size_t>(2));
+    ASSERT_EQ(GetPartitionName(exported->partitions[1]), "vendor");
+    ASSERT_EQ(new_metadata->partitions.size(), static_cast<size_t>(1));
+    ASSERT_EQ(GetPartitionName(new_metadata->partitions[0]), "vendor");
+
+    const LpMetadataExtent& extent_a =
+            exported->extents[exported->partitions[1].first_extent_index];
+    const LpMetadataExtent& extent_b =
+            new_metadata->extents[new_metadata->partitions[0].first_extent_index];
+    EXPECT_EQ(extent_a.num_sectors, extent_b.num_sectors);
+    EXPECT_EQ(extent_a.target_type, extent_b.target_type);
+    EXPECT_EQ(extent_a.target_data, extent_b.target_data);
+    EXPECT_EQ(extent_a.target_source, extent_b.target_source);
+}
+
+TEST(liblp, ImportPartitionsFail) {
+    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
+    ASSERT_NE(builder, nullptr);
+
+    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);
+    EXPECT_EQ(builder->ResizePartition(vendor, 32768), true);
+    EXPECT_EQ(builder->ResizePartition(system, 98304), true);
+
+    unique_ptr<LpMetadata> exported = builder->Export();
+    ASSERT_NE(exported, nullptr);
+
+    // Different device size.
+    builder = MetadataBuilder::New(1024 * 2048, 1024, 2);
+    ASSERT_NE(builder, nullptr);
+    EXPECT_FALSE(builder->ImportPartitions(*exported.get(), {"system"}));
+}
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index f9de106..d5e3fed 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -22,6 +22,7 @@
 
 #include <map>
 #include <memory>
+#include <set>
 
 #include "liblp.h"
 #include "partition_opener.h"
@@ -225,6 +226,11 @@
     bool GetBlockDeviceInfo(const std::string& partition_name, BlockDeviceInfo* info) const;
     bool UpdateBlockDeviceInfo(const std::string& partition_name, const BlockDeviceInfo& info);
 
+    // Attempt to preserve the named partitions from an older metadata. If this
+    // is not possible (for example, the block device list has changed) then
+    // false is returned.
+    bool ImportPartitions(const LpMetadata& metadata, const std::set<std::string>& partition_names);
+
   private:
     MetadataBuilder();
     MetadataBuilder(const MetadataBuilder&) = delete;
@@ -240,6 +246,10 @@
     uint64_t TotalSizeOfGroup(PartitionGroup* group) const;
     bool UpdateBlockDeviceInfo(size_t index, const BlockDeviceInfo& info);
     bool FindBlockDeviceByName(const std::string& partition_name, uint32_t* index) const;
+    bool ValidatePartitionSizeChange(Partition* partition, uint64_t old_size, uint64_t new_size);
+    void ImportExtents(Partition* dest, const LpMetadata& metadata,
+                       const LpMetadataPartition& source);
+    bool ImportPartition(const LpMetadata& metadata, const LpMetadataPartition& source);
 
     struct Interval {
         uint32_t device_index;
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index a5dac00..8723a7f 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -93,8 +93,9 @@
 // Get the list of block device names required by the given metadata.
 std::vector<std::string> GetBlockDevicePartitionNames(const LpMetadata& metadata);
 
-// Helper to return a slot number for a slot suffix.
+// Slot suffix helpers.
 uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
+std::string GetPartitionSlotSuffix(const std::string& partition_name);
 
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index 199d994..cce90a3 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -97,15 +97,15 @@
 }
 
 uint32_t SlotNumberForSlotSuffix(const std::string& suffix) {
-    if (suffix.empty()) {
+    if (suffix.empty() || suffix == "a" || suffix == "_a") {
         return 0;
-    }
-    if (suffix.size() != 2 || suffix[0] != '_' || suffix[1] < 'a') {
+    } else if (suffix == "b" || suffix == "_b") {
+        return 1;
+    } else {
         LERROR << __PRETTY_FUNCTION__ << "slot '" << suffix
                << "' does not have a recognized format.";
         return 0;
     }
-    return suffix[1] - 'a';
 }
 
 uint64_t GetTotalSuperPartitionSize(const LpMetadata& metadata) {
@@ -124,5 +124,13 @@
     return list;
 }
 
+std::string GetPartitionSlotSuffix(const std::string& partition_name) {
+    if (partition_name.size() <= 2) {
+        return "";
+    }
+    std::string suffix = partition_name.substr(partition_name.size() - 2);
+    return (suffix == "_a" || suffix == "_b") ? suffix : "";
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index bdf6dfd..0fa4590 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -24,10 +24,12 @@
 
 TEST(liblp, SlotNumberForSlotSuffix) {
     EXPECT_EQ(SlotNumberForSlotSuffix(""), 0);
+    EXPECT_EQ(SlotNumberForSlotSuffix("a"), 0);
     EXPECT_EQ(SlotNumberForSlotSuffix("_a"), 0);
+    EXPECT_EQ(SlotNumberForSlotSuffix("b"), 1);
     EXPECT_EQ(SlotNumberForSlotSuffix("_b"), 1);
-    EXPECT_EQ(SlotNumberForSlotSuffix("_c"), 2);
-    EXPECT_EQ(SlotNumberForSlotSuffix("_d"), 3);
+    EXPECT_EQ(SlotNumberForSlotSuffix("_c"), 0);
+    EXPECT_EQ(SlotNumberForSlotSuffix("_d"), 0);
 }
 
 TEST(liblp, GetMetadataOffset) {
@@ -60,3 +62,11 @@
     EXPECT_EQ(AlignTo(32, 32, 30), 62);
     EXPECT_EQ(AlignTo(17, 32, 30), 30);
 }
+
+TEST(liblp, GetPartitionSlotSuffix) {
+    EXPECT_EQ(GetPartitionSlotSuffix("system"), "");
+    EXPECT_EQ(GetPartitionSlotSuffix("_"), "");
+    EXPECT_EQ(GetPartitionSlotSuffix("_a"), "");
+    EXPECT_EQ(GetPartitionSlotSuffix("system_a"), "_a");
+    EXPECT_EQ(GetPartitionSlotSuffix("system_b"), "_b");
+}
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index c740bd4..f4c9b99 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -82,12 +82,8 @@
 
 // Perform sanity checks so we don't accidentally overwrite valid metadata
 // with potentially invalid metadata, or random partition data with metadata.
-static bool ValidateAndSerializeMetadata(int fd, const LpMetadata& metadata, std::string* blob) {
-    uint64_t blockdevice_size;
-    if (!GetDescriptorSize(fd, &blockdevice_size)) {
-        return false;
-    }
-
+static bool ValidateAndSerializeMetadata(const IPartitionOpener& opener, const LpMetadata& metadata,
+                                         std::string* blob) {
     const LpMetadataHeader& header = metadata.header;
     const LpMetadataGeometry& geometry = metadata.geometry;
 
@@ -104,7 +100,7 @@
     // metadata.
     uint64_t reserved_size = LP_METADATA_GEOMETRY_SIZE +
                              uint64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
-    uint64_t total_reserved = reserved_size * 2;
+    uint64_t total_reserved = LP_PARTITION_RESERVED_BYTES + reserved_size * 2;
 
     const LpMetadataBlockDevice* super_device = GetMetadataSuperBlockDevice(metadata);
     if (!super_device) {
@@ -112,15 +108,27 @@
         return false;
     }
 
-    if (total_reserved > blockdevice_size ||
-        total_reserved > super_device->first_logical_sector * LP_SECTOR_SIZE) {
+    if (total_reserved > super_device->first_logical_sector * LP_SECTOR_SIZE) {
         LERROR << "Not enough space to store all logical partition metadata slots.";
         return false;
     }
-    if (blockdevice_size != super_device->size) {
-        LERROR << "Block device size " << blockdevice_size
-               << " does not match metadata requested size " << super_device->size;
-        return false;
+    for (const auto& block_device : metadata.block_devices) {
+        std::string partition_name = GetBlockDevicePartitionName(block_device);
+        if ((block_device.first_logical_sector + 1) * LP_SECTOR_SIZE > block_device.size) {
+            LERROR << "Block device " << partition_name << " has invalid first sector "
+                   << block_device.first_logical_sector << " for size " << block_device.size;
+            return false;
+        }
+        BlockDeviceInfo info;
+        if (!opener.GetInfo(partition_name, &info)) {
+            PERROR << partition_name << ": ioctl";
+            return false;
+        }
+        if (info.size != block_device.size) {
+            LERROR << "Block device " << partition_name << " size mismatch (expected"
+                   << block_device.size << ", got " << info.size << ")";
+            return false;
+        }
     }
 
     // Make sure all partition entries reference valid extents.
@@ -230,7 +238,7 @@
     // basic checks that the geometry and tables are coherent, and will fit
     // on the given block device.
     std::string metadata_blob;
-    if (!ValidateAndSerializeMetadata(fd, metadata, &metadata_blob)) {
+    if (!ValidateAndSerializeMetadata(opener, metadata, &metadata_blob)) {
         return false;
     }
 
@@ -295,7 +303,7 @@
     // basic checks that the geometry and tables are coherent, and will fit
     // on the given block device.
     std::string blob;
-    if (!ValidateAndSerializeMetadata(fd, metadata, &blob)) {
+    if (!ValidateAndSerializeMetadata(opener, metadata, &blob)) {
         return false;
     }
 
@@ -327,7 +335,7 @@
         // synchronize the backup copy. This guarantees that a partial write
         // still leaves one copy intact.
         std::string old_blob;
-        if (!ValidateAndSerializeMetadata(fd, *primary.get(), &old_blob)) {
+        if (!ValidateAndSerializeMetadata(opener, *primary.get(), &old_blob)) {
             LERROR << "Error serializing primary metadata to repair corrupted backup";
             return false;
         }
@@ -339,7 +347,7 @@
         // The backup copy is coherent, and the primary is not. Sync it for
         // safety.
         std::string old_blob;
-        if (!ValidateAndSerializeMetadata(fd, *backup.get(), &old_blob)) {
+        if (!ValidateAndSerializeMetadata(opener, *backup.get(), &old_blob)) {
             LERROR << "Error serializing primary metadata to repair corrupted backup";
             return false;
         }
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 6b908d3..98c0879 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -274,9 +274,8 @@
   echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
   die  "overlay takeover after remount"
 !(adb_sh grep "^overlay " /proc/mounts </dev/null | grep " overlay ro,") &&
-  !(adb_sh grep " rw," /proc/mounts </dev/null |
-  skip_administrative_mounts) ||
-    die "remount overlayfs missed a spot"
+  !(adb_sh grep " rw," /proc/mounts </dev/null | skip_administrative_mounts) ||
+  die "remount overlayfs missed a spot (ro)"
 
 adb_su "sed -n '1,/overlay \\/system/p' /proc/mounts" </dev/null |
   skip_administrative_mounts |
diff --git a/run-as/.clang-format b/run-as/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/run-as/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp
index ac470d4..971b9f4 100644
--- a/run-as/run-as.cpp
+++ b/run-as/run-as.cpp
@@ -144,7 +144,7 @@
   // Some devices can disable running run-as, such as Chrome OS when running in
   // non-developer mode.
   if (android::base::GetBoolProperty("ro.boot.disable_runas", false)) {
-      error(1, 0, "run-as is disabled from the kernel commandline");
+    error(1, 0, "run-as is disabled from the kernel commandline");
   }
 
   char* pkgname = argv[1];