Merge "Add a test for bug 198265278."
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 55f4ed7..a49b026 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -408,6 +408,7 @@
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;
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index 1f57bbc..c3b40dc 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -100,6 +100,9 @@
return IDeviceInfo::OpenImageManager("ota/test");
}
android::dm::IDeviceMapper& GetDeviceMapper() override {
+ if (dm_) {
+ return *dm_;
+ }
return android::dm::DeviceMapper::Instance();
}
@@ -111,6 +114,8 @@
}
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 @@
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 {
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 43c7fe2..d78ba0a 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -56,6 +56,7 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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, 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 @@
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 @@
};
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_));