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

Commit 07012f8b authored by David Anderson's avatar David Anderson Committed by android-build-merger
Browse files

Merge "libsnapshot: Do not map snapshots for partitions that were reflashed."

am: f5960a1a

Change-Id: Ibe80264d53d4becfdddc89352747b5faf26f8404
parents f63251c8 f5960a1a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ cc_test {
        "libcutils",
        "libcrypto",
        "libfs_mgr",
        "libgmock",
        "liblp",
        "libsnapshot",
    ],
+1 −0
Original line number Diff line number Diff line
@@ -158,6 +158,7 @@ class SnapshotManager final {
    FRIEND_TEST(SnapshotTest, CreateSnapshot);
    FRIEND_TEST(SnapshotTest, FirstStageMountAfterRollback);
    FRIEND_TEST(SnapshotTest, FirstStageMountAndMerge);
    FRIEND_TEST(SnapshotTest, FlashSuperDuringUpdate);
    FRIEND_TEST(SnapshotTest, MapPartialSnapshot);
    FRIEND_TEST(SnapshotTest, MapSnapshot);
    FRIEND_TEST(SnapshotTest, Merge);
+6 −0
Original line number Diff line number Diff line
@@ -1041,6 +1041,12 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions(const std::string& supe
            continue;
        }

        if (!(partition.attributes & LP_PARTITION_ATTR_UPDATED)) {
            LOG(INFO) << "Detected re-flashing of partition, will skip snapshot: "
                      << partition_name;
            live_snapshots.erase(partition_name);
        }

        CreateLogicalPartitionParams params = {
                .block_device = super_device,
                .metadata = metadata.get(),
+86 −5
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <libdm/dm.h>
#include <libfiemap/image_manager.h>
#include <liblp/builder.h>
#include <liblp/mock_property_fetcher.h>

#include "test_helpers.h"

@@ -43,7 +44,10 @@ using android::dm::DmDeviceState;
using android::fiemap::IImageManager;
using android::fs_mgr::BlockDeviceInfo;
using android::fs_mgr::CreateLogicalPartitionParams;
using android::fs_mgr::DestroyLogicalPartition;
using android::fs_mgr::MetadataBuilder;
using namespace ::testing;
using namespace android::fs_mgr::testing;
using namespace std::chrono_literals;
using namespace std::string_literals;

@@ -67,6 +71,7 @@ class SnapshotTest : public ::testing::Test {

  protected:
    void SetUp() override {
        ResetMockPropertyFetcher();
        InitializeState();
        CleanupTestArtifacts();
        FormatFakeSuper();
@@ -78,6 +83,7 @@ class SnapshotTest : public ::testing::Test {
        lock_ = nullptr;

        CleanupTestArtifacts();
        ResetMockPropertyFetcher();
    }

    void InitializeState() {
@@ -95,7 +101,8 @@ class SnapshotTest : public ::testing::Test {
        // get an accurate list to remove.
        lock_ = nullptr;

        std::vector<std::string> snapshots = {"test-snapshot", "test_partition_b"};
        std::vector<std::string> snapshots = {"test-snapshot", "test_partition_a",
                                              "test_partition_b"};
        for (const auto& snapshot : snapshots) {
            DeleteSnapshotDevice(snapshot);
            DeleteBackingImage(image_manager_, snapshot + "-cow");
@@ -154,11 +161,10 @@ class SnapshotTest : public ::testing::Test {
            return false;
        }

        // Update both slots for convenience.
        // Update the source slot.
        auto metadata = builder->Export();
        if (!metadata) return false;
        if (!UpdatePartitionTable(opener, "super", *metadata.get(), 0) ||
            !UpdatePartitionTable(opener, "super", *metadata.get(), 1)) {
        if (!UpdatePartitionTable(opener, "super", *metadata.get(), 0)) {
            return false;
        }

@@ -174,6 +180,35 @@ class SnapshotTest : public ::testing::Test {
        return CreateLogicalPartition(params, path);
    }

    bool MapUpdatePartitions() {
        TestPartitionOpener opener(fake_super);
        auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1);
        if (!builder) return false;

        auto metadata = builder->Export();
        if (!metadata) return false;

        // Update the destination slot, mark it as updated.
        if (!UpdatePartitionTable(opener, "super", *metadata.get(), 1)) {
            return false;
        }

        for (const auto& partition : metadata->partitions) {
            CreateLogicalPartitionParams params = {
                    .block_device = fake_super,
                    .metadata = metadata.get(),
                    .partition = &partition,
                    .force_writable = true,
                    .timeout_ms = 10s,
            };
            std::string ignore_path;
            if (!CreateLogicalPartition(params, &ignore_path)) {
                return false;
            }
        }
        return true;
    }

    void DeleteSnapshotDevice(const std::string& snapshot) {
        DeleteDevice(snapshot);
        DeleteDevice(snapshot + "-inner");
@@ -370,17 +405,22 @@ TEST_F(SnapshotTest, MergeCannotRemoveCow) {
}

TEST_F(SnapshotTest, FirstStageMountAndMerge) {
    ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.virtual_ab.enabled", _))
            .WillByDefault(Return(true));

    ASSERT_TRUE(AcquireLock());

    static const uint64_t kDeviceSize = 1024 * 1024;

    ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));
    ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
    ASSERT_TRUE(MapUpdatePartitions());
    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b", kDeviceSize, kDeviceSize,
                                   kDeviceSize));

    // Simulate a reboot into the new slot.
    lock_ = nullptr;
    ASSERT_TRUE(sm->FinishedSnapshotWrites());
    ASSERT_TRUE(DestroyLogicalPartition("test_partition_b"));

    auto rebooted = new TestDeviceInfo(fake_super);
    rebooted->set_slot_suffix("_b");
@@ -403,6 +443,47 @@ TEST_F(SnapshotTest, FirstStageMountAndMerge) {
    ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
}

TEST_F(SnapshotTest, FlashSuperDuringUpdate) {
    ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.virtual_ab.enabled", _))
            .WillByDefault(Return(true));

    ASSERT_TRUE(AcquireLock());

    static const uint64_t kDeviceSize = 1024 * 1024;

    ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
    ASSERT_TRUE(MapUpdatePartitions());
    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b", kDeviceSize, kDeviceSize,
                                   kDeviceSize));

    // Simulate a reboot into the new slot.
    lock_ = nullptr;
    ASSERT_TRUE(sm->FinishedSnapshotWrites());
    ASSERT_TRUE(DestroyLogicalPartition("test_partition_b"));

    // Reflash the super partition.
    FormatFakeSuper();
    ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));

    auto rebooted = new TestDeviceInfo(fake_super);
    rebooted->set_slot_suffix("_b");

    auto init = SnapshotManager::NewForFirstStageMount(rebooted);
    ASSERT_NE(init, nullptr);
    ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));

    ASSERT_TRUE(AcquireLock());

    SnapshotManager::SnapshotStatus status;
    ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));

    // We should not get a snapshot device now.
    DeviceMapper::TargetInfo target;
    auto dm_name = init->GetSnapshotDeviceName("test_partition_b", status);
    ASSERT_FALSE(init->IsSnapshotDevice(dm_name, &target));
}

}  // namespace snapshot
}  // namespace android