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:
commit
cedb057e2b
7 changed files with 115 additions and 21 deletions
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue