[metrics] Report CompilationReason and CompilerFilter

Since we do not know the real primary OAT file when the runtime starts
up, we have to wait until NotifyStartupCompleted to be sure we have
the right one. To accomodate this, we delay starting the metrics
session until the first report and then send updated session
information in NotifyStartupCompleted.

Note that we could delay the whole metrics reporting initialization to
NotifyStartupCompleted, but this doesn't get called in all
circumstances, which would mean metrics reporting is disabled in cases
where we want it.

Bug: 178239096
Test: manual
Change-Id: Ide59be88bc934526e0c172fb745dc2f5cd797749
diff --git a/libartbase/base/metrics/metrics.h b/libartbase/base/metrics/metrics.h
index 4e3346a..316eb7a 100644
--- a/libartbase/base/metrics/metrics.h
+++ b/libartbase/base/metrics/metrics.h
@@ -83,8 +83,14 @@
   kError,
   kUnknown,
   kFirstBoot,
-  kBoot,
+  kBootAfterOTA,
+  kPostBoot,
   kInstall,
+  kInstallFast,
+  kInstallBulk,
+  kInstallBulkSecondary,
+  kInstallBulkDowngraded,
+  kInstallBulkSecondaryDowngraded,
   kBgDexopt,
   kABOTA,
   kInactive,
@@ -95,28 +101,90 @@
 constexpr const char* CompilationReasonName(CompilationReason reason) {
   switch (reason) {
     case CompilationReason::kError:
-      return "Error";
+      return "error";
     case CompilationReason::kUnknown:
-      return "Unknown";
+      return "unknown";
     case CompilationReason::kFirstBoot:
-      return "FirstBoot";
-    case CompilationReason::kBoot:
-      return "Boot";
+      return "first-boot";
+    case CompilationReason::kBootAfterOTA:
+      return "boot-after-ota";
+    case CompilationReason::kPostBoot:
+      return "post-boot";
     case CompilationReason::kInstall:
-      return "Install";
+      return "install";
+    case CompilationReason::kInstallFast:
+      return "install-fast";
+    case CompilationReason::kInstallBulk:
+      return "install-bulk";
+    case CompilationReason::kInstallBulkSecondary:
+      return "install-bulk-secondary";
+    case CompilationReason::kInstallBulkDowngraded:
+      return "install-bulk-downgraded";
+    case CompilationReason::kInstallBulkSecondaryDowngraded:
+      return "install-bulk-secondary-downgraded";
     case CompilationReason::kBgDexopt:
-      return "BgDexopt";
+      return "bg-dexopt";
     case CompilationReason::kABOTA:
-      return "ABOTA";
+      return "ab-ota";
     case CompilationReason::kInactive:
-      return "Inactive";
+      return "inactive";
     case CompilationReason::kShared:
-      return "Shared";
+      return "shared";
     case CompilationReason::kInstallWithDexMetadata:
-      return "InstallWithDexMetadata";
+      return "install-with-dex-metadata";
   }
 }
 
+constexpr CompilationReason CompilationReasonFromName(std::string_view name) {
+  // Names come from PackageManagerServiceCompilerMapping.java
+  if (name == "unknown") {
+    return CompilationReason::kUnknown;
+  }
+  if (name == "first-boot") {
+    return CompilationReason::kFirstBoot;
+  }
+  if (name == "boot-after-ota") {
+    return CompilationReason::kBootAfterOTA;
+  }
+  if (name == "post-boot") {
+    return CompilationReason::kPostBoot;
+  }
+  if (name == "install") {
+    return CompilationReason::kInstall;
+  }
+  if (name == "install-fast") {
+    return CompilationReason::kInstallFast;
+  }
+  if (name == "install-bulk") {
+    return CompilationReason::kInstallBulk;
+  }
+  if (name == "install-bulk-secondary") {
+    return CompilationReason::kInstallBulkSecondary;
+  }
+  if (name == "install-bulk-downgraded") {
+    return CompilationReason::kInstallBulkDowngraded;
+  }
+  if (name == "install-bulk-secondary-downgraded") {
+    return CompilationReason::kInstallBulkSecondaryDowngraded;
+  }
+  if (name == "bg-dexopt") {
+    return CompilationReason::kBgDexopt;
+  }
+  if (name == "ab-ota") {
+    return CompilationReason::kABOTA;
+  }
+  if (name == "inactive") {
+    return CompilationReason::kInactive;
+  }
+  if (name == "shared") {
+    return CompilationReason::kShared;
+  }
+  if (name == "install-with-dex-metadata") {
+    return CompilationReason::kInstallWithDexMetadata;
+  }
+  return CompilationReason::kError;
+}
+
 // SessionData contains metadata about a metrics session (basically the lifetime of an ART process).
 // This information should not change for the lifetime of the session.
 struct SessionData {
diff --git a/libartbase/base/metrics/metrics_common.cc b/libartbase/base/metrics/metrics_common.cc
index 89d003a..7805f51 100644
--- a/libartbase/base/metrics/metrics_common.cc
+++ b/libartbase/base/metrics/metrics_common.cc
@@ -179,6 +179,44 @@
   }
 }
 
