Splits AnomalyTracker into two files

Splits out DurationAnomalyTracker-specific functions into their own
subclass.

Test: the unit tests and CTS tests
Change-Id: Id6eb74d232b4a9c3a932d805d1ba3f0ba43a88b1
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index f98ee3d..c392540 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -22,6 +22,7 @@
     src/atoms.proto \
     src/anomaly/AnomalyMonitor.cpp \
     src/anomaly/AnomalyTracker.cpp \
+    src/anomaly/DurationAnomalyTracker.cpp \
     src/condition/CombinationConditionTracker.cpp \
     src/condition/condition_util.cpp \
     src/condition/SimpleConditionTracker.cpp \
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 0c078d5..5f9b53a 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -81,6 +81,9 @@
 void StatsLogProcessor::onAnomalyAlarmFired(
         const uint64_t timestampNs,
         unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet) {
+    // TODO: This is a thread-safety issue. mMetricsManagers could change under our feet.
+    // TODO: Solution? Lock everything! :(
+    // TODO: Question: Can we replace the other lock (broadcast), or do we need to supplement it?
     for (const auto& itr : mMetricsManagers) {
         itr.second->onAnomalyAlarmFired(timestampNs, anomalySet);
     }
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 162a34b..f8a9413 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -30,8 +30,6 @@
 namespace os {
 namespace statsd {
 
-// TODO: Separate DurationAnomalyTracker as a separate subclass and let each MetricProducer
-//       decide and let which one it wants.
 // TODO: Get rid of bucketNumbers, and return to the original circular array method.
 AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
     : mAlert(alert),
@@ -52,7 +50,6 @@
 
 AnomalyTracker::~AnomalyTracker() {
     VLOG("~AnomalyTracker() called");
-    stopAllAlarms();
 }
 
 void AnomalyTracker::resetStorage() {
@@ -61,8 +58,6 @@
     // Excludes the current bucket.
     mPastBuckets.resize(mNumOfPastBuckets);
     mSumOverPastBuckets.clear();
-
-    if (!mAlarms.empty()) VLOG("AnomalyTracker.resetStorage() called but mAlarms is NOT empty!");
 }
 
 size_t AnomalyTracker::index(int64_t bucketNum) const {
@@ -205,23 +200,22 @@
         return;
     }
     // TODO(guardrail): Consider guarding against too short refractory periods.
-    mLastAlarmTimestampNs = timestampNs;
-
+    mLastAnomalyTimestampNs = timestampNs;
 
     // TODO: If we had access to the bucket_size_millis, consider calling resetStorage()
     // if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) { resetStorage(); }
 
     if (mAlert.has_incidentd_details()) {
         if (mAlert.has_name()) {
-            ALOGW("An anomaly (%s) has occurred! Informing incidentd.",
+            ALOGI("An anomaly (%s) has occurred! Informing incidentd.",
                   mAlert.name().c_str());
         } else {
             // TODO: Can construct a name based on the criteria (and/or relay the criteria).
-            ALOGW("An anomaly (nameless) has occurred! Informing incidentd.");
+            ALOGI("An anomaly (nameless) has occurred! Informing incidentd.");
         }
         informIncidentd();
     } else {
-        ALOGW("An anomaly has occurred! (But informing incidentd not requested.)");
+        ALOGI("An anomaly has occurred! (But informing incidentd not requested.)");
     }
 
     StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.name());
@@ -230,20 +224,6 @@
                                mConfigKey.GetName().c_str(), mAlert.name().c_str());
 }
 
-void AnomalyTracker::declareAnomalyIfAlarmExpired(const HashableDimensionKey& dimensionKey,
-                                                  const uint64_t& timestampNs) {
-    auto itr = mAlarms.find(dimensionKey);
-    if (itr == mAlarms.end()) {
-        return;
-    }
-
-    if (itr->second != nullptr &&
-        static_cast<uint32_t>(timestampNs / NS_PER_SEC) >= itr->second->timestampSec) {
-        declareAnomaly(timestampNs);
-        stopAlarm(dimensionKey);
-    }
-}
-
 void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs,
                                              const int64_t& currBucketNum,
                                              const HashableDimensionKey& key,
@@ -261,68 +241,9 @@
     }
 }
 
