[metrics] Enable periodic reporting for system server

This enables reporting from system server once an hour.

The reason is that system server is long-running, so startup metrics,
which are all that are enabled by default otherwise, are not as
meaningful. Note that the reporting period can still be overridden by
a command line argument.

Testing instructions:

    adb shell setprop dalvik.vm.extra-opts -Xwrite-metrics-to-log
    adb logcat -e "ART internal metrics"

    Observe periodic system server reports.

Bug: 170149255
Test: manual (see above)
Test: ./test.py --run-test --host -t 911
Change-Id: I71775e454c6fd07c4312e3df9ae8082fa497ea93
diff --git a/libartbase/base/time_utils.h b/libartbase/base/time_utils.h
index e1273a3..fbf3e94 100644
--- a/libartbase/base/time_utils.h
+++ b/libartbase/base/time_utils.h
@@ -35,6 +35,10 @@
   kTimeUnitSecond,
 };
 
+// Constants for common time periods.
+constexpr unsigned int kOneMinuteInSeconds = 60;
+constexpr unsigned int kOneHourInSeconds = 60 * kOneMinuteInSeconds;
+
 // Returns a human-readable time string which prints every nanosecond while trying to limit the
 // number of trailing zeros. Prints using the largest human readable unit up to a second.
 // e.g. "1ms", "1.000000001s", "1.001us"
diff --git a/runtime/metrics/reporter.cc b/runtime/metrics/reporter.cc
index 745b9b1..262422e 100644
--- a/runtime/metrics/reporter.cc
+++ b/runtime/metrics/reporter.cc
@@ -37,12 +37,25 @@
 
 MetricsReporter::~MetricsReporter() { MaybeStopBackgroundThread(); }
 
-void MetricsReporter::MaybeStartBackgroundThread(SessionData session_data) {
+bool MetricsReporter::IsPeriodicReportingEnabled() const {
+  return config_.periodic_report_seconds.has_value();
+}
+
+void MetricsReporter::SetReportingPeriod(unsigned int period_seconds) {
+  DCHECK(!thread_.has_value()) << "The reporting period should not be changed after the background "
+                                  "reporting thread is started.";
+
+  config_.periodic_report_seconds = period_seconds;
+}
+
+bool MetricsReporter::MaybeStartBackgroundThread(SessionData session_data) {
+  if (!config_.ReportingEnabled()) {
+    return false;
+  }
   CHECK(!thread_.has_value());
-
   thread_.emplace(&MetricsReporter::BackgroundThreadRun, this);
-
   messages_.SendMessage(BeginSessionMessage{session_data});
+  return true;
 }
 
 void MetricsReporter::MaybeStopBackgroundThread() {
diff --git a/runtime/metrics/reporter.h b/runtime/metrics/reporter.h
index ee0d13a..ca43163 100644
--- a/runtime/metrics/reporter.h
+++ b/runtime/metrics/reporter.h
@@ -62,7 +62,11 @@
   ~MetricsReporter();
 
   // Creates and runs the background reporting thread.
-  void MaybeStartBackgroundThread(SessionData session_data);
+  //
+  // Does nothing if the reporting config does not have any outputs enabled.
+  //
+  // Returns true if the thread was started, false otherwise.
+  bool MaybeStartBackgroundThread(SessionData session_data);
 
   // Sends a request to the background thread to shutdown.
   void MaybeStopBackgroundThread();
@@ -71,6 +75,14 @@
   // completes.
   void NotifyStartupCompleted();
 
+  bool IsPeriodicReportingEnabled() const;
+
+  // Changes the reporting period.
+  //
+  // This function is not thread safe and may only be called before the background reporting thread
+  // has been started.
+  void SetReportingPeriod(unsigned int period_seconds);
+
   static constexpr const char* kBackgroundThreadName = "Metrics Background Reporting Thread";
 
  private:
@@ -85,7 +97,7 @@
   // Outputs the current state of the metrics to the destination set by config_.
   void ReportMetrics() const;
 
-  const ReportingConfig config_;
+  ReportingConfig config_;
   Runtime* runtime_;
   std::vector<std::unique_ptr<MetricsBackend>> backends_;
   std::optional<std::thread> thread_;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 3c187d3..7010c17 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1070,6 +1070,14 @@
   heap_->ResetGcPerformanceInfo();
 
   if (metrics_reporter_ != nullptr) {
+    if (IsSystemServer() && !metrics_reporter_->IsPeriodicReportingEnabled()) {
+      // For system server, we don't get startup metrics, so make sure we have periodic reporting
+      // enabled.
+      //
+      // Note that this does not override the command line argument if one is given.
+      metrics_reporter_->SetReportingPeriod(kOneHourInSeconds);
+    }
+
     metrics::SessionData session_data{metrics::SessionData::CreateDefault()};
     session_data.session_id = GetRandomNumber<int64_t>(0, std::numeric_limits<int64_t>::max());
     // TODO: set session_data.compilation_reason and session_data.compiler_filter
@@ -1846,9 +1854,7 @@
 
 void Runtime::InitMetrics(const RuntimeArgumentMap& runtime_options) {
   auto metrics_config = metrics::ReportingConfig::FromRuntimeArguments(runtime_options);
-  if (metrics_config.ReportingEnabled()) {
-    metrics_reporter_ = metrics::MetricsReporter::Create(metrics_config, this);
-  }
+  metrics_reporter_ = metrics::MetricsReporter::Create(metrics_config, this);
 }
 
 bool Runtime::EnsurePluginLoaded(const char* plugin_name, std::string* error_msg) {