Remove alarm manager dependency from anomalyalarms

Anomaly alarms, which are used for prediction-base duration metric
anomaly detection, currently use alarm manager for setting alarms. This
can result in excessive binder calls to SCS to set/cancel the alarms if
the duration metric that the alarm is based on gets stopped/started in
quick succession.

To resolve this without losing precision, we can instead rely on the
flow of events into the statsd socket for this prediction. The socket
receives events very frequently, so there should be minimal (if any)
loss of precision, and we can remove the binder call entirely.

One concern is that we used to hold a wakelock when the alarm fired
(since alarm manager would hold a wakelock), and we now lose this
ability.

Test: atest statsd_test
Test: atest AnomalyDetectionTests
Bug: 161326200
Bug: 152642091
Change-Id: If37e5c6ccd8efa4e822c70a0444fa6b5a31bebca
Merged-In: If37e5c6ccd8efa4e822c70a0444fa6b5a31bebca
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index e7b32c5..c10f248 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -120,10 +120,9 @@
     }
 }
 
-void StatsLogProcessor::onAnomalyAlarmFired(
+void StatsLogProcessor::processFiredAnomalyAlarmsLocked(
         const int64_t& timestampNs,
         unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
     for (const auto& itr : mMetricsManagers) {
         itr.second->onAnomalyAlarmFired(timestampNs, alarmSet);
     }
@@ -431,6 +430,20 @@
         return;
     }
 
+    bool fireAlarm = false;
+    {
+        std::lock_guard<std::mutex> anomalyLock(mAnomalyAlarmMutex);
+        if (mNextAnomalyAlarmTime != 0 &&
+            MillisToNano(mNextAnomalyAlarmTime) <= elapsedRealtimeNs) {
+            mNextAnomalyAlarmTime = 0;
+            VLOG("informing anomaly alarm at time %lld", (long long)elapsedRealtimeNs);
+            fireAlarm = true;
+        }
+    }
+    if (fireAlarm) {
+        informAnomalyAlarmFiredLocked(NanoToMillis(elapsedRealtimeNs));
+    }
+
     int64_t curTimeSec = getElapsedRealtimeSec();
     if (curTimeSec - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) {
         mPullerManager->ClearPullerCacheIfNecessary(curTimeSec * NS_PER_SEC);
@@ -1092,6 +1105,28 @@
     mOnDiskDataConfigs.insert(key);
 }
 
+void StatsLogProcessor::setAnomalyAlarm(const int64_t elapsedTimeMillis) {
+    std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex);
+    mNextAnomalyAlarmTime = elapsedTimeMillis;
+}
+
+void StatsLogProcessor::cancelAnomalyAlarm() {
+    std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex);
+    mNextAnomalyAlarmTime = 0;
+}
+
+void StatsLogProcessor::informAnomalyAlarmFiredLocked(const int64_t elapsedTimeMillis) {
+    VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called");
+    std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
+            mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(elapsedTimeMillis / 1000));
+    if (alarmSet.size() > 0) {
+        VLOG("Found periodic alarm fired.");
+        processFiredAnomalyAlarmsLocked(MillisToNano(elapsedTimeMillis), alarmSet);
+    } else {
+        ALOGW("Cannot find an periodic alarm that fired. Perhaps it was recently cancelled.");
+    }
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android