Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 76cde417 authored by David Anderson's avatar David Anderson
Browse files

liblp: Allow automatic slot suffixing of partition names.

On retrofit devices, an OTA package or super_empty.img won't know which
slot it applies to. This is not an issue on devices shipping with
dynamic partitions, since they ship on the "a" slot.

To work around this, partitions and block devices can be flagged as
"auto-slot-suffixed". This indicates that ReadMetadata should
automatically append a slot suffix before returning the metadata. This
flag is added by MetadataBuilder when requested, and will be enabled via
lpmake separately.

After ReadMetadata has applied slot suffixes, it takes care to remove
the slot-suffix flag. This prevents the suffix from being applied twice,
if for example the metadata is then imported into a MetadataBuilder.

Bug: 116802789
Test: liblp_test gtest
      retrofit device boots

Change-Id: Ic7de06d31253a8d5b8d15c0d936175ca2939f857
parent 71c29a9c
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -150,7 +150,7 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata
    return builder;
}

MetadataBuilder::MetadataBuilder() {
MetadataBuilder::MetadataBuilder() : auto_slot_suffixing_(false) {
    memset(&geometry_, 0, sizeof(geometry_));
    geometry_.magic = LP_METADATA_GEOMETRY_MAGIC;
    geometry_.struct_size = sizeof(geometry_);
@@ -564,7 +564,12 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
    metadata->geometry = geometry_;

    // Assign this early so the extent table can read it.
    metadata->block_devices = block_devices_;
    for (const auto& block_device : block_devices_) {
        metadata->block_devices.emplace_back(block_device);
        if (auto_slot_suffixing_) {
            metadata->block_devices.back().flags |= LP_BLOCK_DEVICE_SLOT_SUFFIXED;
        }
    }

    std::map<std::string, size_t> group_indices;
    for (const auto& group : groups_) {
@@ -600,6 +605,9 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
        part.first_extent_index = static_cast<uint32_t>(metadata->extents.size());
        part.num_extents = static_cast<uint32_t>(partition->extents().size());
        part.attributes = partition->attributes();
        if (auto_slot_suffixing_) {
            part.attributes |= LP_PARTITION_ATTR_SLOT_SUFFIXED;
        }

        auto iter = group_indices.find(partition->group_name());
        if (iter == group_indices.end()) {
@@ -836,5 +844,9 @@ bool MetadataBuilder::ImportPartition(const LpMetadata& metadata,
    return true;
}

void MetadataBuilder::SetAutoSlotSuffixing() {
    auto_slot_suffixing_ = true;
}

}  // namespace fs_mgr
}  // namespace android
+4 −0
Original line number Diff line number Diff line
@@ -223,6 +223,9 @@ class MetadataBuilder {
    // Remove all partitions belonging to a group, then remove the group.
    void RemoveGroupAndPartitions(const std::string& group_name);

    // Set the LP_METADATA_AUTO_SLOT_SUFFIXING flag.
    void SetAutoSlotSuffixing();

    bool GetBlockDeviceInfo(const std::string& partition_name, BlockDeviceInfo* info) const;
    bool UpdateBlockDeviceInfo(const std::string& partition_name, const BlockDeviceInfo& info);

@@ -275,6 +278,7 @@ class MetadataBuilder {
    std::vector<std::unique_ptr<Partition>> partitions_;
    std::vector<std::unique_ptr<PartitionGroup>> groups_;
    std::vector<LpMetadataBlockDevice> block_devices_;
    bool auto_slot_suffixing_;
};

// Read BlockDeviceInfo for a given block device. This always returns false
+1 −0
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ std::vector<std::string> GetBlockDevicePartitionNames(const LpMetadata& metadata

// Slot suffix helpers.
uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
std::string SlotSuffixForSlotNumber(uint32_t slot_number);
std::string GetPartitionSlotSuffix(const std::string& partition_name);

}  // namespace fs_mgr
+25 −3
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ extern "C" {
#define LP_METADATA_HEADER_MAGIC 0x414C5030

/* Current metadata version. */
#define LP_METADATA_MAJOR_VERSION 8
#define LP_METADATA_MAJOR_VERSION 9
#define LP_METADATA_MINOR_VERSION 0

/* Attributes for the LpMetadataPartition::attributes field.
@@ -47,10 +47,19 @@ extern "C" {
 * device mapper, the block device will be created as read-only.
 */
#define LP_PARTITION_ATTR_NONE 0x0
#define LP_PARTITION_ATTR_READONLY 0x1
#define LP_PARTITION_ATTR_READONLY (1 << 0)

/* This flag is only intended to be used with super_empty.img and super.img on
 * retrofit devices. On these devices there are A and B super partitions, and
 * we don't know ahead of time which slot the image will be applied to.
 *
 * If set, the partition name needs a slot suffix applied. The slot suffix is
 * determined by the metadata slot number (0 = _a, 1 = _b).
 */
#define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1)

/* Mask that defines all valid attributes. */
#define LP_PARTITION_ATTRIBUTE_MASK (LP_PARTITION_ATTR_READONLY)
#define LP_PARTITION_ATTRIBUTE_MASK (LP_PARTITION_ATTR_READONLY | LP_PARTITION_ATTR_SLOT_SUFFIXED)

/* Default name of the physical partition that holds logical partition entries.
 * The layout of this partition will look like:
@@ -302,8 +311,21 @@ typedef struct LpMetadataBlockDevice {

    /* 24: Partition name in the GPT. Any unused characters must be 0. */
    char partition_name[36];

    /* 60: Flags (see LP_BLOCK_DEVICE_* flags below). */
    uint32_t flags;
} LpMetadataBlockDevice;

/* This flag is only intended to be used with super_empty.img and super.img on
 * retrofit devices. On these devices there are A and B super partitions, and
 * we don't know ahead of time which slot the image will be applied to.
 *
 * If set, the block device needs a slot suffix applied before being used with
 * IPartitionOpener. The slot suffix is determined by the metadata slot number
 * (0 = _a, 1 = _b).
 */
#define LP_BLOCK_DEVICE_SLOT_SUFFIXED (1 << 0)

#ifdef __cplusplus
} /* extern "C" */
#endif
+25 −1
Original line number Diff line number Diff line
@@ -88,11 +88,14 @@ static bool AddDefaultPartitions(MetadataBuilder* builder) {
}

// Create a temporary disk and flash it with the default partition setup.
static unique_fd CreateFlashedDisk() {
static unique_fd CreateFlashedDisk(bool auto_slot_suffix = false) {
    unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
    if (!builder || !AddDefaultPartitions(builder.get())) {
        return {};
    }
    if (auto_slot_suffix) {
        builder->SetAutoSlotSuffixing();
    }
    unique_fd fd = CreateFakeDisk();
    if (fd < 0) {
        return {};
@@ -608,3 +611,24 @@ TEST(liblp, FlashSparseImage) {
    ASSERT_NE(ReadPrimaryMetadata(fd.get(), geometry, 0), nullptr);
    ASSERT_NE(ReadBackupMetadata(fd.get(), geometry, 0), nullptr);
}

TEST(liblp, AutoSlotSuffixing) {
    auto fd = CreateFlashedDisk(true);
    ASSERT_GE(fd, 0);

    TestPartitionOpener opener({{"super", fd}});

    auto metadata = ReadMetadata(opener, "super", 1);
    ASSERT_NE(metadata, nullptr);
    ASSERT_EQ(metadata->partitions.size(), static_cast<size_t>(1));
    EXPECT_EQ(GetPartitionName(metadata->partitions[0]), "system_b");
    ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
    EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_b");

    metadata = ReadMetadata(opener, "super", 0);
    ASSERT_NE(metadata, nullptr);
    ASSERT_EQ(metadata->partitions.size(), static_cast<size_t>(1));
    EXPECT_EQ(GetPartitionName(metadata->partitions[0]), "system_a");
    ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
    EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_a");
}
Loading