-void AnomalyTracker::startAlarm(const HashableDimensionKey& dimensionKey,
-                                const uint64_t& timestampNs) {
-    uint32_t timestampSec = static_cast<uint32_t>(timestampNs / NS_PER_SEC);
-    if (isInRefractoryPeriod(timestampNs)) {
-        VLOG("Skipping setting anomaly alarm since it'd fall in the refractory period");
-        return;
-    }
-
-    sp<const AnomalyAlarm> alarm = new AnomalyAlarm{timestampSec};
-    mAlarms.insert({dimensionKey, alarm});
-    if (mAnomalyMonitor != nullptr) {
-        mAnomalyMonitor->add(alarm);
-    }
-}
-
-void AnomalyTracker::stopAlarm(const HashableDimensionKey& dimensionKey) {
-    auto itr = mAlarms.find(dimensionKey);
-    if (itr != mAlarms.end()) {
-        mAlarms.erase(dimensionKey);
-        if (mAnomalyMonitor != nullptr) {
-            mAnomalyMonitor->remove(itr->second);
-        }
-    }
-}
-
-void AnomalyTracker::stopAllAlarms() {
-    std::set<HashableDimensionKey> keys;
-    for (auto itr = mAlarms.begin(); itr != mAlarms.end(); ++itr) {
-        keys.insert(itr->first);
-    }
-    for (auto key : keys) {
-        stopAlarm(key);
-    }
-}
-
-bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs) {
-    return mLastAlarmTimestampNs >= 0 &&
-            timestampNs - mLastAlarmTimestampNs <= mAlert.refractory_period_secs() * NS_PER_SEC;
-}
-
-void AnomalyTracker::informAlarmsFired(const uint64_t& timestampNs,
-        unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
-
-    if (firedAlarms.empty() || mAlarms.empty()) return;
-    // Find the intersection of firedAlarms and mAlarms.
-    // The for loop is inefficient, since it loops over all keys, but that's okay since it is very
-    // seldomly called. The alternative would be having AnomalyAlarms store information about the
-    // AnomalyTracker and key, but that's a lot of data overhead to speed up something that is
-    // rarely ever called.
-    unordered_map<HashableDimensionKey, sp<const AnomalyAlarm>> matchedAlarms;
-    for (const auto& kv : mAlarms) {
-        if (firedAlarms.count(kv.second) > 0) {
-            matchedAlarms.insert({kv.first, kv.second});
-        }
-    }
-
-    // Now declare each of these alarms to have fired.
-    for (const auto& kv : matchedAlarms) {
-        declareAnomaly(timestampNs /* TODO: , kv.first */);
-        mAlarms.erase(kv.first);
-        firedAlarms.erase(kv.second);  // No one else can also own it, so we're done with it.
-    }
+bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs) const {
+    return mLastAnomalyTimestampNs >= 0 &&
+            timestampNs - mLastAnomalyTimestampNs <= mAlert.refractory_period_secs() * NS_PER_SEC;
 }
 
 void AnomalyTracker::informIncidentd() {
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index 874add2..48f0203 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -61,23 +61,11 @@
                                  const HashableDimensionKey& key,
                                  const int64_t& currentBucketValue);
 
-    // Starts the alarm at the given timestamp.
-    void startAlarm(const HashableDimensionKey& dimensionKey, const uint64_t& eventTime);
-    // Stops the alarm.
-    void stopAlarm(const HashableDimensionKey& dimensionKey);
-
-    // Stop all the alarms owned by this tracker.
-    void stopAllAlarms();
-
-    // Init the anmaly monitor which is shared across anomaly trackers.
-    inline void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor) {
-        mAnomalyMonitor = anomalyMonitor;
+    // Init the AnomalyMonitor which is shared across anomaly trackers.
+    virtual void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor) {
+        return; // Base AnomalyTracker class has no need for the AnomalyMonitor.
     }
 
-    // Declares the anomaly when the alarm expired given the current timestamp.
-    void declareAnomalyIfAlarmExpired(const HashableDimensionKey& dimensionKey,
-                                      const uint64_t& timestampNs);
-
     // Helper function to return the sum value of past buckets at given dimension.
     int64_t getSumOverPastBuckets(const HashableDimensionKey& key) const;
 
@@ -89,9 +77,9 @@
         return mAlert.trigger_if_sum_gt();
     }
 