+// Make sure CompilationReasonName and CompilationReasonForName are inverses.
+static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kError)) ==
+              CompilationReason::kError);
+static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kUnknown)) ==
+              CompilationReason::kUnknown);
+static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kFirstBoot)) ==
+              CompilationReason::kFirstBoot);
+static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kBootAfterOTA)) ==
+              CompilationReason::kBootAfterOTA);
+static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kPostBoot)) ==
+              CompilationReason::kPostBoot);
+static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstall)) ==
+              CompilationReason::kInstall);
+static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallFast)) ==
+              CompilationReason::kInstallFast);
+static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallBulk)) ==
+              CompilationReason::kInstallBulk);
+static_assert(
+    CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallBulkSecondary)) ==
+    CompilationReason::kInstallBulkSecondary);
+static_assert(
+    CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallBulkDowngraded)) ==
+    CompilationReason::kInstallBulkDowngraded);
+static_assert(CompilationReasonFromName(
+                  CompilationReasonName(CompilationReason::kInstallBulkSecondaryDowngraded)) ==
+              CompilationReason::kInstallBulkSecondaryDowngraded);
+static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kBgDexopt)) ==
+              CompilationReason::kBgDexopt);
+static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kABOTA)) ==
+              CompilationReason::kABOTA);
+static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInactive)) ==
+              CompilationReason::kInactive);
+static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kShared)) ==
+              CompilationReason::kShared);
+static_assert(
+    CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallWithDexMetadata)) ==
+    CompilationReason::kInstallWithDexMetadata);
+
 }  // namespace metrics
 }  // namespace art
 
diff --git a/runtime/metrics/reporter.cc b/runtime/metrics/reporter.cc
index 5148b20..4cf1ba5 100644
--- a/runtime/metrics/reporter.cc
+++ b/runtime/metrics/reporter.cc
@@ -77,6 +77,13 @@
   }
 }
 
+void MetricsReporter::SetCompilationInfo(CompilationReason compilation_reason,
+                                         CompilerFilter::Filter compiler_filter) {
+  if (thread_.has_value()) {
+    messages_.SendMessage(CompilationInfoMessage{compilation_reason, compiler_filter});
+  }
+}
+
 void MetricsReporter::BackgroundThreadRun() {
   LOG_STREAM(DEBUG) << "Metrics reporting thread started";
 
@@ -108,10 +115,7 @@
     messages_.SwitchReceive(
         [&](BeginSessionMessage message) {
           LOG_STREAM(DEBUG) << "Received session metadata";
-
-          for (auto& backend : backends_) {
-            backend->BeginSession(message.session_data);
-          }
+          session_data_ = message.session_data;
         },
         [&]([[maybe_unused]] ShutdownRequestedMessage message) {
           LOG_STREAM(DEBUG) << "Shutdown request received";
@@ -139,6 +143,11 @@
         [&]([[maybe_unused]] StartupCompletedMessage message) {
           LOG_STREAM(DEBUG) << "App startup completed, reporting metrics";
           ReportMetrics();
+        },
+        [&](CompilationInfoMessage message) {
+          LOG_STREAM(DEBUG) << "Compilation info received";
+          session_data_.compilation_reason = message.compilation_reason;
+          session_data_.compiler_filter = message.compiler_filter;
         });
   }
 
@@ -154,9 +163,16 @@
   }
 }
 
