libsnapshot: Place forward merge indicator for wipe
If the device applies a package with FDR, place forward merge indicator
so that on FDR, the snapshots aren't abandoned, and we forward merge
the update.
Test: apply downgrade
Test: apply update with data wipe
Test: vts_libsnapshot_test
Bug: 152094219
Change-Id: Id32aeca380db797cd777321837f146333ae6b33c
(cherry picked from commit 6b0251232ab368b52c67825a5edad568c9afeab7)
Merged-In: Id32aeca380db797cd777321837f146333ae6b33c
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index b14b049..08d17d1 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -142,7 +142,9 @@
// be created, and the device must either cancel the OTA (either before
// rebooting or after rolling back), or merge the OTA.
// Before calling this function, all snapshots must be mapped.
- bool FinishedSnapshotWrites();
+ // If |wipe| is set to true, wipe is scheduled after reboot, and snapshots
+ // may need to be merged before wiping.
+ bool FinishedSnapshotWrites(bool wipe);
// Initiate a merge on all snapshot devices. This should only be used after an
// update has been marked successful after booting.
@@ -523,6 +525,10 @@
bool ShouldDeleteSnapshot(LockedFile* lock, const std::map<std::string, bool>& flashing_status,
Slot current_slot, const std::string& name);
+ // Create or delete forward merge indicator given |wipe|. Iff wipe is scheduled,
+ // allow forward merge on FDR.
+ bool UpdateForwardMergeIndicator(bool wipe);
+
std::string gsid_dir_;
std::string metadata_dir_;
std::unique_ptr<IDeviceInfo> device_;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 6c18b17..f7df181 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -248,7 +248,7 @@
return WriteUpdateState(lock, UpdateState::None);
}
-bool SnapshotManager::FinishedSnapshotWrites() {
+bool SnapshotManager::FinishedSnapshotWrites(bool wipe) {
auto lock = LockExclusive();
if (!lock) return false;
@@ -268,6 +268,10 @@
return false;
}
+ if (!UpdateForwardMergeIndicator(wipe)) {
+ return false;
+ }
+
// This file is written on boot to detect whether a rollback occurred. It
// MUST NOT exist before rebooting, otherwise, we're at risk of deleting
// snapshots too early.
@@ -2638,5 +2642,19 @@
return CreateResult::CREATED;
}
+bool SnapshotManager::UpdateForwardMergeIndicator(bool wipe) {
+ if (!wipe) {
+ return RemoveFileIfExists(path);
+ }
+
+ LOG(INFO) << "Wipe will be scheduled. Allowing forward merge of snapshots.";
+ if (!android::base::WriteStringToFile("1", path)) {
+ PLOG(ERROR) << "Unable to write forward merge indicator: " << path;
+ return false;
+ }
+
+ return true;
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index fdcde52..862add1 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -320,7 +320,7 @@
// Simulate a reboot into the new slot.
AssertionResult SimulateReboot() {
lock_ = nullptr;
- if (!sm->FinishedSnapshotWrites()) {
+ if (!sm->FinishedSnapshotWrites(false)) {
return AssertionFailure();
}
if (!dm_.DeleteDevice("test_partition_b")) {
@@ -424,7 +424,7 @@
}
TEST_F(SnapshotTest, NoMergeBeforeReboot) {
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
// Merge should fail, since the slot hasn't changed.
ASSERT_FALSE(sm->InitiateMerge());
@@ -440,7 +440,7 @@
}
TEST_F(SnapshotTest, FirstStageMountAfterRollback) {
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
// We didn't change the slot, so we shouldn't need snapshots.
TestDeviceInfo* info = new TestDeviceInfo(fake_super);
@@ -476,7 +476,7 @@
lock_ = nullptr;
// Done updating.
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
test_device->set_slot_suffix("_b");
ASSERT_TRUE(sm->InitiateMerge());
@@ -1007,7 +1007,7 @@
ASSERT_TRUE(IsPartitionUnchanged(name));
}
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
// Simulate shutting down the device.
ASSERT_TRUE(UnmapAll());
@@ -1139,7 +1139,7 @@
ASSERT_TRUE(IsPartitionUnchanged(name));
}
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
// Simulate shutting down the device.
ASSERT_TRUE(UnmapAll());
@@ -1171,7 +1171,7 @@
// Test that if an update is applied but not booted into, it can be canceled.
TEST_F(SnapshotUpdateTest, CancelAfterApply) {
ASSERT_TRUE(sm->BeginUpdate());
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
ASSERT_TRUE(sm->CancelUpdate());
}
@@ -1188,7 +1188,7 @@
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
ASSERT_TRUE(MapUpdateSnapshots());
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
// Simulate shutting down the device.
ASSERT_TRUE(UnmapAll());
@@ -1295,7 +1295,7 @@
ASSERT_TRUE(IsPartitionUnchanged(name));
}
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
}
TEST_F(SnapshotUpdateTest, MergeCannotRemoveCow) {
@@ -1324,7 +1324,7 @@
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
ASSERT_TRUE(MapUpdateSnapshots());
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
// Simulate shutting down the device.
ASSERT_TRUE(UnmapAll());
@@ -1428,7 +1428,7 @@
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
ASSERT_TRUE(MapUpdateSnapshots());
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
// Simulate shutting down the device.
ASSERT_TRUE(UnmapAll());
@@ -1460,7 +1460,7 @@
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
ASSERT_TRUE(MapUpdateSnapshots());
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
// Simulate shutting down the device.
ASSERT_TRUE(UnmapAll());
@@ -1485,7 +1485,7 @@
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
ASSERT_TRUE(MapUpdateSnapshots());
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
// Simulate shutting down the device.
ASSERT_TRUE(UnmapAll());
@@ -1533,7 +1533,7 @@
ASSERT_TRUE(WriteSnapshotAndHash("sys_b", partition_size));
// Finish update.
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
// Simulate shutting down the device.
ASSERT_TRUE(UnmapAll());
@@ -1569,7 +1569,7 @@
ASSERT_EQ(1u, table.size());
EXPECT_TRUE(table[0].IsOverflowSnapshot());
- ASSERT_FALSE(sm->FinishedSnapshotWrites())
+ ASSERT_FALSE(sm->FinishedSnapshotWrites(false))
<< "FinishedSnapshotWrites should detect overflow of CoW device.";
}
@@ -1623,7 +1623,7 @@
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
ASSERT_TRUE(MapUpdateSnapshots());
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
// Simulate shutting down the device.
ASSERT_TRUE(UnmapAll());