-    // Helper function to return the last alarm timestamp.
-    inline int64_t getLastAlarmTimestampNs() const {
-        return mLastAlarmTimestampNs;
+    // Helper function to return the timestamp of the last detected anomaly.
+    inline int64_t getLastAnomalyTimestampNs() const {
+        return mLastAnomalyTimestampNs;
     }
 
     inline int getNumOfPastBuckets() const {
@@ -100,15 +88,12 @@
 
     // Declares an anomaly for each alarm in firedAlarms that belongs to this AnomalyTracker,
     // and removes it from firedAlarms. Does NOT remove the alarm from the AnomalyMonitor.
-    // TODO: This will actually be called from a different thread, so make it thread-safe!
-    // TODO: Consider having AnomalyMonitor have a reference to each relevant MetricProducer
-    //       instead of calling it from a chain starting at StatsLogProcessor.
-    void informAlarmsFired(const uint64_t& timestampNs,
-            unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms);
+    virtual void informAlarmsFired(const uint64_t& timestampNs,
+            unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
+        return; // The base AnomalyTracker class doesn't have alarms.
+    }
 
 protected:
-    void flushPastBuckets(const int64_t& currBucketNum);
-
     // statsd_config.proto Alert message that defines this tracker.
     const Alert mAlert;
 
@@ -119,13 +104,6 @@
     // for the anomaly detection (since the current bucket is not in the past).
     int mNumOfPastBuckets;
 
-    // The alarms owned by this tracker. The alarm monitor also shares the alarm pointers when they
-    // are still active.
-    std::unordered_map<HashableDimensionKey, sp<const AnomalyAlarm>> mAlarms;
-
-    // Anomaly alarm monitor.
-    sp<AnomalyMonitor> mAnomalyMonitor;
-
     // The exisiting bucket list.
     std::vector<shared_ptr<DimToValMap>> mPastBuckets;
 
@@ -136,7 +114,9 @@
     int64_t mMostRecentBucketNum = -1;
 
     // The timestamp when the last anomaly was declared.
-    int64_t mLastAlarmTimestampNs = -1;
+    int64_t mLastAnomalyTimestampNs = -1;
+
+    void flushPastBuckets(const int64_t& currBucketNum);
 
     // Add the information in the given bucket to mSumOverPastBuckets.
     void addBucketToSum(const shared_ptr<DimToValMap>& bucket);
@@ -145,13 +125,13 @@
     // and remove any items with value 0.
     void subtractBucketFromSum(const shared_ptr<DimToValMap>& bucket);
 
-    bool isInRefractoryPeriod(const uint64_t& timestampNs);
+    bool isInRefractoryPeriod(const uint64_t& timestampNs) const;
 
     // Calculates the corresponding bucket index within the circular array.
     size_t index(int64_t bucketNum) const;
 
     // Resets all bucket data. For use when all the data gets stale.
-    void resetStorage();
+    virtual void resetStorage();
 
     // Informs the incident service that an anomaly has occurred.
     void informIncidentd();
@@ -160,11 +140,6 @@
     FRIEND_TEST(AnomalyTrackerTest, TestSparseBuckets);
     FRIEND_TEST(GaugeMetricProducerTest, TestAnomalyDetection);
     FRIEND_TEST(CountMetricProducerTest, TestAnomalyDetection);
-    FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
-    FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetection);
-    FRIEND_TEST(MaxDurationTrackerTest, TestAnomalyDetection);
-    FRIEND_TEST(MaxDurationTrackerTest, TestAnomalyDetection);
-    FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetection);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
new file mode 100644
index 0000000..d30810f
--- /dev/null
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define DEBUG true  // STOPSHIP if true
+#include "Log.h"
+
+#include "DurationAnomalyTracker.h"
+#include "guardrail/StatsdStats.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+DurationAnomalyTracker::DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey)
+    : AnomalyTracker(alert, configKey) {
+}
+
+DurationAnomalyTracker::~DurationAnomalyTracker() {
+    stopAllAlarms();
+}
+
+void DurationAnomalyTracker::resetStorage() {
+    AnomalyTracker::resetStorage();
+    if (!mAlarms.empty()) VLOG("AnomalyTracker.resetStorage() called but mAlarms is NOT empty!");
+}
+
+void DurationAnomalyTracker::declareAnomalyIfAlarmExpired(const HashableDimensionKey& dimensionKey,
+                                                  const uint64_t& timestampNs) {
+    auto itr = mAlarms.find(dimensionKey);
+    if (itr == mAlarms.end()) {
+        return;
+    }
+
+    if (itr->second != nullptr &&
+        static_cast<uint32_t>(timestampNs / NS_PER_SEC) >= itr->second->timestampSec) {
+        declareAnomaly(timestampNs);
+        stopAlarm(dimensionKey);
+    }
+}
+
+void DurationAnomalyTracker::startAlarm(const HashableDimensionKey& dimensionKey,
+                                const uint64_t& timestampNs) {
+
+    uint32_t timestampSec = static_cast<uint32_t>(timestampNs / NS_PER_SEC);
+    if (isInRefractoryPeriod(timestampNs)) {
+        VLOG("Skipping setting anomaly alarm since it'd fall in the refractory period");
+        return;
+    }
+    sp<const AnomalyAlarm> alarm = new AnomalyAlarm{timestampSec};
+    mAlarms.insert({dimensionKey, alarm});
+    if (mAnomalyMonitor != nullptr) {
+        mAnomalyMonitor->add(alarm);
+    }
+}
+
+void DurationAnomalyTracker::stopAlarm(const HashableDimensionKey& dimensionKey) {
+    auto itr = mAlarms.find(dimensionKey);
+    if (itr != mAlarms.end()) {
+        mAlarms.erase(dimensionKey);
+        if (mAnomalyMonitor != nullptr) {
+            mAnomalyMonitor->remove(itr->second);
+        }
+    }
+}
+
+void DurationAnomalyTracker::stopAllAlarms() {
+    std::set<HashableDimensionKey> keys;
+    for (auto itr = mAlarms.begin(); itr != mAlarms.end(); ++itr) {
+        keys.insert(itr->first);
+    }
+    for (auto key : keys) {
+        stopAlarm(key);
+    }
+}
+
+void DurationAnomalyTracker::informAlarmsFired(const uint64_t& timestampNs,
+        unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
+
+    if (firedAlarms.empty() || mAlarms.empty()) return;
+    // Find the intersection of firedAlarms and mAlarms.
+    // The for loop is inefficient, since it loops over all keys, but that's okay since it is very
+    // seldomly called. The alternative would be having AnomalyAlarms store information about the
+    // DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that is
+    // rarely ever called.
+    unordered_map<HashableDimensionKey, sp<const AnomalyAlarm>> matchedAlarms;
+    for (const auto& kv : mAlarms) {
+        if (firedAlarms.count(kv.second) > 0) {
+            matchedAlarms.insert({kv.first, kv.second});
+        }
+    }
+
+    // Now declare each of these alarms to have fired.
+    for (const auto& kv : matchedAlarms) {
+        declareAnomaly(timestampNs /* TODO: , kv.first */);
+        mAlarms.erase(kv.first);
+        firedAlarms.erase(kv.second);  // No one else can also own it, so we're done with it.
+    }
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
new file mode 100644
index 0000000..182ce3b
--- /dev/null
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include "AnomalyMonitor.h"
+#include "AnomalyTracker.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::unordered_map;
+
+class DurationAnomalyTracker : public virtual AnomalyTracker {
+public:
+    DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey);
+
+    virtual ~DurationAnomalyTracker();
+
+    // Starts the alarm at the given timestamp.
+    void startAlarm(const HashableDimensionKey& dimensionKey, const uint64_t& eventTime);
+
+    // Stops the alarm.
+    void stopAlarm(const HashableDimensionKey& dimensionKey);
+
+    // Stop all the alarms owned by this tracker.
+    void stopAllAlarms();
+
+    // Init the AnomalyMonitor which is shared across anomaly trackers.
+    void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor) override {
+        mAnomalyMonitor = anomalyMonitor;
+    }
+
+    // Declares the anomaly when the alarm expired given the current timestamp.
+    void declareAnomalyIfAlarmExpired(const HashableDimensionKey& dimensionKey,
+                                      const uint64_t& timestampNs);
+
+    // Declares an anomaly for each alarm in firedAlarms that belongs to this DurationAnomalyTracker
+    // and removes it from firedAlarms. Does NOT remove the alarm from the AnomalyMonitor.
+    // TODO: This will actually be called from a different thread, so make it thread-safe!
+    //          This means that almost every function in DurationAnomalyTracker needs to be locked.
+    //          But this should be done at the level of StatsLogProcessor, which needs to lock
+    //          mMetricsMangers anyway.
+    void informAlarmsFired(const uint64_t& timestampNs,
+            unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) override;
+
+protected:
+    // The alarms owned by this tracker. The alarm monitor also shares the alarm pointers when they
+    // are still active.
+    std::unordered_map<HashableDimensionKey, sp<const AnomalyAlarm>> mAlarms;
+
+    // Anomaly alarm monitor.
+    sp<AnomalyMonitor> mAnomalyMonitor;
+
+    // Resets all bucket data. For use when all the data gets stale.
+    void resetStorage() override;
+
+    FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
+    FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetection);
+    FRIEND_TEST(MaxDurationTrackerTest, TestAnomalyDetection);
+    FRIEND_TEST(MaxDurationTrackerTest, TestAnomalyDetection);
+    FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetection);
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 1c8f422..51ea4b5 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -101,15 +101,19 @@
     VLOG("~DurationMetric() called");
 }
 
