Merge changes Ibffdd9c9,Ief5a16d1

* changes:
  libsnapshot: Add a test case for unexpected snapshots during data resets.
  libfiemap: Add some dependency injection.
This commit is contained in:
David Anderson 2021-05-06 17:57:46 +00:00 committed by Gerrit Code Review
commit cedb057e2b
7 changed files with 115 additions and 21 deletions

View file

@ -224,8 +224,9 @@ bool ImageManagerBinder::MapAllImages(const std::function<bool(std::set<std::str
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;

View file

@ -55,7 +55,8 @@ using android::fs_mgr::GetPartitionName;
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 @@ std::unique_ptr<ImageManager> ImageManager::Open(const std::string& dir_prefix)
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 @@ bool ImageManager::DeleteBackingImage(const std::string& name) {
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 @@ bool ImageManager::DeleteBackingImage(const std::string& name) {
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 @@ bool ImageManager::MapImageDevice(const std::string& name,
// 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)) {

View file

@ -21,6 +21,7 @@
#include <chrono>
#include <functional>
#include <memory>
#include <optional>
#include <set>
#include <string>
@ -37,11 +38,17 @@ class IImageManager {
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 @@ class ImageManager final : public IImageManager {
// 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 @@ class ImageManager final : public IImageManager {
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 @@ class ImageManager final : public IImageManager {
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.

View file

@ -20,9 +20,10 @@ namespace android {
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

View file

@ -392,6 +392,7 @@ class SnapshotManager final : public ISnapshotManager {
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);

View file

@ -2583,7 +2583,11 @@ bool SnapshotManager::EnsureSnapuserdConnected() {
}
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;

View file

@ -1860,6 +1860,67 @@ TEST_F(SnapshotUpdateTest, DataWipeRequiredInPackage) {
}
}
// 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;