Merge "Utility class to measure snapshot merge duration" am: e87527faa3 am: e6060c927c am: 5a88ff5e18

Change-Id: Ie2f86222e09bdaf1976f10fd996912d550b47e7d
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index adfee1d..d274ba4 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -72,6 +72,7 @@
         "android/snapshot/snapshot.proto",
         "device_info.cpp",
         "snapshot.cpp",
+        "snapshot_stats.cpp",
         "snapshot_metadata_updater.cpp",
         "partition_cow_creator.cpp",
         "return.cpp",
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index a3a518d..2ac0c44 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -131,3 +131,13 @@
     // Sectors allocated for metadata in all the snapshot devices.
     uint64 metadata_sectors = 4;
 }
+
+// Next: 2
+message SnapshotMergeReport {
+    // Status of the update after the merge attempts.
+    UpdateState state = 1;
+
+    // Number of reboots that occurred after issuing and before completeing the
+    // merge of all the snapshot devices.
+    int32 resume_count = 2;
+}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index a56078a..0cf579d 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -91,6 +91,8 @@
     using MergeStatus = android::hardware::boot::V1_1::MergeStatus;
     using FiemapStatus = android::fiemap::FiemapStatus;
 
+    friend class SnapshotMergeStats;
+
   public:
     // Dependency injection for testing.
     class IDeviceInfo {
diff --git a/fs_mgr/libsnapshot/snapshot_stats.cpp b/fs_mgr/libsnapshot/snapshot_stats.cpp
new file mode 100644
index 0000000..c48509e
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_stats.cpp
@@ -0,0 +1,80 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "snapshot_stats.h"
+
+#include <sstream>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include "utility.h"
+
+namespace android {
+namespace snapshot {
+
+SnapshotMergeStats::SnapshotMergeStats(SnapshotManager& parent) : parent_(parent) {
+    init_time_ = std::chrono::steady_clock::now();
+}
+
+SnapshotMergeStats::~SnapshotMergeStats() {
+    std::string error;
+    auto file_path = parent_.GetMergeStateFilePath();
+    if (!android::base::RemoveFileIfExists(file_path, &error)) {
+        LOG(ERROR) << "Failed to remove merge statistics file " << file_path << ": " << error;
+        return;
+    }
+}
+
+void SnapshotMergeStats::Start() {
+    SnapshotMergeReport report;
+    report.set_resume_count(0);
+    report.set_state(UpdateState::None);
+
+    std::string contents;
+    if (!report.SerializeToString(&contents)) {
+        LOG(ERROR) << "Unable to serialize SnapshotMergeStats.";
+        return;
+    }
+    auto file_path = parent_.GetMergeStateFilePath();
+    if (!WriteStringToFileAtomic(contents, file_path)) {
+        PLOG(ERROR) << "Could not write to merge statistics file";
+        return;
+    }
+}
+
+void SnapshotMergeStats::Resume() {
+    std::string contents;
+    if (!android::base::ReadFileToString(parent_.GetMergeStateFilePath(), &contents)) {
+        PLOG(INFO) << "Read merge statistics file failed";
+        return;
+    }
+
+    if (!report_.ParseFromString(contents)) {
+        LOG(ERROR) << "Unable to parse merge statistics file as SnapshotMergeReport";
+        return;
+    }
+
+    report_.set_resume_count(report_.resume_count() + 1);
+}
+
+void SnapshotMergeStats::set_state(android::snapshot::UpdateState state) {
+    report_.set_state(state);
+}
+
+SnapshotMergeReport SnapshotMergeStats::GetReport() {
+    return report_;
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/snapshot_stats.h
new file mode 100644
index 0000000..1ca9156
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_stats.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <chrono>
+
+#include <android/snapshot/snapshot.pb.h>
+#include <libsnapshot/snapshot.h>
+
+namespace android {
+namespace snapshot {
+
+class SnapshotMergeStats {
+  public:
+    SnapshotMergeStats(SnapshotManager& parent);
+    ~SnapshotMergeStats();
+    void Start();
+    void Resume();
+    void set_state(android::snapshot::UpdateState state);
+    SnapshotMergeReport GetReport();
+
+  private:
+    const SnapshotManager& parent_;
+    SnapshotMergeReport report_;
+    std::chrono::time_point<std::chrono::steady_clock> init_time_;
+    std::chrono::time_point<std::chrono::steady_clock> end_time_;
+};
+
+}  // namespace snapshot
+}  // namespace android