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

Commit 179e6434 authored by David Anderson's avatar David Anderson Committed by Automerger Merge Worker
Browse files

Merge "Add a test for bug 198265278." am: a5df9e5d am: 7ff1912d

Original change: https://android-review.googlesource.com/c/platform/system/core/+/1838238

Change-Id: I4dd01e103d920ca9f472d525c0016ca809cdb15c
parents 230fc209 7ff1912d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -408,6 +408,7 @@ class SnapshotManager final : public ISnapshotManager {
    FRIEND_TEST(SnapshotUpdateTest, FullUpdateFlow);
    FRIEND_TEST(SnapshotUpdateTest, MergeCannotRemoveCow);
    FRIEND_TEST(SnapshotUpdateTest, MergeInRecovery);
    FRIEND_TEST(SnapshotUpdateTest, QueryStatusError);
    FRIEND_TEST(SnapshotUpdateTest, SnapshotStatusFileWithoutCow);
    FRIEND_TEST(SnapshotUpdateTest, SpaceSwapUpdate);
    friend class SnapshotTest;
+44 −0
Original line number Diff line number Diff line
@@ -100,6 +100,9 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
        return IDeviceInfo::OpenImageManager("ota/test");
    }
    android::dm::IDeviceMapper& GetDeviceMapper() override {
        if (dm_) {
            return *dm_;
        }
        return android::dm::DeviceMapper::Instance();
    }

@@ -111,6 +114,8 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
    }
    void set_recovery(bool value) { recovery_ = value; }
    void set_first_stage_init(bool value) { first_stage_init_ = value; }
    void set_dm(android::dm::IDeviceMapper* dm) { dm_ = dm; }

    MergeStatus merge_status() const { return merge_status_; }

  private:
@@ -120,6 +125,45 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
    bool recovery_ = false;
    bool first_stage_init_ = false;
    std::unordered_set<uint32_t> unbootable_slots_;
    android::dm::IDeviceMapper* dm_ = nullptr;
};

class DeviceMapperWrapper : public android::dm::IDeviceMapper {
    using DmDeviceState = android::dm::DmDeviceState;
    using DmTable = android::dm::DmTable;

  public:
    DeviceMapperWrapper() : impl_(android::dm::DeviceMapper::Instance()) {}
    explicit DeviceMapperWrapper(android::dm::IDeviceMapper& impl) : impl_(impl) {}

    virtual bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
                              const std::chrono::milliseconds& timeout_ms) override {
        return impl_.CreateDevice(name, table, path, timeout_ms);
    }
    virtual DmDeviceState GetState(const std::string& name) const override {
        return impl_.GetState(name);
    }
    virtual bool LoadTableAndActivate(const std::string& name, const DmTable& table) {
        return impl_.LoadTableAndActivate(name, table);
    }
    virtual bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) {
        return impl_.GetTableInfo(name, table);
    }
    virtual bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) {
        return impl_.GetTableStatus(name, table);
    }
    virtual bool GetDmDevicePathByName(const std::string& name, std::string* path) {
        return impl_.GetDmDevicePathByName(name, path);
    }
    virtual bool GetDeviceString(const std::string& name, std::string* dev) {
        return impl_.GetDeviceString(name, dev);
    }
    virtual bool DeleteDeviceIfExists(const std::string& name) {
        return impl_.DeleteDeviceIfExists(name);
    }

  private:
    android::dm::IDeviceMapper& impl_;
};

class SnapshotTestPropertyFetcher : public android::fs_mgr::testing::MockPropertyFetcher {
+68 −30
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ namespace snapshot {
using android::base::unique_fd;
using android::dm::DeviceMapper;
using android::dm::DmDeviceState;
using android::dm::IDeviceMapper;
using android::fiemap::FiemapStatus;
using android::fiemap::IImageManager;
using android::fs_mgr::BlockDeviceInfo;
@@ -911,6 +912,11 @@ class SnapshotUpdateTest : public SnapshotTest {
            ASSERT_TRUE(hash.has_value());
            hashes_[name] = *hash;
        }

        // OTA client blindly unmaps all partitions that are possibly mapped.
        for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
            ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
        }
    }
    void TearDown() override {
        RETURN_IF_NON_VIRTUAL_AB();
@@ -925,6 +931,14 @@ class SnapshotUpdateTest : public SnapshotTest {
        MountMetadata();
        for (const auto& suffix : {"_a", "_b"}) {
            test_device->set_slot_suffix(suffix);

            // Cheat our way out of merge failed states.
            if (sm->ProcessUpdateState() == UpdateState::MergeFailed) {
                ASSERT_TRUE(AcquireLock());
                ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::None));
                lock_ = {};
            }

            EXPECT_TRUE(sm->CancelUpdate()) << suffix;
        }
        EXPECT_TRUE(UnmapAll());