-sp<AnomalyTracker> DurationMetricProducer::createAnomalyTracker(const Alert &alert) {
+sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(const Alert &alert) {
+    std::lock_guard<std::mutex> lock(mMutex);
     if (alert.trigger_if_sum_gt() > alert.number_of_buckets() * mBucketSizeNs) {
         ALOGW("invalid alert: threshold (%lld) > possible recordable value (%d x %lld)",
               alert.trigger_if_sum_gt(), alert.number_of_buckets(),
               (long long)mBucketSizeNs);
         return nullptr;
     }
-    // TODO: return a DurationAnomalyTracker (which should sublclass AnomalyTracker)
-    return new AnomalyTracker(alert, mConfigKey);
+    sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, mConfigKey);
+    if (anomalyTracker != nullptr) {
+        mAnomalyTrackers.push_back(anomalyTracker);
+    }
+    return anomalyTracker;
 }
 
 unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 7044b4b..abc89bd 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -20,6 +20,7 @@
 #include <unordered_map>
 
 #include <android/util/ProtoOutputStream.h>
+#include "../anomaly/DurationAnomalyTracker.h"
 #include "../condition/ConditionTracker.h"
 #include "../matchers/matcher_util.h"
 #include "MetricProducer.h"
@@ -45,7 +46,7 @@
 
     virtual ~DurationMetricProducer();
 
