Merge "Add a test for bug 198265278."
This commit is contained in:
commit
a5df9e5db1
|
@ -408,6 +408,7 @@ class SnapshotManager final : public ISnapshotManager {
|
||||||
FRIEND_TEST(SnapshotUpdateTest, FullUpdateFlow);
|
FRIEND_TEST(SnapshotUpdateTest, FullUpdateFlow);
|
||||||
FRIEND_TEST(SnapshotUpdateTest, MergeCannotRemoveCow);
|
FRIEND_TEST(SnapshotUpdateTest, MergeCannotRemoveCow);
|
||||||
FRIEND_TEST(SnapshotUpdateTest, MergeInRecovery);
|
FRIEND_TEST(SnapshotUpdateTest, MergeInRecovery);
|
||||||
|
FRIEND_TEST(SnapshotUpdateTest, QueryStatusError);
|
||||||
FRIEND_TEST(SnapshotUpdateTest, SnapshotStatusFileWithoutCow);
|
FRIEND_TEST(SnapshotUpdateTest, SnapshotStatusFileWithoutCow);
|
||||||
FRIEND_TEST(SnapshotUpdateTest, SpaceSwapUpdate);
|
FRIEND_TEST(SnapshotUpdateTest, SpaceSwapUpdate);
|
||||||
friend class SnapshotTest;
|
friend class SnapshotTest;
|
||||||
|
|
|
@ -100,6 +100,9 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
|
||||||
return IDeviceInfo::OpenImageManager("ota/test");
|
return IDeviceInfo::OpenImageManager("ota/test");
|
||||||
}
|
}
|
||||||
android::dm::IDeviceMapper& GetDeviceMapper() override {
|
android::dm::IDeviceMapper& GetDeviceMapper() override {
|
||||||
|
if (dm_) {
|
||||||
|
return *dm_;
|
||||||
|
}
|
||||||
return android::dm::DeviceMapper::Instance();
|
return android::dm::DeviceMapper::Instance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +114,8 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
|
||||||
}
|
}
|
||||||
void set_recovery(bool value) { recovery_ = value; }
|
void set_recovery(bool value) { recovery_ = value; }
|
||||||
void set_first_stage_init(bool value) { first_stage_init_ = 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_; }
|
MergeStatus merge_status() const { return merge_status_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -120,6 +125,45 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
|
||||||
bool recovery_ = false;
|
bool recovery_ = false;
|
||||||
bool first_stage_init_ = false;
|
bool first_stage_init_ = false;
|
||||||
std::unordered_set<uint32_t> unbootable_slots_;
|
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 {
|
class SnapshotTestPropertyFetcher : public android::fs_mgr::testing::MockPropertyFetcher {
|
||||||
|
|
|
@ -56,6 +56,7 @@ namespace snapshot {
|
||||||
using android::base::unique_fd;
|
using android::base::unique_fd;
|
||||||
using android::dm::DeviceMapper;
|
using android::dm::DeviceMapper;
|
||||||
using android::dm::DmDeviceState;
|
using android::dm::DmDeviceState;
|
||||||
|
using android::dm::IDeviceMapper;
|
||||||
using android::fiemap::FiemapStatus;
|
using android::fiemap::FiemapStatus;
|
||||||
using android::fiemap::IImageManager;
|
using android::fiemap::IImageManager;
|
||||||
using android::fs_mgr::BlockDeviceInfo;
|
using android::fs_mgr::BlockDeviceInfo;
|
||||||
|
@ -911,6 +912,11 @@ class SnapshotUpdateTest : public SnapshotTest {
|
||||||
ASSERT_TRUE(hash.has_value());
|
ASSERT_TRUE(hash.has_value());
|
||||||
hashes_[name] = *hash;
|
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 {
|
void TearDown() override {
|
||||||
RETURN_IF_NON_VIRTUAL_AB();
|
RETURN_IF_NON_VIRTUAL_AB();
|
||||||
|
@ -925,6 +931,14 @@ class SnapshotUpdateTest : public SnapshotTest {
|
||||||
MountMetadata();
|
MountMetadata();
|
||||||
for (const auto& suffix : {"_a", "_b"}) {
|
for (const auto& suffix : {"_a", "_b"}) {
|
||||||
test_device->set_slot_suffix(suffix);
|
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(sm->CancelUpdate()) << suffix;
|
||||||
}
|
}
|
||||||
EXPECT_TRUE(UnmapAll());
|
EXPECT_TRUE(UnmapAll());
|
||||||
|
@ -1097,11 +1111,6 @@ class SnapshotUpdateTest : public SnapshotTest {
|
||||||
// Also test UnmapUpdateSnapshot unmaps everything.
|
// Also test UnmapUpdateSnapshot unmaps everything.
|
||||||
// Also test first stage mount and merge after this.
|
// Also test first stage mount and merge after this.
|
||||||
TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
|
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
|
// Grow all partitions. Set |prd| large enough that |sys| and |vnd|'s COWs
|
||||||
// fit in super, but not |prd|.
|
// fit in super, but not |prd|.
|
||||||
constexpr uint64_t partition_size = 3788_KiB;
|
constexpr uint64_t partition_size = 3788_KiB;
|
||||||
|
@ -1189,11 +1198,6 @@ TEST_F(SnapshotUpdateTest, DuplicateOps) {
|
||||||
GTEST_SKIP() << "Compression-only test";
|
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.
|
// Execute the update.
|
||||||
ASSERT_TRUE(sm->BeginUpdate());
|
ASSERT_TRUE(sm->BeginUpdate());
|
||||||
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
|
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
|
||||||
|
@ -1239,11 +1243,6 @@ TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) {
|
||||||
GTEST_SKIP() << "Skipping Virtual A/B Compression test";
|
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_sys_size = GetSize(sys_);
|
||||||
auto old_prd_size = GetSize(prd_);
|
auto old_prd_size = GetSize(prd_);
|
||||||
|
|
||||||
|
@ -1630,11 +1629,6 @@ TEST_F(SnapshotUpdateTest, MergeCannotRemoveCow) {
|
||||||
ASSERT_NE(nullptr, metadata);
|
ASSERT_NE(nullptr, metadata);
|
||||||
ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *metadata.get(), 0));
|
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.
|
// Add operations for sys. The whole device is written.
|
||||||
AddOperation(sys_);
|
AddOperation(sys_);
|
||||||
|
|
||||||
|
@ -2074,11 +2068,6 @@ TEST_F(SnapshotUpdateTest, LowSpace) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SnapshotUpdateTest, AddPartition) {
|
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");
|
group_->add_partition_names("dlkm");
|
||||||
|
|
||||||
auto dlkm = manifest_.add_partitions();
|
auto dlkm = manifest_.add_partitions();
|
||||||
|
@ -2249,6 +2238,60 @@ TEST_F(SnapshotUpdateTest, CancelOnTargetSlot) {
|
||||||
ASSERT_TRUE(sm->BeginUpdate());
|
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,
|
class FlashAfterUpdateTest : public SnapshotUpdateTest,
|
||||||
public WithParamInterface<std::tuple<uint32_t, bool>> {
|
public WithParamInterface<std::tuple<uint32_t, bool>> {
|
||||||
public:
|
public:
|
||||||
|
@ -2265,11 +2308,6 @@ class FlashAfterUpdateTest : public SnapshotUpdateTest,
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_P(FlashAfterUpdateTest, FlashSlotAfterUpdate) {
|
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.
|
// Execute the update.
|
||||||
ASSERT_TRUE(sm->BeginUpdate());
|
ASSERT_TRUE(sm->BeginUpdate());
|
||||||
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
|
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
|
||||||
|
|
Loading…
Reference in New Issue