-void MetricsReporter::ReportMetrics() const {
+void MetricsReporter::ReportMetrics() {
   ArtMetrics* metrics{runtime_->GetMetrics()};
 
+  if (!session_started_) {
+    for (auto& backend : backends_) {
+      backend->BeginSession(session_data_);
+    }
+    session_started_ = true;
+  }
+
   for (auto& backend : backends_) {
     metrics->ReportAllMetrics(backend.get());
   }
diff --git a/runtime/metrics/reporter.h b/runtime/metrics/reporter.h
index eff6e47..3ad55b0 100644
--- a/runtime/metrics/reporter.h
+++ b/runtime/metrics/reporter.h
@@ -83,6 +83,9 @@
   // If synchronous is set to true, this function will block until the report has completed.
   void RequestMetricsReport(bool synchronous = true);
 
+  void SetCompilationInfo(CompilationReason compilation_reason,
+                          CompilerFilter::Filter compiler_filter);
+
   static constexpr const char* kBackgroundThreadName = "Metrics Background Reporting Thread";
 
  private:
@@ -95,7 +98,7 @@
   void MaybeResetTimeout();
 
   // Outputs the current state of the metrics to the destination set by config_.
-  void ReportMetrics() const;
+  void ReportMetrics();
 
   ReportingConfig config_;
   Runtime* runtime_;
@@ -122,16 +125,25 @@
     bool synchronous;
   };
 
+  struct CompilationInfoMessage {
+    CompilationReason compilation_reason;
+    CompilerFilter::Filter compiler_filter;
+  };
+
   MessageQueue<ShutdownRequestedMessage,
                StartupCompletedMessage,
                BeginSessionMessage,
-               RequestMetricsReportMessage>
+               RequestMetricsReportMessage,
+               CompilationInfoMessage>
       messages_;
 
   // A message indicating a requested report has been finished.
   struct ReportCompletedMessage {};
 
   MessageQueue<ReportCompletedMessage> thread_to_host_messages_;
+
+  SessionData session_data_{};
+  bool session_started_{false};
 };
 
 }  // namespace metrics
diff --git a/runtime/metrics/statsd.cc b/runtime/metrics/statsd.cc
index 39836e2..7dc2300 100644
--- a/runtime/metrics/statsd.cc
+++ b/runtime/metrics/statsd.cc
@@ -117,8 +117,6 @@
       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_AB_OTA;
     case CompilationReason::kBgDexopt:
       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BG_DEXOPT;
-    case CompilationReason::kBoot:
-      return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BOOT;
     case CompilationReason::kError:
       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_ERROR;
     case CompilationReason::kFirstBoot:
@@ -132,6 +130,23 @@
           ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA;
     case CompilationReason::kShared:
       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_SHARED;
+    case CompilationReason::kPostBoot:
+      return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_POST_BOOT;
+    case CompilationReason::kInstallBulk:
+      return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK;
+    case CompilationReason::kInstallBulkSecondary:
+      return statsd::
+          ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY;
+    case CompilationReason::kInstallBulkDowngraded:
+      return statsd::
+          ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED;
+    case CompilationReason::kInstallBulkSecondaryDowngraded:
+      return statsd::
+          ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
+    case CompilationReason::kBootAfterOTA:
+      return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BOOT_AFTER_OTA;
+    case CompilationReason::kInstallFast:
+      return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_FAST;
   }
 }
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 6e7167d..4c4567a 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -3063,6 +3063,13 @@
   ProfileSaver::NotifyStartupCompleted();
 
   if (metrics_reporter_ != nullptr) {
+    const OatFile* primary_oat_file = oat_file_manager_->GetPrimaryOatFile();
+    DCHECK_NE(primary_oat_file, nullptr);
+    const char* compilation_reason = primary_oat_file->GetCompilationReason();
+    metrics_reporter_->SetCompilationInfo(
+        compilation_reason != nullptr ? metrics::CompilationReasonFromName(compilation_reason) :
+                                        metrics::CompilationReason::kUnknown,
+        primary_oat_file->GetCompilerFilter());
     metrics_reporter_->NotifyStartupCompleted();
   }
 }