Revert^2 "[metrics] Add StatsdBackend"

Adds a new backend that allows reporting ART's metrics to statsd, where
they can then be uploaded to Westworld.

Manual Testing Instructions:

Run the following commands.

    m statsd_testdrive
    adb shell setprop dalvik.vm.extra-opts              \
                      -Xwrite-metrics-to-statsd\\\      \
                      -Xwrite-metrics-to-log\\\         \
                      -Xmetrics-reporting-period=10
    adb shell stop && adb shell start
    statsd_testdrive 332

After about a minute, you should see several atoms logged from ART.

This reverts commit dbad1ef673140c66cdbcbbf40424674ae8e2b4c8.
Reason for revert: Added statsd apex to prebuilts

Bug: 178236337
Test: Manual, see above
Test: see instructions on https://r.android.com/1591932
Change-Id: I2071983c04c51efe88df6a56c59fc418fe6e9424
diff --git a/libartbase/base/metrics/metrics.h b/libartbase/base/metrics/metrics.h
index 3ea19c8..9345565 100644
--- a/libartbase/base/metrics/metrics.h
+++ b/libartbase/base/metrics/metrics.h
@@ -158,7 +158,7 @@
 
  protected:
   // Called by the metrics reporter to indicate that a new metrics report is starting.
-  virtual void BeginReport(uint64_t timestamp_millis) = 0;
+  virtual void BeginReport(uint64_t timestamp_since_start_ms) = 0;
 
   // Called by the metrics reporter to give the current value of the counter with id counter_type.
   //
@@ -442,6 +442,14 @@
 // Returns a human readable name for the given DatumId.
 std::string DatumName(DatumId datum);
 
+// We also log the thread type for metrics so we can distinguish things that block the UI thread
+// from things that happen on the background thread. This enum keeps track of what thread types we
+// support.
+enum class ThreadType {
+  kMain,
+  kBackground,
+};
+
 }  // namespace metrics
 }  // namespace art
 
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index c9e5809..bb8fa3b 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -45,7 +45,7 @@
 #include "gc/system_weak.h"
 #include "gc_root-inl.h"
 #include "jni/jni_internal.h"
-#include "metrics_reporter.h"
+#include "metrics/reporter.h"
 #include "mirror/class.h"
 #include "mirror/object-inl.h"
 #include "mirror/string.h"
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 9019d1e..913a32f 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -164,7 +164,7 @@
         "jni/jni_internal.cc",
         "linear_alloc.cc",
         "method_handles.cc",
-        "metrics_reporter.cc",
+        "metrics/reporter.cc",
         "mirror/array.cc",
         "mirror/class.cc",
         "mirror/class_ext.cc",
@@ -373,12 +373,17 @@
                 "monitor_android.cc",
                 "runtime_android.cc",
                 "thread_android.cc",
+                "metrics/statsd.cc",
             ],
             shared_libs: [
                 "libdl_android",
                 "libicu",
+                "libstatssocket",
                 "libz", // For adler32.
             ],
+            static_libs: [
+                "libstatslog_art",
+            ],
         },
         android_arm: {
             ldflags: JIT_DEBUG_REGISTER_CODE_LDFLAGS,
@@ -868,3 +873,41 @@
     ],
     cmd: "$(location interpreter/mterp/gen_mterp.py) $(out) $(in)",
 }
