Merge "init: Create logical partitions via liblp."
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index b2f3a68..ed42d40 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -37,6 +37,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <liblp/reader.h>
 
 #include "fs_mgr_priv.h"
 #include "fs_mgr_priv_dm_ioctl.h"
@@ -137,5 +138,30 @@
     return nullptr;
 }
 
+bool CreateLogicalPartitions(const std::string& block_device) {
+    uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
+    auto metadata = ReadMetadata(block_device.c_str(), slot);
+    if (!metadata) {
+        LOG(ERROR) << "Could not read partition table.";
+        return true;
+    }
+
+    LogicalPartitionTable table;
+    for (const auto& partition : metadata->partitions) {
+        LogicalPartition new_partition;
+        new_partition.name = GetPartitionName(partition);
+        new_partition.attributes = partition.attributes;
+        for (size_t i = 0; i < partition.num_extents; i++) {
+            const auto& extent = metadata->extents[partition.first_extent_index + i];
+            new_partition.extents.emplace_back(new_partition.num_sectors, extent.target_data,
+                                               extent.num_sectors, block_device.c_str());
+            new_partition.num_sectors += extent.num_sectors;
+        }
+        table.partitions.push_back(new_partition);
+    }
+
+    return CreateLogicalPartitions(table);
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
index 7f928e5..9772c4b 100644
--- a/fs_mgr/include/fs_mgr_dm_linear.h
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -92,6 +92,7 @@
 //   /dev/block/dm-<name> where |name| is the partition name.
 //
 bool CreateLogicalPartitions(const LogicalPartitionTable& table);
+bool CreateLogicalPartitions(const std::string& block_device);
 
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index f6262ff..6a2c655 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -256,6 +256,9 @@
 std::string GetPartitionName(const LpMetadataPartition& partition);
 std::string GetPartitionGuid(const LpMetadataPartition& partition);
 
+// Helper to return a slot number for a slot suffix.
+uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
+
 }  // namespace fs_mgr
 }  // namespace android
 #endif
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index 958700b..217d802 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -88,5 +88,17 @@
     return buffer;
 }
 
+uint32_t SlotNumberForSlotSuffix(const std::string& suffix) {
+    if (suffix.empty()) {
+        return 0;
+    }
+    if (suffix.size() != 2 || suffix[0] != '_' || suffix[1] < 'a') {
+        LERROR << __PRETTY_FUNCTION__ << "slot '" << suffix
+               << "' does not have a recognized format.";
+        return 0;
+    }
+    return suffix[1] - 'a';
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index db60ce1..2bc9f3a 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -29,6 +29,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/strings.h>
+#include <liblp/metadata_format.h>
 
 #include "devices.h"
 #include "fs_mgr.h"
@@ -75,6 +76,7 @@
 
     std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
     std::unique_ptr<LogicalPartitionTable> dm_linear_table_;
+    std::string lp_metadata_partition_;
     std::vector<fstab_rec*> mount_fstab_recs_;
     std::set<std::string> required_devices_partition_names_;
     std::unique_ptr<DeviceHandler> device_handler_;
@@ -120,13 +122,17 @@
 }
 
 static inline bool IsDmLinearEnabled() {
-    bool enabled = false;
-    import_kernel_cmdline(
-        false, [&enabled](const std::string& key, const std::string& value, bool in_qemu) {
-            if (key == "androidboot.logical_partitions" && value == "1") {
-                enabled = true;
-            }
-        });
+    static bool checked = false;
+    static bool enabled = false;
+    if (checked) {
+        return enabled;
+    }
+    import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) {
+        if (key == "androidboot.logical_partitions" && value == "1") {
+            enabled = true;
+        }
+    });
+    checked = true;
     return enabled;
 }
 
@@ -163,7 +169,7 @@
 }
 
 bool FirstStageMount::DoFirstStageMount() {
-    if (!dm_linear_table_ && mount_fstab_recs_.empty()) {
+    if (!IsDmLinearEnabled() && mount_fstab_recs_.empty()) {
         // Nothing to mount.
         LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
         return true;
@@ -184,14 +190,18 @@
 
 bool FirstStageMount::GetBackingDmLinearDevices() {
     // Add any additional devices required for dm-linear mappings.
-    if (!dm_linear_table_) {
+    if (!IsDmLinearEnabled()) {
         return true;
     }
 
-    for (const auto& partition : dm_linear_table_->partitions) {
-        for (const auto& extent : partition.extents) {
-            const std::string& partition_name = android::base::Basename(extent.block_device());
-            required_devices_partition_names_.emplace(partition_name);
+    required_devices_partition_names_.emplace(LP_METADATA_PARTITION_NAME);
+
+    if (dm_linear_table_) {
+        for (const auto& partition : dm_linear_table_->partitions) {
+            for (const auto& extent : partition.extents) {
+                const std::string& partition_name = android::base::Basename(extent.block_device());
+                required_devices_partition_names_.emplace(partition_name);
+            }
         }
     }
     return true;
@@ -205,7 +215,7 @@
         return true;
     }
 
-    if (dm_linear_table_ || need_dm_verity_) {
+    if (IsDmLinearEnabled() || need_dm_verity_) {
         const std::string dm_path = "/devices/virtual/misc/device-mapper";
         bool found = false;
         auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
@@ -253,10 +263,21 @@
 }
 
 bool FirstStageMount::CreateLogicalPartitions() {
-    if (!dm_linear_table_) {
+    if (!IsDmLinearEnabled()) {
         return true;
     }
-    return android::fs_mgr::CreateLogicalPartitions(*dm_linear_table_.get());
+
+    if (lp_metadata_partition_.empty()) {
+        LOG(ERROR) << "Could not locate logical partition tables in partition "
+                   << LP_METADATA_PARTITION_NAME;
+        return false;
+    }
+    if (dm_linear_table_) {
+        if (!android::fs_mgr::CreateLogicalPartitions(*dm_linear_table_.get())) {
+            return false;
+        }
+    }
+    return android::fs_mgr::CreateLogicalPartitions(lp_metadata_partition_);
 }
 
 ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const Uevent& uevent) {
@@ -266,6 +287,10 @@
     auto iter = required_devices_partition_names_.find(name);
     if (iter != required_devices_partition_names_.end()) {
         LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
+        if (IsDmLinearEnabled() && name == LP_METADATA_PARTITION_NAME) {
+            std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
+            lp_metadata_partition_ = links[0];
+        }
         required_devices_partition_names_.erase(iter);
         device_handler_->HandleDeviceEvent(uevent);
         if (required_devices_partition_names_.empty()) {