Merge "E2e test for periodic alarm." into pi-dev am: 46eef8d049
am: 5708929c0c

Change-Id: I432b9f5df7e10d3466c2f2fb32e05a1d3722e6fd
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 1aef0c4..7723615 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -202,6 +202,7 @@
     tests/statsd_test_util.cpp \
     tests/e2e/WakelockDuration_e2e_test.cpp \
     tests/e2e/MetricConditionLink_e2e_test.cpp \
+    tests/e2e/Alarm_e2e_test.cpp \
     tests/e2e/Attribution_e2e_test.cpp \
     tests/e2e/GaugeMetric_e2e_push_test.cpp \
     tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp \
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index c1ff275..13f2679 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -85,7 +85,7 @@
 }
 
 void StatsLogProcessor::onAnomalyAlarmFired(
-        const uint64_t timestampNs,
+        const uint64_t& timestampNs,
         unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
     for (const auto& itr : mMetricsManagers) {
@@ -93,7 +93,7 @@
     }
 }
 void StatsLogProcessor::onPeriodicAlarmFired(
-        const uint64_t timestampNs,
+        const uint64_t& timestampNs,
         unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
 
     std::lock_guard<std::mutex> lock(mMetricsMutex);
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index a07a355..387a929 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -51,12 +51,12 @@
 
     /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
     void onAnomalyAlarmFired(
-            const uint64_t timestampNs,
+            const uint64_t& timestampNs,
             unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
 
     /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies periodic alarmSet. */
     void onPeriodicAlarmFired(
-            const uint64_t timestampNs,
+            const uint64_t& timestampNs,
             unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
 
     /* Flushes data to disk. Data on memory will be gone after written to disk. */
@@ -74,6 +74,10 @@
         return mAnomalyAlarmMonitor;
     }
 
+    inline sp<AlarmMonitor> getPeriodicAlarmMonitor() const {
+        return mPeriodicAlarmMonitor;
+    }
+
     mutable mutex mMetricsMutex;
 
     std::unordered_map<ConfigKey, sp<MetricsManager>> mMetricsManagers;
@@ -147,6 +151,7 @@
     FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
     FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
     FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
+    FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 9f70c75..7b0d5d9 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -698,7 +698,7 @@
                 "Only system uid can call informAlarmForSubscriberTriggeringFired");
     }
 