-    virtual sp<AnomalyTracker> createAnomalyTracker(const Alert &alert) override;
+    sp<AnomalyTracker> addAnomalyTracker(const Alert &alert) override;
 
 protected:
     void onMatchedLogEventInternalLocked(
@@ -98,6 +99,9 @@
     std::unique_ptr<DurationTracker> createDurationTracker(
             const HashableDimensionKey& eventKey) const;
 
+    // This hides the base class's std::vector<sp<AnomalyTracker>> mAnomalyTrackers
+    std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers;
+
     // Util function to check whether the specified dimension hits the guardrail.
     bool hitGuardRailLocked(const HashableDimensionKey& newKey);
 
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 85ef4ad..647d8c1 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -98,13 +98,13 @@
         return byteSizeLocked();
     }
 
-    virtual sp<AnomalyTracker> createAnomalyTracker(const Alert &alert) {
-        return new AnomalyTracker(alert, mConfigKey);
-    }
-
-    void addAnomalyTracker(sp<AnomalyTracker> tracker) {
+    virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert) {
         std::lock_guard<std::mutex> lock(mMutex);
-        mAnomalyTrackers.push_back(tracker);
+        sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, mConfigKey);
+        if (anomalyTracker != nullptr) {
+            mAnomalyTrackers.push_back(anomalyTracker);
+        }
+        return anomalyTracker;
     }
 
     int64_t getBuckeSizeInNs() const {
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 3c714b3..9192d12f 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -17,7 +17,7 @@
 #ifndef DURATION_TRACKER_H
 #define DURATION_TRACKER_H
 
-#include "anomaly/AnomalyTracker.h"
+#include "anomaly/DurationAnomalyTracker.h"
 #include "condition/ConditionWizard.h"
 #include "config/ConfigKey.h"
 #include "stats_util.h"
@@ -63,7 +63,7 @@
     DurationTracker(const ConfigKey& key, const string& name, const HashableDimensionKey& eventKey,
                     sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
                     uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
-                    const std::vector<sp<AnomalyTracker>>& anomalyTrackers)
+                    const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
         : mConfigKey(key),
           mName(name),
           mEventKey(eventKey),
@@ -94,7 +94,7 @@
             std::unordered_map<HashableDimensionKey, std::vector<DurationBucket>>* output) = 0;
 
     // Predict the anomaly timestamp given the current status.
-    virtual int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
+    virtual int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
                                               const uint64_t currentTimestamp) const = 0;
 
 protected:
@@ -163,7 +163,7 @@
 
     uint64_t mCurrentBucketNum;
 
-    std::vector<sp<AnomalyTracker>> mAnomalyTrackers;
+    std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers;
 
     FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
     FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetection);
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index 6050f43..d8a8e23 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -28,7 +28,7 @@
                                        const HashableDimensionKey& eventKey,
                                        sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
                                        uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
-                                       const std::vector<sp<AnomalyTracker>>& anomalyTrackers)
+                                       const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
     : DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
                       bucketSizeNs, anomalyTrackers) {
 }
@@ -281,7 +281,7 @@
     }
 }
 
-int64_t MaxDurationTracker::predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
+int64_t MaxDurationTracker::predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
                                                       const uint64_t currentTimestamp) const {
     ALOGE("Max duration producer does not support anomaly timestamp prediction!!!");
     return currentTimestamp;
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index 10eddb8..76f486e 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -32,7 +32,7 @@
                        const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
                        int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
                        uint64_t bucketSizeNs,
-                       const std::vector<sp<AnomalyTracker>>& anomalyTrackers);
+                       const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers);
     void noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime,
                    const ConditionKey& conditionKey) override;
     void noteStop(const HashableDimensionKey& key, const uint64_t eventTime,
@@ -46,7 +46,7 @@
     void onSlicedConditionMayChange(const uint64_t timestamp) override;
     void onConditionChanged(bool condition, const uint64_t timestamp) override;
 
-    int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
+    int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
                                       const uint64_t currentTimestamp) const override;
 
 private:
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index 5c43096..c347d5c 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -24,12 +24,11 @@
 
 using std::pair;
 
