Flush UMA session on pause

We don't want to end the UMA session because we might be starting an
Activity in the same session (eg. History), but we still need to flush
the existing record and state as Android might kill us before we get
stopped.

We also kill ourselves when setting chrome://flags before stop is
called, so that also necessitates a flush.

Flagged by UmaSessionsCorrectnessFixes.

Bug: 441405026, 400975101
Change-Id: Ic871df1077a54231e55d2b8199dcf37dc38a62d9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6931621
Commit-Queue: Michael Thiessen <mthiesse@chromium.org>
Reviewed-by: Mark Pearson <mpearson@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1514656}
NOKEYCHECK=True
GitOrigin-RevId: 2adfd07d057d8a363cf814a33aa8182b1ccaceb2
diff --git a/metrics_logs_event_manager.h b/metrics_logs_event_manager.h
index 82b42d3..9550f1d 100644
--- a/metrics_logs_event_manager.h
+++ b/metrics_logs_event_manager.h
@@ -59,7 +59,9 @@
     kIndependent = 9,
     // The log was created due to a manual upload from the client.
     kOutOfBand = 10,
-    kMaxValue = kOutOfBand,
+    // The log was created due to a flush from the client.
+    kFlush = 11,
+    kMaxValue = kFlush,
   };
   // LINT.ThenChange(/tools/metrics/histograms/metadata/uma/enums.xml:MetricsLogCreateReason)
 
diff --git a/metrics_service.cc b/metrics_service.cc
index f63ccc0..dfdec70 100644
--- a/metrics_service.cc
+++ b/metrics_service.cc
@@ -218,7 +218,6 @@
   }
 };
 
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
 // Emits a histogram upon instantiation, and on destruction. Used to measure how
 // often the browser is ungracefully killed between two different points. In
 // particular, currently, this is used on mobile to measure how often the
@@ -279,7 +278,6 @@
   // this object will do nothing.
   bool active_ = false;
 };
-#endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
 
 // The delay, in seconds, after starting recording before doing expensive
 // initialization work.
@@ -706,6 +704,24 @@
 }
 #endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
 
+void MetricsService::Flush() {
+  if (recording_active() && !IsTooEarlyToCloseLog()) {
+#if BUILDFLAG(IS_ANDROID)
+    client_->MergeSubprocessHistograms();
+#endif  // BUILDFLAG(IS_ANDROID)
+    {
+      ScopedTerminationChecker scoped_termination_checker(
+          "UMA.MetricsService.OnFlushScopedTerminationChecker");
+      PushPendingLogsToPersistentStorage(
+          MetricsLogsEventManager::CreateReason::kFlush);
+    }
+
+    // Persisting logs closes the current log, so start recording a new log
+    // immediately.
+    OpenNewLog();
+  }
+}
+
 void MetricsService::OnPageLoadStarted() {
   delegating_provider_.OnPageLoadStarted();
 }
diff --git a/metrics_service.h b/metrics_service.h
index 6260e01..d7c5e39 100644
--- a/metrics_service.h
+++ b/metrics_service.h
@@ -172,8 +172,14 @@
 
   // Called when the application is coming out of background mode.
   void OnAppEnterForeground(bool force_open_new_log = false);
+
 #endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
 
+  // Flushes state that would be lost if the browser were to be killed. On
+  // Android, this should be called when an Activity pauses, as Android could
+  // suddenly kill the app at that point.
+  void Flush();
+
   // Called when a document first starts loading.
   void OnPageLoadStarted();
 
diff --git a/metrics_service_observer.cc b/metrics_service_observer.cc
index 559753e..6b773ac 100644
--- a/metrics_service_observer.cc
+++ b/metrics_service_observer.cc
@@ -89,6 +89,8 @@
       return "Reason: Independent log";
     case MetricsLogsEventManager::CreateReason::kOutOfBand:
       return "Reason: Manually triggered by client";
+    case MetricsLogsEventManager::CreateReason::kFlush:
+      return "Reason: Flush";
   }
 }