-    uint64_t currentTimeSec = time(nullptr);
+    uint64_t currentTimeSec = getElapsedRealtimeSec();
     std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
             mPeriodicAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
     if (alarmSet.size() > 0) {
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp
index eb28383..249cb59 100644
--- a/cmds/statsd/src/anomaly/AlarmTracker.cpp
+++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp
@@ -39,12 +39,14 @@
     VLOG("AlarmTracker() called");
     mAlarmSec = (startMillis + mAlarmConfig.offset_millis()) / MS_PER_SEC;
     mInternalAlarm = new InternalAlarm{static_cast<uint32_t>(mAlarmSec)};
-    mAlarmMonitor->add(mInternalAlarm);
+    if (mAlarmMonitor != nullptr) {
+        mAlarmMonitor->add(mInternalAlarm);
+    }
 }
 
 AlarmTracker::~AlarmTracker() {
     VLOG("~AlarmTracker() called");
-    if (mInternalAlarm != nullptr) {
+    if (mInternalAlarm != nullptr && mAlarmMonitor != nullptr) {
         mAlarmMonitor->remove(mInternalAlarm);
     }
 }
@@ -61,7 +63,8 @@
 void AlarmTracker::informAlarmsFired(
         const uint64_t& timestampNs,
         unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) {
-    if (firedAlarms.empty() || firedAlarms.find(mInternalAlarm) == firedAlarms.end()) {
+    if (firedAlarms.empty() || mInternalAlarm == nullptr ||
+        firedAlarms.find(mInternalAlarm) == firedAlarms.end()) {
         return;
     }
     if (!mSubscriptions.empty()) {
@@ -69,9 +72,11 @@
                            mSubscriptions);
     }
     firedAlarms.erase(mInternalAlarm);
-    mAlarmSec = findNextAlarmSec(timestampNs / NS_PER_SEC);
+    mAlarmSec = findNextAlarmSec((timestampNs-1) / NS_PER_SEC + 1); // round up
     mInternalAlarm = new InternalAlarm{static_cast<uint32_t>(mAlarmSec)};
-    mAlarmMonitor->add(mInternalAlarm);
+    if (mAlarmMonitor != nullptr) {
+        mAlarmMonitor->add(mInternalAlarm);
+    }
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.h b/cmds/statsd/src/anomaly/AlarmTracker.h
index d59dacaa..13180a5 100644
--- a/cmds/statsd/src/anomaly/AlarmTracker.h
+++ b/cmds/statsd/src/anomaly/AlarmTracker.h
@@ -48,6 +48,11 @@
             unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms);
 
 protected:
+    // For test only. Returns the alarm timestamp in seconds. Otherwise returns 0.
+    inline uint32_t getAlarmTimestampSec() const {
+        return mInternalAlarm == nullptr ? 0 : mInternalAlarm->timestampSec;
+    }
+
     uint64_t findNextAlarmSec(uint64_t currentTimeMillis);
 
     // statsd_config.proto Alarm message that defines this tracker.
@@ -69,6 +74,7 @@
     sp<const InternalAlarm> mInternalAlarm;
 
     FRIEND_TEST(AlarmTrackerTest, TestTriggerTimestamp);
+    FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 1be082a..00188e8 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -351,7 +351,7 @@
 }
 
 void MetricsManager::onAnomalyAlarmFired(
-        const uint64_t timestampNs,
+        const uint64_t& timestampNs,
         unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet) {
     for (const auto& itr : mAllAnomalyTrackers) {
         itr->informAlarmsFired(timestampNs, alarmSet);
@@ -359,7 +359,7 @@
 }
 
 void MetricsManager::onPeriodicAlarmFired(
-        const uint64_t timestampNs,
+        const uint64_t& timestampNs,
         unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet) {
     for (const auto& itr : mAllPeriodicAlarmTrackers) {
         itr->informAlarmsFired(timestampNs, alarmSet);
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 05ce84d..da0cd4a 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -48,11 +48,11 @@
     void onLogEvent(const LogEvent& event);
 
     void onAnomalyAlarmFired(
-        const uint64_t timestampNs,
+        const uint64_t& timestampNs,
         unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet);
 
     void onPeriodicAlarmFired(
-        const uint64_t timestampNs,
+        const uint64_t& timestampNs,
         unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet);
 
     void notifyAppUpgrade(const uint64_t& eventTimeNs, const string& apk, const int uid,
@@ -184,6 +184,7 @@
     FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
     FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
 
+    FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp b/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp
new file mode 100644
index 0000000..73c4e7b
--- /dev/null
+++ b/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp
@@ -0,0 +1,92 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+#include "src/StatsLogProcessor.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+namespace {
+
+StatsdConfig CreateStatsdConfig() {
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+    auto alarm = config.add_alarm();
+    alarm->set_id(123456);
+    alarm->set_offset_millis(TimeUnitToBucketSizeInMillis(TEN_MINUTES));
+    alarm->set_period_millis(TimeUnitToBucketSizeInMillis(ONE_HOUR));
+
+    alarm = config.add_alarm();
+    alarm->set_id(654321);
+    alarm->set_offset_millis(TimeUnitToBucketSizeInMillis(FIVE_MINUTES));
+    alarm->set_period_millis(TimeUnitToBucketSizeInMillis(THIRTY_MINUTES));
+    return config;
+}
+
+}  // namespace
+
+TEST(AlarmE2eTest, TestMultipleAlarms) {
+    auto config = CreateStatsdConfig();
+    int64_t bucketStartTimeNs = 10000000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    EXPECT_EQ(2u, processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers.size());
+
+    auto alarmTracker1 = processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers[0];
+    auto alarmTracker2 = processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers[1];
+
+    int64_t alarmTimestampSec0 = bucketStartTimeNs / NS_PER_SEC + 10 * 60;
+    int64_t alarmTimestampSec1 = bucketStartTimeNs / NS_PER_SEC + 5 * 60;
+    EXPECT_EQ(alarmTimestampSec0, alarmTracker1->getAlarmTimestampSec());
+    EXPECT_EQ(alarmTimestampSec1, alarmTracker2->getAlarmTimestampSec());
+
+    // Alarm fired.
+    const int64_t alarmFiredTimestampSec0 = alarmTimestampSec1 + 5;
+    auto alarmSet = processor->getPeriodicAlarmMonitor()->popSoonerThan(
+            static_cast<uint32_t>(alarmFiredTimestampSec0));
+    EXPECT_EQ(1u, alarmSet.size());
+    processor->onPeriodicAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
+    EXPECT_EQ(alarmTimestampSec0, alarmTracker1->getAlarmTimestampSec());
+    EXPECT_EQ(alarmTimestampSec1 + 30 * 60, alarmTracker2->getAlarmTimestampSec());
+
+    // Alarms fired very late.
+    const int64_t alarmFiredTimestampSec1 = alarmTimestampSec0 + 2 * 60 * 60 + 125;
+    alarmSet = processor->getPeriodicAlarmMonitor()->popSoonerThan(
+            static_cast<uint32_t>(alarmFiredTimestampSec1));
+    EXPECT_EQ(2u, alarmSet.size());
+    processor->onPeriodicAlarmFired(alarmFiredTimestampSec1 * NS_PER_SEC, alarmSet);
+    EXPECT_EQ(alarmTimestampSec0 + 60 * 60 * 3, alarmTracker1->getAlarmTimestampSec());
+    EXPECT_EQ(alarmTimestampSec1 + 30 * 60 * 5, alarmTracker2->getAlarmTimestampSec());
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 6621500..d0840f0 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -450,7 +450,9 @@
     sp<AlarmMonitor> anomalyAlarmMonitor =
         new AlarmMonitor(1,  [](const sp<IStatsCompanionService>&, int64_t){},
                 [](const sp<IStatsCompanionService>&){});
-    sp<AlarmMonitor> periodicAlarmMonitor;
+    sp<AlarmMonitor> periodicAlarmMonitor =
+        new AlarmMonitor(1,  [](const sp<IStatsCompanionService>&, int64_t){},
+                [](const sp<IStatsCompanionService>&){});
     sp<StatsLogProcessor> processor = new StatsLogProcessor(
         uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, [](const ConfigKey&){});
     processor->OnConfigUpdated(key, config);