Throttle metric writing by 3 seconds

After aosp/2320000 , pref writes are atomic but slower. Since
update_engine frequently writes metrics such as bytes downloaded to
disk, update time is negatively impacted. Throttle metric writing to
mitigate.

Bug: 259174530
Test: th
Change-Id: I09be219fa08d5569a5cb5b808e07da3d71a8131c
diff --git a/metrics_utils.h b/metrics_utils.h
index 16e9eec..2f79140 100644
--- a/metrics_utils.h
+++ b/metrics_utils.h
@@ -17,7 +17,11 @@
 #ifndef UPDATE_ENGINE_METRICS_UTILS_H_
 #define UPDATE_ENGINE_METRICS_UTILS_H_
 
+#include <chrono>
 #include <string>
+#include <string_view>
+#include <type_traits>
+#include <utility>
 
 #include <base/time/time.h>
 
@@ -81,6 +85,69 @@
                                PrefsInterface* prefs,
                                ClockInterface* clock);
 
+template <typename T>
+class PersistedValue {
+ public:
+  PersistedValue(std::string_view key, PrefsInterface* prefs)
+      : key_(key), prefs_(prefs) {
+    val_ = metrics_utils::GetPersistedValue(key, prefs);
+  }
+  ~PersistedValue() { Flush(true); }
+  void Delete() {
+    val_ = {};
+    prefs_->Delete(key_);
+  }
+  T get() const { return val_; }
+  using clock = std::chrono::system_clock;
+  using time_point = clock::time_point;
+  // prefix increment
+  PersistedValue<T>& operator++() {
+    ++val_;
+    Flush();
+    return *this;
+  }
+  PersistedValue<T>& operator--() {
+    --val_;
+    Flush();
+    return *this;
+  }
+  PersistedValue<T>& operator+=(T&& t) {
+    val_ += std::forward<T>(t);
+    Flush();
+    return *this;
+  }
+  PersistedValue<T>& operator-=(T&& t) {
+    val_ -= std::forward<T>(t);
+    Flush();
+    return *this;
+  }
+  PersistedValue<T>& operator=(T&& t) {
+    val_ = std::forward<T>(t);
+    Flush();
+    return *this;
+  }
+  void Flush(bool force = false) {
+    auto now = clock::now();
+    if (now - last_save_ > metrics::kMetricFlushInterval || force) {
+      last_save_ = now;
+      if (std::is_integral_v<T>) {
+        prefs_->SetInt64(key_, val_);
+      } else if (std::is_same_v<T, bool>) {
+        prefs_->SetBoolean(key_, val_);
+      } else {
+        auto value = std::to_string(val_);
+        prefs_->SetString(key_, value);
+      }
+    }
+  }
+
+ private:
+  const std::string_view key_;
+  PrefsInterface* prefs_;
+  T val_;
+  time_point last_save_{};
+};
+
 }  // namespace metrics_utils
 }  // namespace chromeos_update_engine