-OringDurationTracker::OringDurationTracker(const ConfigKey& key, const string& name,
-                                           const HashableDimensionKey& eventKey,
-                                           sp<ConditionWizard> wizard, int conditionIndex,
-                                           bool nesting, uint64_t currentBucketStartNs,
-                                           uint64_t bucketSizeNs,
-                                           const std::vector<sp<AnomalyTracker>>& anomalyTrackers)
+OringDurationTracker::OringDurationTracker(
+        const ConfigKey& key, const string& name, const HashableDimensionKey& eventKey,
+        sp<ConditionWizard> wizard, int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
+        uint64_t bucketSizeNs, const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
+
     : DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
                       bucketSizeNs, anomalyTrackers),
       mStarted(),
@@ -264,8 +263,8 @@
     }
 }
 
-int64_t OringDurationTracker::predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
-                                                        const uint64_t eventTimestampNs) const {
+int64_t OringDurationTracker::predictAnomalyTimestampNs(
+        const DurationAnomalyTracker& anomalyTracker, const uint64_t eventTimestampNs) const {
     // TODO: Unit-test this and see if it can be done more efficiently (e.g. use int32).
     // All variables below represent durations (not timestamps).
 
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index b7d3cba..dcf04db 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -31,7 +31,7 @@
                          const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
                          int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
                          uint64_t bucketSizeNs,
-                         const std::vector<sp<AnomalyTracker>>& anomalyTrackers);
+                         const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers);
 
     void noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime,
                    const ConditionKey& conditionKey) override;
@@ -46,7 +46,7 @@
             uint64_t timestampNs,
             std::unordered_map<HashableDimensionKey, std::vector<DurationBucket>>* output) override;
 
-    int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
+    int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
                                       const uint64_t currentTimestamp) const override;
 
 private:
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 5d0e97e..658b732 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -480,9 +480,8 @@
         }
         const int metricIndex = itr->second;
         sp<MetricProducer> metric = allMetricProducers[metricIndex];
-        sp<AnomalyTracker> anomalyTracker = metric->createAnomalyTracker(alert);
+        sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert);
         if (anomalyTracker != nullptr) {
-            metric->addAnomalyTracker(anomalyTracker);
             allAnomalyTrackers.push_back(anomalyTracker);
         }
     }
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index f62171d..a016054 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -89,7 +89,7 @@
     EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL);
     EXPECT_FALSE(anomalyTracker.detectAnomaly(0, *bucket0));
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp0, 0, *bucket0);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, -1L);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, -1L);
 
     // Adds past bucket #0
     anomalyTracker.addPastBucket(bucket0, 0);
@@ -100,7 +100,7 @@
     EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
     EXPECT_FALSE(anomalyTracker.detectAnomaly(1, *bucket1));
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp1, 1, *bucket1);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, -1L);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, -1L);
 
     // Adds past bucket #0 again. The sum does not change.
     anomalyTracker.addPastBucket(bucket0, 0);
@@ -111,7 +111,7 @@
     EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
     EXPECT_FALSE(anomalyTracker.detectAnomaly(1, *bucket1));
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp1 + 1, 1, *bucket1);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, -1L);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, -1L);
 
     // Adds past bucket #1.
     anomalyTracker.addPastBucket(bucket1, 1);
@@ -122,7 +122,7 @@
     EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
     EXPECT_TRUE(anomalyTracker.detectAnomaly(2, *bucket2));
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp2, 2, *bucket2);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp2);
 
     // Adds past bucket #1 again. Nothing changes.
     anomalyTracker.addPastBucket(bucket1, 1);
@@ -133,7 +133,7 @@
     EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
     EXPECT_TRUE(anomalyTracker.detectAnomaly(2, *bucket2));
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp2 + 1, 2, *bucket2);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp2);
 
     // Adds past bucket #2.
     anomalyTracker.addPastBucket(bucket2, 2);
@@ -144,7 +144,7 @@
     EXPECT_TRUE(anomalyTracker.detectAnomaly(3, *bucket3));
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp3, 3, *bucket3);
     // Within refractory period.
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp2);
 
     // Adds bucket #3.
     anomalyTracker.addPastBucket(bucket3, 3L);
@@ -154,7 +154,7 @@
     EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
     EXPECT_FALSE(anomalyTracker.detectAnomaly(4, *bucket4));
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp4, 4, *bucket4);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp2);
 
     // Adds bucket #4.
     anomalyTracker.addPastBucket(bucket4, 4);
@@ -164,7 +164,7 @@
     EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
     EXPECT_TRUE(anomalyTracker.detectAnomaly(5, *bucket5));
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp5, 5, *bucket5);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp5);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp5);
 
     // Adds bucket #5.
     anomalyTracker.addPastBucket(bucket5, 5);
@@ -175,7 +175,7 @@
     EXPECT_TRUE(anomalyTracker.detectAnomaly(6, *bucket6));
     // Within refractory period.
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp6, 6, *bucket6);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp5);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp5);
 }
 
 TEST(AnomalyTrackerTest, TestSparseBuckets) {
@@ -210,7 +210,7 @@
     EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
     EXPECT_FALSE(anomalyTracker.detectAnomaly(9, *bucket9));
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp1, 9, *bucket9);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, -1);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, -1);
 
     // Add past bucket #9
     anomalyTracker.addPastBucket(bucket9, 9);
