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

Commit 869f2df6 authored by David Anderson's avatar David Anderson Committed by android-build-merger
Browse files

Merge "liblp: Add a helper method for upgrading metadata on retrofit devices."

am: b6ae0e4f

Change-Id: Ifedf943e96bbdadd59727e6cebd36150c4f70980
parents b3ef4f83 b6ae0e4f
Loading
Loading
Loading
Loading
+57 −13
Original line number Diff line number Diff line
@@ -113,18 +113,7 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const IPartitionOpener& op
    if (!metadata) {
        return nullptr;
    }
    std::unique_ptr<MetadataBuilder> builder = New(*metadata.get());
    if (!builder) {
        return nullptr;
    }
    for (size_t i = 0; i < builder->block_devices_.size(); i++) {
        std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]);
        BlockDeviceInfo device_info;
        if (opener.GetInfo(partition_name, &device_info)) {
            builder->UpdateBlockDeviceInfo(i, device_info);
        }
    }
    return builder;
    return New(*metadata.get(), &opener);
}

std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& super_partition,
@@ -142,14 +131,69 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New(
    return builder;
}

std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata) {
std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata,
                                                      const IPartitionOpener* opener) {
    std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder());
    if (!builder->Init(metadata)) {
        return nullptr;
    }
    if (opener) {
        for (size_t i = 0; i < builder->block_devices_.size(); i++) {
            std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]);
            BlockDeviceInfo device_info;
            if (opener->GetInfo(partition_name, &device_info)) {
                builder->UpdateBlockDeviceInfo(i, device_info);
            }
        }
    }
    return builder;
}

std::unique_ptr<MetadataBuilder> MetadataBuilder::NewForUpdate(const IPartitionOpener& opener,
                                                               const std::string& source_partition,
                                                               uint32_t source_slot_number,
                                                               uint32_t target_slot_number) {
    auto metadata = ReadMetadata(opener, source_partition, source_slot_number);
    if (!metadata) {
        return nullptr;
    }

    // Get the list of devices we already have.
    std::set<std::string> block_devices;
    for (const auto& block_device : metadata->block_devices) {
        block_devices.emplace(GetBlockDevicePartitionName(block_device));
    }

    auto new_block_devices = metadata->block_devices;

    // Add missing block devices.
    std::string source_slot_suffix = SlotSuffixForSlotNumber(source_slot_number);
    std::string target_slot_suffix = SlotSuffixForSlotNumber(target_slot_number);
    for (const auto& block_device : metadata->block_devices) {
        std::string partition_name = GetBlockDevicePartitionName(block_device);
        std::string slot_suffix = GetPartitionSlotSuffix(partition_name);
        if (slot_suffix.empty() || slot_suffix != source_slot_suffix) {
            continue;
        }
        std::string new_name =
                partition_name.substr(0, partition_name.size() - slot_suffix.size()) +
                target_slot_suffix;
        if (block_devices.find(new_name) != block_devices.end()) {
            continue;
        }

        auto new_device = block_device;
        if (!UpdateBlockDevicePartitionName(&new_device, new_name)) {
            LERROR << "Partition name too long: " << new_name;
            return nullptr;
        }
        new_block_devices.emplace_back(new_device);
    }

    metadata->block_devices = new_block_devices;
    return New(*metadata.get(), &opener);
}

MetadataBuilder::MetadataBuilder() : auto_slot_suffixing_(false) {
    memset(&geometry_, 0, sizeof(geometry_));
    geometry_.magic = LP_METADATA_GEOMETRY_MAGIC;
+16 −2
Original line number Diff line number Diff line
@@ -150,10 +150,24 @@ class MetadataBuilder {
    static std::unique_ptr<MetadataBuilder> New(const std::string& super_partition,
                                                uint32_t slot_number);

    // This is when performing an A/B update. The source partition must be a
    // super partition. On a normal device, the metadata for the source slot
    // is imported and the target slot is ignored. On a retrofit device, the
    // metadata may not have the target slot's devices listed yet, in which
    // case, it is automatically upgraded to include all available block
    // devices.
    static std::unique_ptr<MetadataBuilder> NewForUpdate(const IPartitionOpener& opener,
                                                         const std::string& source_partition,
                                                         uint32_t source_slot_number,
                                                         uint32_t target_slot_number);

    // Import an existing table for modification. If the table is not valid, for
    // example it contains duplicate partition names, then nullptr is returned.
    // This method is for testing or changing off-line tables.
    static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata);
    //
    // If an IPartitionOpener is specified, then block device informatiom will
    // be updated.
    static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata,
                                                const IPartitionOpener* opener = nullptr);

    // Helper function for a single super partition, for tests.
    static std::unique_ptr<MetadataBuilder> New(const BlockDeviceInfo& device_info,
+39 −0
Original line number Diff line number Diff line
@@ -649,3 +649,42 @@ TEST(liblp, AutoSlotSuffixing) {
    ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
    EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_a");
}

TEST(liblp, UpdateRetrofit) {
    unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
    ASSERT_NE(builder, nullptr);
    ASSERT_TRUE(AddDefaultPartitions(builder.get()));
    builder->SetAutoSlotSuffixing();

    auto fd = CreateFakeDisk();
    ASSERT_GE(fd, 0);

    // Note: we bind the same fd to both names, since we want to make sure the
    // exact same bits are getting read back in each test.
    TestPartitionOpener opener({{"super_a", fd}, {"super_b", fd}},
                               {{"super_a", kSuperInfo}, {"super_b", kSuperInfo}});
    auto exported = builder->Export();
    ASSERT_NE(exported, nullptr);
    ASSERT_TRUE(FlashPartitionTable(opener, "super_a", *exported.get()));

    builder = MetadataBuilder::NewForUpdate(opener, "super_a", 0, 1);
    ASSERT_NE(builder, nullptr);
    auto updated = builder->Export();
    ASSERT_NE(updated, nullptr);
    ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(2));
    EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super_a");
    EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[1]), "super_b");
}

TEST(liblp, UpdateNonRetrofit) {
    unique_fd fd = CreateFlashedDisk();
    ASSERT_GE(fd, 0);

    DefaultPartitionOpener opener(fd);
    auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1);
    ASSERT_NE(builder, nullptr);
    auto updated = builder->Export();
    ASSERT_NE(updated, nullptr);
    ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(1));
    EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super");
}
+1 −3
Original line number Diff line number Diff line
@@ -369,12 +369,10 @@ bool AdjustMetadataForSlot(LpMetadata* metadata, uint32_t slot_number) {
            continue;
        }
        std::string partition_name = GetBlockDevicePartitionName(block_device) + slot_suffix;
        if (partition_name.size() > sizeof(block_device.partition_name)) {
        if (!UpdateBlockDevicePartitionName(&block_device, partition_name)) {
            LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name;
            return false;
        }
        strncpy(block_device.partition_name, partition_name.c_str(),
                sizeof(block_device.partition_name));
        block_device.flags &= ~LP_BLOCK_DEVICE_SLOT_SUFFIXED;
    }
    return true;
+8 −0
Original line number Diff line number Diff line
@@ -137,5 +137,13 @@ std::string SlotSuffixForSlotNumber(uint32_t slot_number) {
    return (slot_number == 0) ? "_a" : "_b";
}

bool UpdateBlockDevicePartitionName(LpMetadataBlockDevice* device, const std::string& name) {
    if (name.size() > sizeof(device->partition_name)) {
        return false;
    }
    strncpy(device->partition_name, name.c_str(), sizeof(device->partition_name));
    return true;
}

}  // namespace fs_mgr
}  // namespace android
Loading