Allow multiple output formats for runtime metrics

* Add base abstract class MetricsFormatter
* Extract current formatting into TextFormatter
* Add XmlFormatter for XML output format
* Add command line flag for xml format

Test: test.py (gTests)
Test: atest art_standalone_libartbase_tests
Test: art/build/apex/runtests.sh
Bug: 175048705

Size of APEX files:
* before the changes:
  * com.android.art.apex: 61,001,728 bytes (59 MB)
  * com.android.art.capex: 22,757,376 bytes (22 MB)

* after the changes:
  * com.android.art.apex: 60,928,000 bytes (-73,728 bytes)
  * com.android.art.capex: 22,728,704 bytes (-28,672 bytes)

Change-Id: Ie80abaf67ffc721d7da59b8115f655630b21cae4
diff --git a/libartbase/base/metrics/metrics.h b/libartbase/base/metrics/metrics.h
index 701054e..4a1664a 100644
--- a/libartbase/base/metrics/metrics.h
+++ b/libartbase/base/metrics/metrics.h
@@ -30,6 +30,7 @@
 #include "android-base/logging.h"
 #include "base/bit_utils.h"
 #include "base/time_utils.h"
+#include "tinyxml2.h"
 
 #pragma clang diagnostic push
 #pragma clang diagnostic error "-Wconversion"
@@ -433,12 +434,80 @@
   friend class ArtMetrics;
 };
 
-// A backend that writes metrics in a human-readable format to a string.
+// Base class for formatting metrics into different formats
+// (human-readable text, JSON, etc.)
+class MetricsFormatter {
+ public:
+  virtual ~MetricsFormatter() = default;
+
+  virtual void FormatBeginReport(uint64_t timestamp_since_start_ms,
+                                 const std::optional<SessionData>& session_data) = 0;
+  virtual void FormatEndReport() = 0;
+  virtual void FormatReportCounter(DatumId counter_type, uint64_t value) = 0;
+  virtual void FormatReportHistogram(DatumId histogram_type,
+                                     int64_t low_value,
+                                     int64_t high_value,
+                                     const std::vector<uint32_t>& buckets) = 0;
+  virtual std::string GetAndResetBuffer() = 0;
+
+ protected:
+  const std::string version = "1.0";
+};
+
+// Formatter outputting metrics in human-readable text format
+class TextFormatter : public MetricsFormatter {
+ public:
+  TextFormatter() = default;
+
+  void FormatBeginReport(uint64_t timestamp_millis,
+                         const std::optional<SessionData>& session_data) override;
+
+  void FormatReportCounter(DatumId counter_type, uint64_t value) override;
+
+  void FormatReportHistogram(DatumId histogram_type,
+                             int64_t low_value,
+                             int64_t high_value,
+                             const std::vector<uint32_t>& buckets) override;
+
+  void FormatEndReport() override;
+
+  std::string GetAndResetBuffer() override;
+
+ private:
+  std::ostringstream os_;
+};
+
+// Formatter outputting metrics in XML format
+class XmlFormatter : public MetricsFormatter {
+ public:
+  XmlFormatter() = default;
+
+  void FormatBeginReport(uint64_t timestamp_millis,
+                         const std::optional<SessionData>& session_data) override;
+
+  void FormatReportCounter(DatumId counter_type, uint64_t value) override;
+
+  void FormatReportHistogram(DatumId histogram_type,
+                             int64_t low_value,
+                             int64_t high_value,
+                             const std::vector<uint32_t>& buckets) override;
+
+  void FormatEndReport() override;
+
+  std::string GetAndResetBuffer() override;
+
+ private:
+  tinyxml2::XMLDocument document_;
+};
+
+// A backend that writes metrics to a string.
+// The format of the metrics' output is delegated
+// to the MetricsFormatter class.
 //
 // This is used as a base for LogBackend and FileBackend.
 class StringBackend : public MetricsBackend {
  public:
-  StringBackend();
+  explicit StringBackend(std::unique_ptr<MetricsFormatter> formatter);
 
   void BeginOrUpdateSession(const SessionData& session_data) override;
 
@@ -456,14 +525,15 @@
   std::string GetAndResetBuffer();
 
  private:
-  std::ostringstream os_;
+  std::unique_ptr<MetricsFormatter> formatter_;
   std::optional<SessionData> session_data_;
 };
 
 // A backend that writes metrics in human-readable format to the log (i.e. logcat).
 class LogBackend : public StringBackend {
  public:
-  explicit LogBackend(android::base::LogSeverity level);
+  explicit LogBackend(std::unique_ptr<MetricsFormatter> formatter,
+                      android::base::LogSeverity level);
 
   void BeginReport(uint64_t timestamp_millis) override;
   void EndReport() override;
@@ -473,12 +543,10 @@
 };
 
 // A backend that writes metrics to a file.
-//
-// These are currently written in the same human-readable format used by StringBackend and
-// LogBackend, but we will probably want a more machine-readable format in the future.
 class FileBackend : public StringBackend {
  public:
-  explicit FileBackend(const std::string& filename);
+  explicit FileBackend(std::unique_ptr<MetricsFormatter> formatter,
+                       const std::string& filename);
 
   void BeginReport(uint64_t timestamp_millis) override;
   void EndReport() override;