@@ -224,7 +224,7 @@
     EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp2, 16, *bucket16);
     EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp2);
     EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
 
     // Add past bucket #16
@@ -237,7 +237,7 @@
     EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
     // Within refractory period.
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp3, 18, *bucket18);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp2);
     EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
     EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
 
@@ -253,7 +253,7 @@
     EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
     EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp4, 20, *bucket20);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp4);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp4);
 
     // Add bucket #18 again. Nothing changes.
     anomalyTracker.addPastBucket(bucket18, 18);
@@ -267,7 +267,7 @@
     EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp4 + 1, 20, *bucket20);
     // Within refractory period.
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp4);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp4);
 
     // Add past bucket #20
     anomalyTracker.addPastBucket(bucket20, 20);
@@ -279,7 +279,7 @@
     EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 24L);
     EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp5, 25, *bucket25);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp4);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp4);
 
     // Add past bucket #25
     anomalyTracker.addPastBucket(bucket25, 25);
@@ -291,7 +291,7 @@
     EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp6, 28, *bucket28);
     EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp4);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp4);
 
     // Updates current bucket #28.
     (*bucket28)[keyE] = 5;
@@ -300,7 +300,7 @@
     EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
     anomalyTracker.detectAndDeclareAnomaly(eventTimestamp6 + 7, 28, *bucket28);
     EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
-    EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp6 + 7);
+    EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp6 + 7);
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index eec94539..d3269ed 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -196,8 +196,6 @@
     int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
     int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
 
-    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
-
     CountMetric metric;
     metric.set_name("1");
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
@@ -205,7 +203,7 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
                                       bucketStartTimeNs);
-    countProducer.addAnomalyTracker(anomalyTracker);
+    sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
 
     int tagId = 1;
     LogEvent event1(tagId, bucketStartTimeNs + 1);
@@ -222,13 +220,13 @@
 
     EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
     EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
-    EXPECT_EQ(anomalyTracker->getLastAlarmTimestampNs(), -1LL);
+    EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), -1LL);
 
     // One event in bucket #2. No alarm as bucket #0 is trashed out.
     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
     EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
     EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
-    EXPECT_EQ(anomalyTracker->getLastAlarmTimestampNs(), -1LL);
+    EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), -1LL);
 
     // Two events in bucket #3.
     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
@@ -237,12 +235,12 @@
     EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
     EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
     // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
-    EXPECT_EQ(anomalyTracker->getLastAlarmTimestampNs(), (long long)event5.GetTimestampNs());
+    EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event5.GetTimestampNs());
 
     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
     EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
     EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
-    EXPECT_EQ(anomalyTracker->getLastAlarmTimestampNs(), (long long)event7.GetTimestampNs());
+    EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event7.GetTimestampNs());
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 5204834..584a6d3 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -173,8 +173,7 @@
     alert.set_metric_name(metricName);
     alert.set_trigger_if_sum_gt(25);
     alert.set_number_of_buckets(2);
-    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
-    gaugeProducer.addAnomalyTracker(anomalyTracker);
+    sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert);
 
     std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(1, bucketStartTimeNs + 1);
     event1->write(1);
@@ -184,7 +183,7 @@
     gaugeProducer.onDataPulled({event1});
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()->second->kv[0].value_int());
-    EXPECT_EQ(anomalyTracker->getLastAlarmTimestampNs(), -1LL);
+    EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), -1LL);
 
     std::shared_ptr<LogEvent> event2 =
             std::make_shared<LogEvent>(1, bucketStartTimeNs + bucketSizeNs + 10);
@@ -195,7 +194,7 @@
     gaugeProducer.onDataPulled({event2});
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()->second->kv[0].value_int());
-    EXPECT_EQ(anomalyTracker->getLastAlarmTimestampNs(), (long long)event2->GetTimestampNs());
+    EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event2->GetTimestampNs());
 
     std::shared_ptr<LogEvent> event3 =
             std::make_shared<LogEvent>(1, bucketStartTimeNs + 2 * bucketSizeNs + 10);
@@ -206,7 +205,7 @@
     gaugeProducer.onDataPulled({event3});
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     EXPECT_EQ(24L, gaugeProducer.mCurrentSlicedBucket->begin()->second->kv[0].value_int());
-    EXPECT_EQ(anomalyTracker->getLastAlarmTimestampNs(), (long long)event3->GetTimestampNs());
+    EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event3->GetTimestampNs());
 
     // The event4 does not have the gauge field. Thus the current bucket value is 0.
     std::shared_ptr<LogEvent> event4 =
