From 2f11ec6a13503cc508bfdbf7d73779dd4b468261 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 17 Sep 2020 14:41:30 -0700 Subject: [PATCH] libsnapshot: Prototype the new API for mapping writable snapshots. Since we can't provide a single device or fd anymore, we need to expose a CowWriter directly. Additionally, we expose an API for reading snapshots through the FileDescriptor abstraction. Bug: 168554689 Test: builds Change-Id: If7e8adbfe69c2a84d34c63d4b0adff2b3365fd82 --- fs_mgr/libsnapshot/Android.bp | 5 +++ .../include/libsnapshot/mock_snapshot.h | 7 ++++ .../include/libsnapshot/snapshot.h | 27 ++++++++++++++- .../include/libsnapshot/snapshot_stub.h | 5 +++ fs_mgr/libsnapshot/snapshot.cpp | 34 +++++++++++++++++++ fs_mgr/libsnapshot/snapshot_stub.cpp | 13 +++++++ 6 files changed, 90 insertions(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index 0bb1b8719..aa41be3d0 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -30,6 +30,7 @@ cc_defaults { static_libs: [ "libdm", "libfstab", + "libsnapshot_cow", "update_metadata-protos", ], whole_static_libs: [ @@ -38,7 +39,9 @@ cc_defaults { "libfstab", ], header_libs: [ + "libchrome", "libfiemap_headers", + "libupdate_engine_headers", ], export_static_lib_headers: [ "update_metadata-protos", @@ -313,8 +316,10 @@ cc_defaults { "libprotobuf-mutator", ], header_libs: [ + "libchrome", "libfiemap_headers", "libstorage_literals_headers", + "libupdate_engine_headers", ], proto: { type: "full", diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h index 4457de398..70e1dc864 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h @@ -15,6 +15,7 @@ #pragma once #include +#include #include @@ -37,6 +38,12 @@ class MockSnapshotManager : public ISnapshotManager { (const android::fs_mgr::CreateLogicalPartitionParams& params, std::string* snapshot_path), (override)); + MOCK_METHOD(std::unique_ptr, OpenSnapshotWriter, + (const std::string& partition_name, std::chrono::milliseconds timeout_ms), + (override)); + MOCK_METHOD(std::unique_ptr, OpenSnapshotReader, + (const std::string& partition_name, std::chrono::milliseconds timeout_ms), + (override)); MOCK_METHOD(bool, UnmapUpdateSnapshot, (const std::string& target_partition_name), (override)); MOCK_METHOD(bool, NeedSnapshotsInFirstStageMount, (), (override)); MOCK_METHOD(bool, CreateLogicalAndSnapshotPartitions, diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h index a4a31507e..dacdb1ec1 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h @@ -35,6 +35,7 @@ #include #include +#include #include #ifndef FRIEND_TEST @@ -43,6 +44,10 @@ #define DEFINED_FRIEND_TEST #endif +namespace chromeos_update_engine { +class FileDescriptor; +} // namespace chromeos_update_engine + namespace android { namespace fiemap { @@ -105,6 +110,8 @@ class ISnapshotManager { }; virtual ~ISnapshotManager() = default; + using FileDescriptor = chromeos_update_engine::FileDescriptor; + // Begin an update. This must be called before creating any snapshots. It // will fail if GetUpdateState() != None. virtual bool BeginUpdate() = 0; @@ -173,11 +180,25 @@ class ISnapshotManager { // Map a snapshotted partition for OTA clients to write to. Write-protected regions are // determined previously in CreateSnapshots. + // // |snapshot_path| must not be nullptr. + // + // This method will return false if ro.virtual_ab.compression.enabled is true. virtual bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params, std::string* snapshot_path) = 0; - // Unmap a snapshot device that's previously mapped with MapUpdateSnapshot. + // Create an ICowWriter to build a snapshot against a target partition. + virtual std::unique_ptr OpenSnapshotWriter( + const std::string& partition_name, std::chrono::milliseconds timeout_ms = {}) = 0; + + // Open a snapshot for reading. A file-like interface is provided through the FileDescriptor. + // In this mode, writes are not supported. + virtual std::unique_ptr OpenSnapshotReader( + const std::string& partition_name, std::chrono::milliseconds timeout_ms = {}) = 0; + + // Unmap a snapshot device or CowWriter that was previously opened with MapUpdateSnapshot, + // OpenSnapshotWriter, or OpenSnapshotReader. All outstanding open descriptors, writers, + // or readers must be deleted before this is called. virtual bool UnmapUpdateSnapshot(const std::string& target_partition_name) = 0; // If this returns true, first-stage mount must call @@ -288,6 +309,10 @@ class SnapshotManager final : public ISnapshotManager { Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override; bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params, std::string* snapshot_path) override; + std::unique_ptr OpenSnapshotWriter( + const std::string& partition_name, std::chrono::milliseconds timeout_ms = {}) override; + std::unique_ptr OpenSnapshotReader( + const std::string& partition_name, std::chrono::milliseconds timeout_ms = {}) override; bool UnmapUpdateSnapshot(const std::string& target_partition_name) override; bool NeedSnapshotsInFirstStageMount() override; bool CreateLogicalAndSnapshotPartitions( diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h index 7a27fadca..f70cc921a 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h @@ -15,6 +15,7 @@ #pragma once #include +#include namespace android::snapshot { @@ -35,6 +36,10 @@ class SnapshotManagerStub : public ISnapshotManager { const chromeos_update_engine::DeltaArchiveManifest& manifest) override; bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params, std::string* snapshot_path) override; + std::unique_ptr OpenSnapshotWriter(const std::string& partition_name, + std::chrono::milliseconds timeout_ms) override; + std::unique_ptr OpenSnapshotReader( + const std::string& partition_name, std::chrono::milliseconds timeout_ms = {}) override; bool UnmapUpdateSnapshot(const std::string& target_partition_name) override; bool NeedSnapshotsInFirstStageMount() override; bool CreateLogicalAndSnapshotPartitions( diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index b49f99ea4..a74f984ab 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,7 @@ using android::fs_mgr::SlotNumberForSlotSuffix; using android::hardware::boot::V1_1::MergeStatus; using chromeos_update_engine::DeltaArchiveManifest; using chromeos_update_engine::Extent; +using chromeos_update_engine::FileDescriptor; using chromeos_update_engine::InstallOperation; template using RepeatedPtrField = google::protobuf::RepeatedPtrField; @@ -103,6 +105,10 @@ SnapshotManager::SnapshotManager(IDeviceInfo* device) : device_(device) { metadata_dir_ = device_->GetMetadataDir(); } +static inline bool IsCompressionEnabled() { + return android::base::GetBoolProperty("ro.virtual_ab.compression.enabled", false); +} + static std::string GetCowName(const std::string& snapshot_name) { return snapshot_name + "-cow"; } @@ -2420,6 +2426,11 @@ Return SnapshotManager::InitializeUpdateSnapshots( bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& params, std::string* snapshot_path) { + if (IsCompressionEnabled()) { + LOG(ERROR) << "MapUpdateSnapshot cannot be used in compression mode."; + return false; + } + auto lock = LockShared(); if (!lock) return false; if (!UnmapPartitionWithSnapshot(lock.get(), params.GetPartitionName())) { @@ -2430,6 +2441,29 @@ bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& para return MapPartitionWithSnapshot(lock.get(), params, snapshot_path); } +std::unique_ptr SnapshotManager::OpenSnapshotWriter( + const std::string& partition_name, std::chrono::milliseconds timeout_ms) { + if (!IsCompressionEnabled()) { + LOG(ERROR) << "OpenSnapshotWriter can only be called in compression mode."; + return nullptr; + } + + (void)partition_name; + (void)timeout_ms; + + // Not yet implemented. + return nullptr; +} + +std::unique_ptr SnapshotManager::OpenSnapshotReader( + const std::string& partition_name, std::chrono::milliseconds timeout_ms) { + (void)partition_name; + (void)timeout_ms; + + // Not yet implemented. + return nullptr; +} + bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_name) { auto lock = LockShared(); if (!lock) return false; diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp index 9b6f758cc..269dd09fc 100644 --- a/fs_mgr/libsnapshot/snapshot_stub.cpp +++ b/fs_mgr/libsnapshot/snapshot_stub.cpp @@ -20,6 +20,7 @@ using android::fs_mgr::CreateLogicalPartitionParams; using chromeos_update_engine::DeltaArchiveManifest; +using chromeos_update_engine::FileDescriptor; namespace android::snapshot { @@ -129,4 +130,16 @@ ISnapshotMergeStats* SnapshotManagerStub::GetSnapshotMergeStatsInstance() { return &snapshot_merge_stats; } +std::unique_ptr SnapshotManagerStub::OpenSnapshotWriter(const std::string&, + std::chrono::milliseconds) { + LOG(ERROR) << __FUNCTION__ << " should never be called."; + return nullptr; +} + +std::unique_ptr SnapshotManagerStub::OpenSnapshotReader(const std::string&, + std::chrono::milliseconds) { + LOG(ERROR) << __FUNCTION__ << " should never be called."; + return nullptr; +} + } // namespace android::snapshot