Merge "libsnapshot: Prototype the new API for mapping writable snapshots."
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 0bb1b87..aa41be3 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -30,6 +30,7 @@
     static_libs: [
         "libdm",
         "libfstab",
+        "libsnapshot_cow",
         "update_metadata-protos",
     ],
     whole_static_libs: [
@@ -38,7 +39,9 @@
         "libfstab",
     ],
     header_libs: [
+        "libchrome",
         "libfiemap_headers",
+        "libupdate_engine_headers",
     ],
     export_static_lib_headers: [
         "update_metadata-protos",
@@ -313,8 +316,10 @@
         "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 4457de3..70e1dc8 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 <libsnapshot/snapshot.h>
+#include <payload_consumer/file_descriptor.h>
 
 #include <gmock/gmock.h>
 
@@ -37,6 +38,12 @@
                 (const android::fs_mgr::CreateLogicalPartitionParams& params,
                  std::string* snapshot_path),
                 (override));
+    MOCK_METHOD(std::unique_ptr<ICowWriter>, OpenSnapshotWriter,
+                (const std::string& partition_name, std::chrono::milliseconds timeout_ms),
+                (override));
+    MOCK_METHOD(std::unique_ptr<FileDescriptor>, 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 a4a3150..dacdb1e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -35,6 +35,7 @@
 #include <update_engine/update_metadata.pb.h>
 
 #include <libsnapshot/auto_device.h>
+#include <libsnapshot/cow_writer.h>
 #include <libsnapshot/return.h>
 
 #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 @@
     };
     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 @@
 
     // 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<ICowWriter> 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<FileDescriptor> 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 @@
     Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override;
     bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
                            std::string* snapshot_path) override;
+    std::unique_ptr<ICowWriter> OpenSnapshotWriter(
+            const std::string& partition_name, std::chrono::milliseconds timeout_ms = {}) override;
+    std::unique_ptr<FileDescriptor> 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 7a27fad..f70cc92 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 <libsnapshot/snapshot.h>
+#include <payload_consumer/file_descriptor.h>
 
 namespace android::snapshot {
 
@@ -35,6 +36,10 @@
             const chromeos_update_engine::DeltaArchiveManifest& manifest) override;
     bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
                            std::string* snapshot_path) override;
+    std::unique_ptr<ICowWriter> OpenSnapshotWriter(const std::string& partition_name,
+                                                   std::chrono::milliseconds timeout_ms) override;
+    std::unique_ptr<FileDescriptor> 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 b49f99e..a74f984 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -27,6 +27,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
+#include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <ext4_utils/ext4_utils.h>
@@ -68,6 +69,7 @@
 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 <typename T>
 using RepeatedPtrField = google::protobuf::RepeatedPtrField<T>;
@@ -103,6 +105,10 @@
     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 @@
 
 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 @@
     return MapPartitionWithSnapshot(lock.get(), params, snapshot_path);
 }
 
+std::unique_ptr<ICowWriter> 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<FileDescriptor> 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 9b6f758..269dd09 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 @@
     return &snapshot_merge_stats;
 }
 
+std::unique_ptr<ICowWriter> SnapshotManagerStub::OpenSnapshotWriter(const std::string&,
+                                                                    std::chrono::milliseconds) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return nullptr;
+}
+
+std::unique_ptr<FileDescriptor> SnapshotManagerStub::OpenSnapshotReader(const std::string&,
+                                                                        std::chrono::milliseconds) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return nullptr;
+}
+
 }  // namespace android::snapshot