@@ -216,7 +215,7 @@
     gaugeProducer.onDataPulled({event4});
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     EXPECT_EQ(0, gaugeProducer.mCurrentSlicedBucket->begin()->second->kv[0].value_int());
-    EXPECT_EQ(anomalyTracker->getLastAlarmTimestampNs(), (long long)event3->GetTimestampNs());
+    EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event3->GetTimestampNs());
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index 7dac0fb..4ad1db1 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -219,20 +219,20 @@
     uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
     uint64_t bucketSizeNs = 30 * NS_PER_SEC;
 
-    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
+    sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
     MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, true, bucketStartTimeNs,
                                bucketSizeNs, {anomalyTracker});
 
     tracker.noteStart(key1, true, eventStartTimeNs, conditionKey1);
     tracker.noteStop(key1, eventStartTimeNs + 10, false);
-    EXPECT_EQ(anomalyTracker->mLastAlarmTimestampNs, -1);
+    EXPECT_EQ(anomalyTracker->mLastAnomalyTimestampNs, -1);
     EXPECT_EQ(10LL, tracker.mDuration);
 
     tracker.noteStart(key2, true, eventStartTimeNs + 20, conditionKey1);
     tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, &buckets);
     tracker.noteStop(key2, eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, false);
     EXPECT_EQ((long long)(4 * NS_PER_SEC + 1LL), tracker.mDuration);
-    EXPECT_EQ(anomalyTracker->mLastAlarmTimestampNs,
+    EXPECT_EQ(anomalyTracker->mLastAnomalyTimestampNs,
               (long long)(eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC));
 }
 
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 9ec302f..e0f554d 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -273,7 +273,7 @@
     uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
     uint64_t bucketSizeNs = 30 * NS_PER_SEC;
 
-    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
+    sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
     OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
                                  bucketSizeNs, {anomalyTracker});
 
@@ -335,13 +335,13 @@
     uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
     uint64_t bucketSizeNs = 30 * NS_PER_SEC;
 
-    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
+    sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
     OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true /*nesting*/,
                                  bucketStartTimeNs, bucketSizeNs, {anomalyTracker});
 
     tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, key1);
     tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 10, false);
-    EXPECT_EQ(anomalyTracker->mLastAlarmTimestampNs, -1);
+    EXPECT_EQ(anomalyTracker->mLastAnomalyTimestampNs, -1);
     EXPECT_TRUE(tracker.mStarted.empty());
     EXPECT_EQ(10LL, tracker.mDuration);
 
@@ -355,7 +355,7 @@
     tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 2 * bucketSizeNs + 25, false);
     EXPECT_EQ(anomalyTracker->getSumOverPastBuckets(eventKey), (long long)(bucketSizeNs));
     EXPECT_EQ((long long)(eventStartTimeNs + 2 * bucketSizeNs + 25),
-              anomalyTracker->mLastAlarmTimestampNs);
+              anomalyTracker->mLastAnomalyTimestampNs);
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 6f117d3..12bc834 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -245,7 +245,6 @@
     alert.set_trigger_if_sum_gt(130);
     alert.set_number_of_buckets(2);
     alert.set_refractory_period_secs(3);
-    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
 
     ValueMetric metric;
     metric.set_name(metricName);
@@ -255,7 +254,7 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
                                       -1 /*not pulled*/, bucketStartTimeNs);
-    valueProducer.addAnomalyTracker(anomalyTracker);
+    sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert);
 
 
     shared_ptr<LogEvent> event1
@@ -292,23 +291,23 @@
     // Two events in bucket #0.
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-    EXPECT_EQ(anomalyTracker->getLastAlarmTimestampNs(), -1LL); // Value sum == 30 <= 130.
+    EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), -1LL); // Value sum == 30 <= 130.
 
     // One event in bucket #2. No alarm as bucket #0 is trashed out.
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
-    EXPECT_EQ(anomalyTracker->getLastAlarmTimestampNs(), -1LL); // Value sum == 130 <= 130.
+    EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), -1LL); // Value sum == 130 <= 130.
 
     // Three events in bucket #3.
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
     // Anomaly at event 4 since Value sum == 131 > 130!
-    EXPECT_EQ(anomalyTracker->getLastAlarmTimestampNs(), (long long)event4->GetTimestampNs());
+    EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event4->GetTimestampNs());
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event5);
     // Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4.
-    EXPECT_EQ(anomalyTracker->getLastAlarmTimestampNs(), (long long)event4->GetTimestampNs());
+    EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event4->GetTimestampNs());
 
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event6);
     // Anomaly at event 6 since Value sum == 160 > 130 and after refractory period.
-    EXPECT_EQ(anomalyTracker->getLastAlarmTimestampNs(), (long long)event6->GetTimestampNs());
+    EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event6->GetTimestampNs());
 }
 
 }  // namespace statsd