@@ -1097,11 +1111,6 @@ class SnapshotUpdateTest : public SnapshotTest {
// Also test UnmapUpdateSnapshot unmaps everything.
// Also test first stage mount and merge after this.
TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
    // OTA client blindly unmaps all partitions that are possibly mapped.
    for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
        ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
    }

    // Grow all partitions. Set |prd| large enough that |sys| and |vnd|'s COWs
    // fit in super, but not |prd|.
    constexpr uint64_t partition_size = 3788_KiB;
@@ -1189,11 +1198,6 @@ TEST_F(SnapshotUpdateTest, DuplicateOps) {
        GTEST_SKIP() << "Compression-only test";
    }

    // OTA client blindly unmaps all partitions that are possibly mapped.
    for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
        ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
    }

    // Execute the update.
    ASSERT_TRUE(sm->BeginUpdate());
    ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
@@ -1239,11 +1243,6 @@ TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) {
        GTEST_SKIP() << "Skipping Virtual A/B Compression test";
    }

    // OTA client blindly unmaps all partitions that are possibly mapped.
    for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
        ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
    }

    auto old_sys_size = GetSize(sys_);
    auto old_prd_size = GetSize(prd_);

@@ -1630,11 +1629,6 @@ TEST_F(SnapshotUpdateTest, MergeCannotRemoveCow) {
    ASSERT_NE(nullptr, metadata);
    ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *metadata.get(), 0));

    // OTA client blindly unmaps all partitions that are possibly mapped.
    for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
        ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
    }

    // Add operations for sys. The whole device is written.
    AddOperation(sys_);

@@ -2074,11 +2068,6 @@ TEST_F(SnapshotUpdateTest, LowSpace) {
}

TEST_F(SnapshotUpdateTest, AddPartition) {
    // OTA client blindly unmaps all partitions that are possibly mapped.
    for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
        ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
    }

    group_->add_partition_names("dlkm");

    auto dlkm = manifest_.add_partitions();
@@ -2249,6 +2238,60 @@ TEST_F(SnapshotUpdateTest, CancelOnTargetSlot) {
    ASSERT_TRUE(sm->BeginUpdate());
}

TEST_F(SnapshotUpdateTest, QueryStatusError) {
    // Grow all partitions. Set |prd| large enough that |sys| and |vnd|'s COWs
    // fit in super, but not |prd|.
    constexpr uint64_t partition_size = 3788_KiB;
    SetSize(sys_, partition_size);

    AddOperationForPartitions({sys_});

    // Execute the update.
    ASSERT_TRUE(sm->BeginUpdate());
    ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
    ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
    ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
    ASSERT_TRUE(UnmapAll());

    class DmStatusFailure final : public DeviceMapperWrapper {
      public:
        bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) override {
            if (!DeviceMapperWrapper::GetTableStatus(name, table)) {
                return false;
            }
            if (name == "sys_b" && !table->empty()) {
                auto& info = table->at(0);
                if (DeviceMapper::GetTargetType(info.spec) == "snapshot-merge") {
                    info.data = "Merge failed";
                }
            }
            return true;
        }
    };
    DmStatusFailure wrapper;

    // After reboot, init does first stage mount.
    auto info = new TestDeviceInfo(fake_super, "_b");
    info->set_dm(&wrapper);

    auto init = NewManagerForFirstStageMount(info);
    ASSERT_NE(init, nullptr);

    ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));

    // Initiate the merge and wait for it to be completed.
    ASSERT_TRUE(init->InitiateMerge());
    ASSERT_EQ(UpdateState::MergeFailed, init->ProcessUpdateState());

    // Simulate a reboot that tries the merge again, with the non-failing dm.
    ASSERT_TRUE(UnmapAll());
    init = NewManagerForFirstStageMount("_b");
    ASSERT_NE(init, nullptr);
    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
    ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
}

class FlashAfterUpdateTest : public SnapshotUpdateTest,
                             public WithParamInterface<std::tuple<uint32_t, bool>> {
  public:
@@ -2265,11 +2308,6 @@ class FlashAfterUpdateTest : public SnapshotUpdateTest,
};

TEST_P(FlashAfterUpdateTest, FlashSlotAfterUpdate) {
    // OTA client blindly unmaps all partitions that are possibly mapped.
    for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
        ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
    }

    // Execute the update.
    ASSERT_TRUE(sm->BeginUpdate());
    ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));