Merge changes Ibffdd9c9,Ief5a16d1
* changes:
libsnapshot: Add a test case for unexpected snapshots during data resets.
libfiemap: Add some dependency injection.
diff --git a/fs_mgr/libfiemap/binder.cpp b/fs_mgr/libfiemap/binder.cpp
index c8516ab..31a57a8 100644
--- a/fs_mgr/libfiemap/binder.cpp
+++ b/fs_mgr/libfiemap/binder.cpp
@@ -224,8 +224,9 @@
return false;
}
-std::unique_ptr<IImageManager> IImageManager::Open(
- const std::string& dir, const std::chrono::milliseconds& /*timeout_ms*/) {
+std::unique_ptr<IImageManager> IImageManager::Open(const std::string& dir,
+ const std::chrono::milliseconds& /*timeout_ms*/,
+ const DeviceInfo&) {
android::sp<IGsiService> service = android::gsi::GetGsiService();
android::sp<IImageService> manager;
diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index 44f659b..dcbbc54 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -55,7 +55,8 @@
static constexpr char kTestImageMetadataDir[] = "/metadata/gsi/test";
static constexpr char kOtaTestImageMetadataDir[] = "/metadata/gsi/ota/test";
-std::unique_ptr<ImageManager> ImageManager::Open(const std::string& dir_prefix) {
+std::unique_ptr<ImageManager> ImageManager::Open(const std::string& dir_prefix,
+ const DeviceInfo& device_info) {
auto metadata_dir = "/metadata/gsi/" + dir_prefix;
auto data_dir = "/data/gsi/" + dir_prefix;
auto install_dir_file = gsi::DsuInstallDirFile(gsi::GetDsuSlot(dir_prefix));
@@ -63,17 +64,28 @@
if (ReadFileToString(install_dir_file, &path)) {
data_dir = path;
}
- return Open(metadata_dir, data_dir);
+ return Open(metadata_dir, data_dir, device_info);
}
std::unique_ptr<ImageManager> ImageManager::Open(const std::string& metadata_dir,
- const std::string& data_dir) {
- return std::unique_ptr<ImageManager>(new ImageManager(metadata_dir, data_dir));
+ const std::string& data_dir,
+ const DeviceInfo& device_info) {
+ return std::unique_ptr<ImageManager>(new ImageManager(metadata_dir, data_dir, device_info));
}
-ImageManager::ImageManager(const std::string& metadata_dir, const std::string& data_dir)
- : metadata_dir_(metadata_dir), data_dir_(data_dir) {
+ImageManager::ImageManager(const std::string& metadata_dir, const std::string& data_dir,
+ const DeviceInfo& device_info)
+ : metadata_dir_(metadata_dir), data_dir_(data_dir), device_info_(device_info) {
partition_opener_ = std::make_unique<android::fs_mgr::PartitionOpener>();
+
+ // Allow overriding whether ImageManager thinks it's in recovery, for testing.
+#ifdef __ANDROID_RECOVERY__
+ device_info_.is_recovery = {true};
+#else
+ if (!device_info_.is_recovery.has_value()) {
+ device_info_.is_recovery = {false};
+ }
+#endif
}
std::string ImageManager::GetImageHeaderPath(const std::string& name) {
@@ -261,10 +273,11 @@
return false;
}
-#if defined __ANDROID_RECOVERY__
- LOG(ERROR) << "Cannot remove images backed by /data in recovery";
- return false;
-#else
+ if (device_info_.is_recovery.value()) {
+ LOG(ERROR) << "Cannot remove images backed by /data in recovery";
+ return false;
+ }
+
std::string message;
auto header_file = GetImageHeaderPath(name);
if (!SplitFiemap::RemoveSplitFiles(header_file, &message)) {
@@ -278,7 +291,6 @@
LOG(ERROR) << "Error removing " << status_file << ": " << message;
}
return RemoveImageMetadata(metadata_dir_, name);
-#endif
}
// Create a block device for an image file, using its extents in its
@@ -521,6 +533,9 @@
// filesystem. This should only happen on devices with no encryption, or
// devices with FBE and no metadata encryption. For these cases it suffices
// to perform normal file writes to /data/gsi (which is unencrypted).
+ //
+ // Note: this is not gated on DeviceInfo, because the recovery-specific path
+ // must only be used in actual recovery.
std::string block_device;
bool can_use_devicemapper;
if (!FiemapWriter::GetBlockDeviceForFile(image_header, &block_device, &can_use_devicemapper)) {
diff --git a/fs_mgr/libfiemap/include/libfiemap/image_manager.h b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
index 7e30509..3c87000 100644
--- a/fs_mgr/libfiemap/include/libfiemap/image_manager.h
+++ b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
@@ -21,6 +21,7 @@
#include <chrono>
#include <functional>
#include <memory>
+#include <optional>
#include <set>
#include <string>
@@ -37,11 +38,17 @@
virtual ~IImageManager() {}
+ // Helper for dependency injection.
+ struct DeviceInfo {
+ std::optional<bool> is_recovery;
+ };
+
// When linking to libfiemap_binder, the Open() call will use binder.
// Otherwise, the Open() call will use the ImageManager implementation
- // below.
+ // below. In binder mode, device_info is ignored.
static std::unique_ptr<IImageManager> Open(const std::string& dir_prefix,
- const std::chrono::milliseconds& timeout_ms);
+ const std::chrono::milliseconds& timeout_ms,
+ const DeviceInfo& device_info = {});
// Flags for CreateBackingImage().
static constexpr int CREATE_IMAGE_DEFAULT = 0x0;
@@ -131,11 +138,13 @@
// Return an ImageManager for the given metadata and data directories. Both
// directories must already exist.
static std::unique_ptr<ImageManager> Open(const std::string& metadata_dir,
- const std::string& data_dir);
+ const std::string& data_dir,
+ const DeviceInfo& device_info = {});
// Helper function that derives the metadata and data dirs given a single
// prefix.
- static std::unique_ptr<ImageManager> Open(const std::string& dir_prefix);
+ static std::unique_ptr<ImageManager> Open(const std::string& dir_prefix,
+ const DeviceInfo& device_info = {});
// Methods that must be implemented from IImageManager.
FiemapStatus CreateBackingImage(const std::string& name, uint64_t size, int flags,
@@ -166,7 +175,8 @@
FiemapStatus ZeroFillNewImage(const std::string& name, uint64_t bytes);
private:
- ImageManager(const std::string& metadata_dir, const std::string& data_dir);
+ ImageManager(const std::string& metadata_dir, const std::string& data_dir,
+ const DeviceInfo& device_info);
std::string GetImageHeaderPath(const std::string& name);
std::string GetStatusFilePath(const std::string& image_name);
bool MapWithLoopDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms,
@@ -187,6 +197,7 @@
std::string metadata_dir_;
std::string data_dir_;
std::unique_ptr<IPartitionOpener> partition_opener_;
+ DeviceInfo device_info_;
};
// RAII helper class for mapping and opening devices with an ImageManager.
diff --git a/fs_mgr/libfiemap/passthrough.cpp b/fs_mgr/libfiemap/passthrough.cpp
index 1ccd9a0..d521804 100644
--- a/fs_mgr/libfiemap/passthrough.cpp
+++ b/fs_mgr/libfiemap/passthrough.cpp
@@ -20,9 +20,10 @@
namespace fiemap {
std::unique_ptr<IImageManager> IImageManager::Open(const std::string& dir_prefix,
- const std::chrono::milliseconds& timeout_ms) {
+ const std::chrono::milliseconds& timeout_ms,
+ const DeviceInfo& device_info) {
(void)timeout_ms;
- return ImageManager::Open(dir_prefix);
+ return ImageManager::Open(dir_prefix, device_info);
}
} // namespace fiemap
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 195b6f2..d2fdfd6 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -392,6 +392,7 @@
FRIEND_TEST(SnapshotUpdateTest, DaemonTransition);
FRIEND_TEST(SnapshotUpdateTest, DataWipeAfterRollback);
FRIEND_TEST(SnapshotUpdateTest, DataWipeRollbackInRecovery);
+ FRIEND_TEST(SnapshotUpdateTest, DataWipeWithStaleSnapshots);
FRIEND_TEST(SnapshotUpdateTest, FullUpdateFlow);
FRIEND_TEST(SnapshotUpdateTest, MergeCannotRemoveCow);
FRIEND_TEST(SnapshotUpdateTest, MergeInRecovery);
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 8f3926a..245742e 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -2583,7 +2583,11 @@
}
bool SnapshotManager::ForceLocalImageManager() {
- images_ = android::fiemap::ImageManager::Open(gsid_dir_);
+ android::fiemap::ImageManager::DeviceInfo device_info = {
+ .is_recovery = {device_->IsRecovery()},
+ };
+
+ images_ = android::fiemap::ImageManager::Open(gsid_dir_, device_info);
if (!images_) {
LOG(ERROR) << "Could not open ImageManager";
return false;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index f18f176..9226b7f 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1860,6 +1860,67 @@
}
}
+// Test update package that requests data wipe.
+TEST_F(SnapshotUpdateTest, DataWipeWithStaleSnapshots) {
+ AddOperationForPartitions();
+
+ // Execute the update.
+ ASSERT_TRUE(sm->BeginUpdate());
+ ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
+
+ // Write some data to target partitions.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+ ASSERT_TRUE(WriteSnapshotAndHash(name)) << name;
+ }
+
+ // Create a stale snapshot that should not exist.
+ {
+ ASSERT_TRUE(AcquireLock());
+
+ PartitionCowCreator cow_creator = {
+ .compression_enabled = IsCompressionEnabled(),
+ .compression_algorithm = IsCompressionEnabled() ? "gz" : "none",
+ };
+ SnapshotStatus status;
+ status.set_name("sys_a");
+ status.set_device_size(1_MiB);
+ status.set_snapshot_size(2_MiB);
+ status.set_cow_partition_size(2_MiB);
+
+ ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &cow_creator, &status));
+ lock_ = nullptr;
+
+ ASSERT_TRUE(sm->EnsureImageManager());
+ ASSERT_TRUE(sm->image_manager()->CreateBackingImage("sys_a", 1_MiB, 0));
+ }
+
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(true /* wipe */));
+
+ // Simulate shutting down the device.
+ ASSERT_TRUE(UnmapAll());
+
+ // Simulate a reboot into recovery.
+ auto test_device = new TestDeviceInfo(fake_super, "_b");
+ test_device->set_recovery(true);
+ auto new_sm = NewManagerForFirstStageMount(test_device);
+
+ ASSERT_TRUE(new_sm->HandleImminentDataWipe());
+ // Manually mount metadata so that we can call GetUpdateState() below.
+ MountMetadata();
+ EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::None);
+ ASSERT_FALSE(test_device->IsSlotUnbootable(1));
+ ASSERT_FALSE(test_device->IsSlotUnbootable(0));
+
+ // Now reboot into new slot.
+ test_device = new TestDeviceInfo(fake_super, "_b");
+ auto init = NewManagerForFirstStageMount(test_device);
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+ // Verify that we are on the downgraded build.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+ ASSERT_TRUE(IsPartitionUnchanged(name)) << name;
+ }
+}
+
TEST_F(SnapshotUpdateTest, Hashtree) {
constexpr auto partition_size = 4_MiB;
constexpr auto data_size = 3_MiB;