libsnapshot: Export COW image size

Enable libsnapshot to export the size of the COW image, representing the
fraction of the COW device that is temporarily created in the /data
partition, computed just before initializing a merge operation.
Thise additional information can be used by other components (i.e.,
update engine) to enrich Virtual A/B metrics.

Bug: 154016862
Test: manual OTA
Signed-off-by: Alessio Balsini <balsini@google.com>
Signed-off-by: Yifan Hong <elsk@google.com>
Change-Id: I4faa0785f23884e26161e0d51268dd7a305d86bf
Merged-In: I4faa0785f23884e26161e0d51268dd7a305d86bf
(cherry picked from commit 2a1778d3400a10538653f2d60e5f8b87cc4dd2c0)
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index 2ac0c44..587089e 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -140,4 +140,7 @@
     // Number of reboots that occurred after issuing and before completeing the
     // merge of all the snapshot devices.
     int32 resume_count = 2;
+
+    // Total size of all the COW images before the update.
+    uint64 cow_file_size = 4;
 }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index ac8a25e..b207978 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -148,7 +148,7 @@
 
     // Initiate a merge on all snapshot devices. This should only be used after an
     // update has been marked successful after booting.
-    bool InitiateMerge();
+    bool InitiateMerge(uint64_t* cow_file_size = nullptr);
 
     // Perform any necessary post-boot actions. This should be run soon after
     // /data is mounted.
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
index 91dd34f..bdc3ea3 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
@@ -31,6 +31,8 @@
     // Called when merge starts or resumes.
     bool Start();
     void set_state(android::snapshot::UpdateState state);
+    virtual void set_cow_file_size(uint64_t cow_file_size);
+    virtual uint64_t cow_file_size();
 
     // Called when merge ends. Properly clean up permanent storage.
     class Result {
@@ -43,6 +45,8 @@
     std::unique_ptr<Result> Finish();
 
   private:
+    virtual ~SnapshotMergeStats() {}
+
     bool ReadState();
     bool WriteState();
     bool DeleteState();
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index d4a3f62..0739fab 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -555,7 +555,7 @@
     return true;
 }
 
-bool SnapshotManager::InitiateMerge() {
+bool SnapshotManager::InitiateMerge(uint64_t* cow_file_size) {
     auto lock = LockExclusive();
     if (!lock) return false;
 
@@ -618,6 +618,7 @@
         }
     }
 
+    uint64_t total_cow_file_size = 0;
     DmTargetSnapshot::Status initial_target_values = {};
     for (const auto& snapshot : snapshots) {
         DmTargetSnapshot::Status current_status;
@@ -627,6 +628,16 @@
         initial_target_values.sectors_allocated += current_status.sectors_allocated;
         initial_target_values.total_sectors += current_status.total_sectors;
         initial_target_values.metadata_sectors += current_status.metadata_sectors;
+
+        SnapshotStatus snapshot_status;
+        if (!ReadSnapshotStatus(lock.get(), snapshot, &snapshot_status)) {
+            return false;
+        }
+        total_cow_file_size += snapshot_status.cow_file_size();
+    }
+
+    if (cow_file_size) {
+        *cow_file_size = total_cow_file_size;
     }
 
     SnapshotUpdateStatus initial_status;
diff --git a/fs_mgr/libsnapshot/snapshot_stats.cpp b/fs_mgr/libsnapshot/snapshot_stats.cpp
index 5da7b98..3723730 100644
--- a/fs_mgr/libsnapshot/snapshot_stats.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stats.cpp
@@ -88,6 +88,15 @@
     report_.set_state(state);
 }
 
+void SnapshotMergeStats::set_cow_file_size(uint64_t cow_file_size) {
+    report_.set_cow_file_size(cow_file_size);
+    WriteState();
+}
+
+uint64_t SnapshotMergeStats::cow_file_size() {
+    return report_.cow_file_size();
+}
+
 class SnapshotMergeStatsResultImpl : public SnapshotMergeStats::Result {
   public:
     SnapshotMergeStatsResultImpl(const SnapshotMergeReport& report,