metricsd: Allows introspecting the metrics.

This CL adds a dump command to metrics_client that will dump the
histograms, aggregated by metricsd since it started, in a human readable
format.
This is useful for developers to ensure that their code uses libmetrics
correctly and the reported values are correct.

Sample output (redacted to fit the commit message):
$ metrics_client -d
Histogram: hello recorded 5 samples, average = 54.8 (flags = 0x1)
0   ...
9   --------O                 (1 = 20.0%) {0.0%}
16  O                         (0 = 0.0%) {20.0%}
29  --------O                 (1 = 20.0%) {20.0%}
54  ------------------------O (3 = 60.0%) {40.0%}
100 O                         (0 = 0.0%) {100.0%}
$

Bug: 25817310
Test: * Send a histogram with metrics_client.
      * `metrics_client -d` shows it.

Change-Id: Id186dc5463403ca9181ee9eef8f46b5e809b8714
diff --git a/metricsd/aidl/android/brillo/metrics/IMetricsd.aidl b/metricsd/aidl/android/brillo/metrics/IMetricsd.aidl
index a92ff46..aa3cb34 100644
--- a/metricsd/aidl/android/brillo/metrics/IMetricsd.aidl
+++ b/metricsd/aidl/android/brillo/metrics/IMetricsd.aidl
@@ -22,4 +22,5 @@
   oneway void recordLinearHistogram(String name, int sample, int max);
   oneway void recordSparseHistogram(String name, int sample);
   oneway void recordCrash(String type);
+  String getHistogramsDump();
 }
diff --git a/metricsd/include/metrics/metrics_library.h b/metricsd/include/metrics/metrics_library.h
index e160657..a1bb926 100644
--- a/metricsd/include/metrics/metrics_library.h
+++ b/metricsd/include/metrics/metrics_library.h
@@ -125,6 +125,11 @@
   // number in the histograms dashboard).
   bool SendCrosEventToUMA(const std::string& event);
 
+  // Debugging only.
+  // Dumps the histograms aggregated since metricsd started into |dump|.
+  // Returns true iff the dump succeeds.
+  bool GetHistogramsDump(std::string* dump);
+
  private:
   friend class CMetricsLibraryTest;
   friend class MetricsLibraryTest;
diff --git a/metricsd/metrics_client.cc b/metricsd/metrics_client.cc
index a2cc38f..c66b975 100644
--- a/metricsd/metrics_client.cc
+++ b/metricsd/metrics_client.cc
@@ -17,12 +17,11 @@
 #include <cstdio>
 #include <cstdlib>
 
-#include <base/memory/scoped_vector.h>
-
 #include "constants.h"
 #include "metrics/metrics_library.h"
 
 enum Mode {
+    kModeDumpHistograms,
     kModeSendSample,
     kModeSendEnumSample,
     kModeSendSparseSample,
@@ -43,6 +42,7 @@
           "           |min| > 0, |min| <= sample < |max|\n"
           "  -c: return exit status 0 if user consents to stats, 1 otherwise,\n"
           "      in guest mode always return 1\n"
+          "  -d: dump the histograms recorded by metricsd to stdout\n"
           "  -e: send linear/enumeration histogram data\n"
           "  -g: return exit status 0 if machine in guest mode, 1 otherwise\n"
           "  -s: send a sparse histogram sample\n"
@@ -71,6 +71,20 @@
   return value;
 }
 
+static int DumpHistograms() {
+  MetricsLibrary metrics_lib;
+  metrics_lib.Init();
+
+  std::string dump;
+  if (!metrics_lib.GetHistogramsDump(&dump)) {
+    printf("Failed to dump the histograms.");
+    return 1;
+  }
+
+  printf("%s\n", dump.c_str());
+  return 0;
+}
+
 static int SendStats(char* argv[],
                      int name_index,
                      enum Mode mode,
@@ -130,11 +144,14 @@
 
   // Parse arguments
   int flag;
-  while ((flag = getopt(argc, argv, "abcegstv")) != -1) {
+  while ((flag = getopt(argc, argv, "abcdegstv")) != -1) {
     switch (flag) {
       case 'c':
         mode = kModeHasConsent;
         break;
+      case 'd':
+        mode = kModeDumpHistograms;
+        break;
       case 'e':
         mode = kModeSendEnumSample;
         break;
@@ -172,6 +189,8 @@
   }
 
   switch (mode) {
+    case kModeDumpHistograms:
+      return DumpHistograms();
     case kModeSendSample:
     case kModeSendEnumSample:
     case kModeSendSparseSample:
diff --git a/metricsd/metrics_library.cc b/metricsd/metrics_library.cc
index 263c310..d211ab4 100644
--- a/metricsd/metrics_library.cc
+++ b/metricsd/metrics_library.cc
@@ -213,3 +213,14 @@
   }
   return false;
 }
+
+bool MetricsLibrary::GetHistogramsDump(std::string* dump) {
+  android::String16 temp_dump;
+  if (!CheckService() ||
+      !metricsd_proxy_->getHistogramsDump(&temp_dump).isOk()) {
+    return false;
+  }
+
+  *dump = android::String8(temp_dump).string();
+  return true;
+}
diff --git a/metricsd/uploader/bn_metricsd_impl.cc b/metricsd/uploader/bn_metricsd_impl.cc
index 1e38002..113a705 100644
--- a/metricsd/uploader/bn_metricsd_impl.cc
+++ b/metricsd/uploader/bn_metricsd_impl.cc
@@ -18,6 +18,7 @@
 
 #include <base/metrics/histogram.h>
 #include <base/metrics/sparse_histogram.h>
+#include <base/metrics/statistics_recorder.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <utils/String16.h>
@@ -96,3 +97,10 @@
   }
   return Status::ok();
 }
+
+Status BnMetricsdImpl::getHistogramsDump(String16* dump) {
+  std::string str_dump;
+  base::StatisticsRecorder::WriteGraph(std::string(), &str_dump);
+  *dump = String16(str_dump.c_str());
+  return Status::ok();
+}
diff --git a/metricsd/uploader/bn_metricsd_impl.h b/metricsd/uploader/bn_metricsd_impl.h
index c6e3d36..016ccb6 100644
--- a/metricsd/uploader/bn_metricsd_impl.h
+++ b/metricsd/uploader/bn_metricsd_impl.h
@@ -47,6 +47,9 @@
   // Records a crash.
   android::binder::Status recordCrash(const android::String16& type) override;
 
+  // Returns a dump of the histograms aggregated in memory.
+  android::binder::Status getHistogramsDump(android::String16* dump) override;
+
  private:
   std::shared_ptr<CrashCounters> counters_;
 };