Add StatsdStats and guardrail.

+ StatsdStats is the global class that tracks the stats about statsd.

+ Added guardrail for classes that have a map which could potentially grow
  unboundedly with the number of logs.

TODO: add unit tests & CTS for StatsdStats, and guardrail
      add stats for pulled atoms.

Test: statsd_test

Change-Id: I0ea562de4dd3f6162f7923a9c193420b482c1d51
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 149b9c1..ce60eb9 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -18,6 +18,7 @@
 #include "Log.h"
 
 #include "CountMetricProducer.h"
+#include "guardrail/StatsdStats.h"
 #include "stats_util.h"
 
 #include <limits.h>
@@ -63,10 +64,11 @@
 
 // TODO: add back AnomalyTracker.
 
-CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex,
+CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric& metric,
+                                         const int conditionIndex,
                                          const sp<ConditionWizard>& wizard,
                                          const uint64_t startTimeNs)
-    : MetricProducer(startTimeNs, conditionIndex, wizard), mMetric(metric) {
+    : MetricProducer(key, startTimeNs, conditionIndex, wizard), mMetric(metric) {
     // TODO: evaluate initial conditions. and set mConditionMet.
     if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
         mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000;
@@ -180,6 +182,26 @@
     mCondition = conditionMet;
 }
 
+bool CountMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) {
+    if (mCurrentSlicedCounter->find(newKey) != mCurrentSlicedCounter->end()) {
+        return false;
+    }
+    // ===========GuardRail==============
+    // 1. Report the tuple count if the tuple count > soft limit
+    if (mCurrentSlicedCounter->size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
+        size_t newTupleCount = mCurrentSlicedCounter->size() + 1;
+        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetric.name(),
+                                                           newTupleCount);
+        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
+        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
+            ALOGE("CountMetric %s dropping data for dimension key %s", mMetric.name().c_str(),
+                  newKey.c_str());
+            return true;
+        }
+    }
+
+    return false;
+}
 void CountMetricProducer::onMatchedLogEventInternal(
         const size_t matcherIndex, const HashableDimensionKey& eventKey,
         const map<string, HashableDimensionKey>& conditionKey, bool condition,
@@ -195,6 +217,11 @@
     auto it = mCurrentSlicedCounter->find(eventKey);
 
     if (it == mCurrentSlicedCounter->end()) {
+        // ===========GuardRail==============
+        if (hitGuardRail(eventKey)) {
+            return;
+        }
+
         // create a counter for the new key
         (*mCurrentSlicedCounter)[eventKey] = 1;
     } else {