+
+cc_library_static {
+    name: "libstatslog_art",
+    generated_sources: ["statslog_art.cpp"],
+    generated_headers: ["statslog_art.h"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    export_generated_headers: ["statslog_art.h"],
+    shared_libs: [
+        "liblog",
+        "libstatssocket",
+        "libutils",
+    ],
+    apex_available: [
+        "com.android.art",
+        "com.android.art.debug",
+    ],
+}
+
+genrule {
+    name: "statslog_art.h",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog_art.h --module art --namespace art,metrics,statsd",
+    out: [
+        "statslog_art.h",
+    ],
+}
+
+genrule {
+    name: "statslog_art.cpp",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog_art.cpp --module art --namespace art,metrics,statsd --importHeader statslog_art.h",
+    out: [
+        "statslog_art.cpp",
+    ],
+}
diff --git a/runtime/metrics_reporter.cc b/runtime/metrics/reporter.cc
similarity index 95%
rename from runtime/metrics_reporter.cc
rename to runtime/metrics/reporter.cc
index 2004c7d..a393f1b 100644
--- a/runtime/metrics_reporter.cc
+++ b/runtime/metrics/reporter.cc
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-#include "metrics_reporter.h"
+#include "reporter.h"
 
 #include "runtime.h"
 #include "runtime_options.h"
+#include "statsd.h"
 #include "thread-current-inl.h"
 
 #pragma clang diagnostic push
@@ -75,6 +76,9 @@
   if (config_.dump_to_file.has_value()) {
     backends_.emplace_back(new FileBackend(config_.dump_to_file.value()));
   }
+  if (config_.dump_to_statsd) {
+    backends_.emplace_back(CreateStatsdBackend());
+  }
 
   MaybeResetTimeout();
 
@@ -133,6 +137,7 @@
   using M = RuntimeArgumentMap;
   return {
       .dump_to_logcat = args.Exists(M::WriteMetricsToLog),
+      .dump_to_statsd = args.Exists(M::WriteMetricsToStatsd),
       .dump_to_file = args.GetOptional(M::WriteMetricsToFile),
       .report_metrics_on_shutdown = !args.Exists(M::DisableFinalMetricsReport),
       .periodic_report_seconds = args.GetOptional(M::MetricsReportingPeriod),
diff --git a/runtime/metrics_reporter.h b/runtime/metrics/reporter.h
similarity index 93%
rename from runtime/metrics_reporter.h
rename to runtime/metrics/reporter.h
index a9cd1f3..ee0d13a 100644
--- a/runtime/metrics_reporter.h
+++ b/runtime/metrics/reporter.h
@@ -33,6 +33,9 @@
   // Causes metrics to be written to the log, which makes them show up in logcat.
   bool dump_to_logcat{false};
 
+  // Causes metrics to be written to statsd, which causes them to be uploaded to Westworld.
+  bool dump_to_statsd{false};
+
   // If set, provides a file name to enable metrics logging to a file.
   std::optional<std::string> dump_to_file;
 
@@ -45,7 +48,9 @@
   std::optional<unsigned int> periodic_report_seconds;
 
   // Returns whether any options are set that enables metrics reporting.
-  constexpr bool ReportingEnabled() const { return dump_to_logcat || dump_to_file.has_value(); }
+  constexpr bool ReportingEnabled() const {
+    return dump_to_logcat || dump_to_file.has_value() || dump_to_statsd;
+  }
 };
 
 // MetricsReporter handles periodically reporting ART metrics.
diff --git a/runtime/metrics/statsd.cc b/runtime/metrics/statsd.cc
new file mode 100644
index 0000000..ea6cd5c
--- /dev/null
+++ b/runtime/metrics/statsd.cc
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2021 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 "statsd.h"
+
+#include "base/compiler_filter.h"
+#include "base/metrics/metrics.h"
+#include "statslog_art.h"
+
+#pragma clang diagnostic push
+#pragma clang diagnostic error "-Wconversion"
+
+namespace art {
+namespace metrics {
+
+namespace {
+
+// EncodeDatumId returns a std::optional that provides a enum value from atoms.proto if the datum is
+// one that we support logging to statsd. The list of datums that ART collects is a superset of what
+// we report to statsd. Therefore, we only have mappings for the DatumIds that statsd recognizes.
+//
+// Other code can use whether the result of this function has a value to decide whether to report
+// the atom to statsd.
+//
+// To report additional measurements to statsd, first add an entry in atoms.proto and then add an
+// entry to this function as well.
+constexpr std::optional<int32_t> EncodeDatumId(DatumId datum_id) {
+  switch (datum_id) {
+    case DatumId::kClassVerificationTotalTime:
+      return std::make_optional(
+          statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_CLASS_VERIFICATION_TIME);
+    case DatumId::kJitMethodCompileTime:
+      return std::make_optional(
+          statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_JIT_METHOD_COMPILE_TIME);
+    default:
+      return std::nullopt;
+  }
+}
+
+constexpr int32_t EncodeCompileFilter(std::optional<CompilerFilter::Filter> filter) {
+  if (filter.has_value()) {
+    switch (filter.value()) {
+      case CompilerFilter::kAssumeVerified:
+        return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_ASSUMED_VERIFIED;
+      case CompilerFilter::kExtract:
+        return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EXTRACT;
+      case CompilerFilter::kVerify:
+        return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_VERIFY;
+      case CompilerFilter::kSpaceProfile:
+        return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE_PROFILE;
+      case CompilerFilter::kSpace:
+        return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE;
+      case CompilerFilter::kSpeedProfile:
+        return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED_PROFILE;
+      case CompilerFilter::kSpeed:
+        return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED;
+      case CompilerFilter::kEverythingProfile:
+        return statsd::
+            ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING_PROFILE;
+      case CompilerFilter::kEverything:
+        return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING;
+    }
+  } else {
+    return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN;
+  }
+}
+
+constexpr int32_t EncodeCompilationReason(CompilationReason reason) {
+  switch (reason) {
+    case CompilationReason::kUnknown:
+      return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN;
+    case CompilationReason::kABOTA:
+      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:
+      return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_FIRST_BOOT;
+    case CompilationReason::kInactive:
+      return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INACTIVE;
+    case CompilationReason::kInstall:
+      return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL;
+    case CompilationReason::kInstallWithDexMetadata:
+      return statsd::
+          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;
+  }
+}
+
+class StatsdBackend : public MetricsBackend {
+ public:
+  void BeginSession(const SessionData& session_data) override { session_data_ = session_data; }
+
+ protected:
+  void BeginReport(uint64_t timestamp_since_start_ms) override {
+    current_timestamp_ = static_cast<int64_t>(timestamp_since_start_ms);
+  }
+
+  void ReportCounter(DatumId counter_type, uint64_t value) override {
+    std::optional<int32_t> datum_id = EncodeDatumId(counter_type);
+    if (datum_id.has_value()) {
+      statsd::stats_write(
+          statsd::ART_DATUM_REPORTED,
+          session_data_.session_id,
+          session_data_.uid,
+          EncodeCompileFilter(session_data_.compiler_filter),
+          EncodeCompilationReason(session_data_.compilation_reason),
+          current_timestamp_,
+          /*thread_type=*/0,  // TODO: collect and report thread type (0 means UNKNOWN, but that
+                              // constant is not present in all branches)
+          datum_id.value(),
+          static_cast<int64_t>(value),
+          statsd::ART_DATUM_REPORTED__DEX_METADATA_TYPE__UNKNOWN_DEX_METADATA);
+    }
+  }
+
+  void ReportHistogram(DatumId /*histogram_type*/,
+                       int64_t /*low_value*/,
+                       int64_t /*high_value*/,
+                       const std::vector<uint32_t>& /*buckets*/) override {
+    // TODO: implement this once ArtDatumReported in atoms.proto supports histograms.
+    LOG_STREAM(DEBUG) << "Attempting to write histogram to statsd. This is not supported yet.";
+  }
+
+  void EndReport() override {}
+
+ private:
+  SessionData session_data_;
+  // The timestamp provided to the last call to BeginReport
+  int64_t current_timestamp_;
+};
+
+}  // namespace
+
+std::unique_ptr<MetricsBackend> CreateStatsdBackend() { return std::make_unique<StatsdBackend>(); }
+
+}  // namespace metrics
+}  // namespace art
+
+#pragma clang diagnostic pop  // -Wconversion
diff --git a/runtime/metrics/statsd.h b/runtime/metrics/statsd.h
new file mode 100644
index 0000000..a99d510
--- /dev/null
+++ b/runtime/metrics/statsd.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#ifndef ART_RUNTIME_METRICS_STATSD_H_
+#define ART_RUNTIME_METRICS_STATSD_H_
+
+#include <memory>
+
+namespace art {
+namespace metrics {
+
+class MetricsBackend;
+
+// Statsd is only supported on Android
+#ifdef __ANDROID__
+std::unique_ptr<MetricsBackend> CreateStatsdBackend();
+#else
+inline std::unique_ptr<MetricsBackend> CreateStatsdBackend() { return nullptr; }
+#endif
+
+}  // namespace metrics
+}  // namespace art
+
+#endif  // ART_RUNTIME_METRICS_STATSD_H_
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index b7a2b66..fa52139 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -397,6 +397,9 @@
       .Define("-Xwrite-metrics-to-log")
           .WithHelp("Enables writing ART metrics to logcat")
           .IntoKey(M::WriteMetricsToLog)
+      .Define("-Xwrite-metrics-to-statsd")
+          .WithHelp("Enables writing ART metrics to statsd")
+          .IntoKey(M::WriteMetricsToStatsd)
       .Define("-Xwrite-metrics-to-file=_")
           .WithHelp("Enables writing ART metrics to the given file")
           .WithType<std::string>()
diff --git a/runtime/runtime.h b/runtime/runtime.h
index b00ab6c..4d93c64 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -41,7 +41,7 @@
 #include "jdwp_provider.h"
 #include "jni/jni_id_manager.h"
 #include "jni_id_type.h"
-#include "metrics_reporter.h"
+#include "metrics/reporter.h"
 #include "obj_ptr.h"
 #include "offsets.h"
 #include "process_state.h"
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 1961113..9552d50 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -186,8 +186,9 @@
 // This is to enable/disable Perfetto Java Heap Stack Profiling
 RUNTIME_OPTIONS_KEY (bool,                PerfettoJavaHeapStackProf,      false)
 
-// Whether to dump ART metrics to logcat
+// Metrics configuration settings
 RUNTIME_OPTIONS_KEY (Unit,                WriteMetricsToLog)
+RUNTIME_OPTIONS_KEY (Unit,                WriteMetricsToStatsd)
 RUNTIME_OPTIONS_KEY (std::string,         WriteMetricsToFile)
 RUNTIME_OPTIONS_KEY (Unit,                DisableFinalMetricsReport)
 RUNTIME_OPTIONS_KEY (unsigned int,        MetricsReportingPeriod)
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index f6d377d..2453ca1 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -78,6 +78,7 @@
   "com.android.i18n"
   "com.android.runtime"
   "com.android.tzdata"
+  "com.android.os.statsd"
 )
 
 if [[ $mode == "host" ]]; then
diff --git a/tools/buildbot-sync.sh b/tools/buildbot-sync.sh
index 55bd3b7..0e79883 100755
--- a/tools/buildbot-sync.sh
+++ b/tools/buildbot-sync.sh
@@ -76,7 +76,6 @@
 # Create the framework directory if it doesn't exist. Some gtests need it.
 adb shell mkdir -p "$ART_TEST_CHROOT/system/framework"
 
-
 # APEX packages activation.
 # -------------------------
 
@@ -108,3 +107,4 @@
 activate_apex com.android.runtime
 activate_apex com.android.tzdata
 activate_apex com.android.conscrypt
+activate_apex com.android.os.statsd