Home | History | Annotate | Download | only in e2e
      1 // Copyright (C) 2018 The Android Open Source Project
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include <gtest/gtest.h>
     16 
     17 #include "src/anomaly/DurationAnomalyTracker.h"
     18 #include "src/StatsLogProcessor.h"
     19 #include "src/stats_log_util.h"
     20 #include "tests/statsd_test_util.h"
     21 
     22 #include <vector>
     23 
     24 namespace android {
     25 namespace os {
     26 namespace statsd {
     27 
     28 #ifdef __ANDROID__
     29 
     30 namespace {
     31 
     32 StatsdConfig CreateStatsdConfig(int num_buckets,
     33                                 uint64_t threshold_ns,
     34                                 DurationMetric::AggregationType aggregationType,
     35                                 bool nesting) {
     36     StatsdConfig config;
     37     config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
     38     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
     39     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
     40     *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
     41     *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
     42 
     43     auto screenIsOffPredicate = CreateScreenIsOffPredicate();
     44     *config.add_predicate() = screenIsOffPredicate;
     45 
     46     auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
     47     FieldMatcher dimensions = CreateAttributionUidDimensions(
     48             android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
     49     dimensions.add_child()->set_field(3);  // The wakelock tag is set in field 3 of the wakelock.
     50     *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
     51     holdingWakelockPredicate.mutable_simple_predicate()->set_count_nesting(nesting);
     52     *config.add_predicate() = holdingWakelockPredicate;
     53 
     54     auto durationMetric = config.add_duration_metric();
     55     durationMetric->set_id(StringToId("WakelockDuration"));
     56     durationMetric->set_what(holdingWakelockPredicate.id());
     57     durationMetric->set_condition(screenIsOffPredicate.id());
     58     durationMetric->set_aggregation_type(aggregationType);
     59     *durationMetric->mutable_dimensions_in_what() =
     60         CreateAttributionUidDimensions(android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
     61     durationMetric->set_bucket(FIVE_MINUTES);
     62 
     63     auto alert = config.add_alert();
     64     alert->set_id(StringToId("alert"));
     65     alert->set_metric_id(StringToId("WakelockDuration"));
     66     alert->set_num_buckets(num_buckets);
     67     alert->set_refractory_period_secs(2);
     68     alert->set_trigger_if_sum_gt(threshold_ns);
     69     return config;
     70 }
     71 
     72 }  // namespace
     73 
     74 std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
     75                                                       CreateAttribution(222, "GMSCoreModule1")};
     76 
     77 std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App2"),
     78                                                       CreateAttribution(222, "GMSCoreModule1")};
     79 
     80 std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1")};
     81 
     82 MetricDimensionKey dimensionKey(
     83     HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
     84                                            (int32_t)0x02010101), Value((int32_t)111))}),
     85     DEFAULT_DIMENSION_KEY);
     86 
     87 MetricDimensionKey dimensionKey2(
     88     HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
     89                                            (int32_t)0x02010101), Value((int32_t)222))}),
     90     DEFAULT_DIMENSION_KEY);
     91 
     92 TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
     93     const int num_buckets = 1;
     94     const uint64_t threshold_ns = NS_PER_SEC;
     95     auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
     96     const uint64_t alert_id = config.alert(0).id();
     97     const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
     98 
     99     int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
    100     int64_t bucketSizeNs =
    101         TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
    102 
    103     ConfigKey cfgKey;
    104     auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
    105     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
    106     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
    107     EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
    108 
    109     sp<AnomalyTracker> anomalyTracker =
    110         processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
    111 
    112     auto screen_on_event = CreateScreenStateChangedEvent(
    113             android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 1);
    114     auto screen_off_event = CreateScreenStateChangedEvent(
    115             android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 10);
    116     processor->OnLogEvent(screen_on_event.get());
    117     processor->OnLogEvent(screen_off_event.get());
    118 
    119     // Acquire wakelock wl1.
    120     auto acquire_event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 11);
    121     processor->OnLogEvent(acquire_event.get());
    122     EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1,
    123               anomalyTracker->getAlarmTimestampSec(dimensionKey));
    124     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    125 
    126     // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event.
    127     auto release_event = CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 101);
    128     processor->OnLogEvent(release_event.get());
    129     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    130     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    131 
    132     // Acquire wakelock wl1 within bucket #0.
    133     acquire_event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 110);
    134     processor->OnLogEvent(acquire_event.get());
    135     EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns - 90) / NS_PER_SEC + 1,
    136               anomalyTracker->getAlarmTimestampSec(dimensionKey));
    137     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    138 
    139     // Release wakelock wl1. One anomaly detected.
    140     release_event = CreateReleaseWakelockEvent(
    141             attributions2, "wl1", bucketStartTimeNs + NS_PER_SEC + 109);
    142     processor->OnLogEvent(release_event.get());
    143     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    144     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
    145               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    146 
    147     // Acquire wakelock wl1.
    148     acquire_event = CreateAcquireWakelockEvent(
    149         attributions1, "wl1", bucketStartTimeNs + NS_PER_SEC + 112);
    150     processor->OnLogEvent(acquire_event.get());
    151     // Wakelock has been hold longer than the threshold in bucket #0. The alarm is set at the
    152     // end of the refractory period.
    153     const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey);
    154     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
    155               (uint32_t)alarmFiredTimestampSec0);
    156 
    157     // Anomaly alarm fired.
    158     auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
    159             static_cast<uint32_t>(alarmFiredTimestampSec0));
    160     EXPECT_EQ(1u, alarmSet.size());
    161     processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
    162     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    163     EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
    164               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    165 
    166     // Release wakelock wl1.
    167     release_event = CreateReleaseWakelockEvent(
    168             attributions1, "wl1", alarmFiredTimestampSec0 * NS_PER_SEC + NS_PER_SEC + 1);
    169     processor->OnLogEvent(release_event.get());
    170     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    171     // Within refractory period. No more anomaly detected.
    172     EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
    173               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    174 
    175     // Acquire wakelock wl1.
    176     acquire_event = CreateAcquireWakelockEvent(
    177         attributions2, "wl1", bucketStartTimeNs + bucketSizeNs -  5 * NS_PER_SEC - 11);
    178     processor->OnLogEvent(acquire_event.get());
    179     const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey);
    180     EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
    181               (uint64_t)alarmFiredTimestampSec1);
    182 
    183     // Release wakelock wl1.
    184     release_event = CreateReleaseWakelockEvent(
    185         attributions2, "wl1", bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10);
    186     processor->OnLogEvent(release_event.get());
    187     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    188     EXPECT_EQ(refractory_period_sec +
    189                     (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1,
    190               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    191 
    192     alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
    193                 static_cast<uint32_t>(alarmFiredTimestampSec1));
    194     EXPECT_EQ(0u, alarmSet.size());
    195 
    196     // Acquire wakelock wl1 near the end of bucket #0.
    197     acquire_event = CreateAcquireWakelockEvent(
    198             attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 2);
    199     processor->OnLogEvent(acquire_event.get());
    200     EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
    201                anomalyTracker->getAlarmTimestampSec(dimensionKey));
    202 
    203     // Release the event at early bucket #1.
    204     release_event = CreateReleaseWakelockEvent(
    205             attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1);
    206     processor->OnLogEvent(release_event.get());
    207     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    208     // Anomaly detected when stopping the alarm. The refractory period does not change.
    209     EXPECT_EQ(refractory_period_sec +
    210                     (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
    211               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    212 
    213     // Condition changes to false.
    214     screen_on_event = CreateScreenStateChangedEvent(
    215         android::view::DisplayStateEnum::DISPLAY_STATE_ON,
    216         bucketStartTimeNs + 2 * bucketSizeNs + 20);
    217     processor->OnLogEvent(screen_on_event.get());
    218     EXPECT_EQ(refractory_period_sec +
    219                     (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
    220               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    221     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    222 
    223     acquire_event = CreateAcquireWakelockEvent(
    224         attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 30);
    225     processor->OnLogEvent(acquire_event.get());
    226     // The condition is false. Do not start the alarm.
    227     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    228     EXPECT_EQ(refractory_period_sec +
    229                     (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
    230               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    231 
    232     // Condition turns true.
    233     screen_off_event = CreateScreenStateChangedEvent(
    234         android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
    235         bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC);
    236     processor->OnLogEvent(screen_off_event.get());
    237     EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
    238               anomalyTracker->getAlarmTimestampSec(dimensionKey));
    239 
    240     // Condition turns to false.
    241     screen_on_event = CreateScreenStateChangedEvent(
    242         android::view::DisplayStateEnum::DISPLAY_STATE_ON,
    243         bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1);
    244     processor->OnLogEvent(screen_on_event.get());
    245     // Condition turns to false. Cancelled the alarm.
    246     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    247     //  Detected one anomaly.
    248     EXPECT_EQ(refractory_period_sec +
    249                     (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1) / NS_PER_SEC + 1,
    250               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    251 
    252     // Condition turns to true again.
    253     screen_off_event = CreateScreenStateChangedEvent(
    254         android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
    255         bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 2);
    256     processor->OnLogEvent(screen_off_event.get());
    257     EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
    258               anomalyTracker->getAlarmTimestampSec(dimensionKey));
    259 
    260     release_event = CreateReleaseWakelockEvent(
    261         attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC);
    262     processor->OnLogEvent(release_event.get());
    263     EXPECT_EQ(refractory_period_sec +
    264                     (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC,
    265               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    266     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    267 }
    268 
    269 TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
    270     const int num_buckets = 3;
    271     const uint64_t threshold_ns = NS_PER_SEC;
    272     auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
    273     const uint64_t alert_id = config.alert(0).id();
    274     const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
    275 
    276     int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
    277     int64_t bucketSizeNs =
    278         TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
    279 
    280     ConfigKey cfgKey;
    281     auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
    282     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
    283     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
    284     EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
    285 
    286     sp<AnomalyTracker> anomalyTracker =
    287         processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
    288 
    289     auto screen_off_event = CreateScreenStateChangedEvent(
    290             android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 1);
    291     processor->OnLogEvent(screen_off_event.get());
    292 
    293     // Acquire wakelock "wc1" in bucket #0.
    294     auto acquire_event = CreateAcquireWakelockEvent(
    295         attributions1, "wl1", bucketStartTimeNs + bucketSizeNs -  NS_PER_SEC / 2 - 1);
    296     processor->OnLogEvent(acquire_event.get());
    297     EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
    298               anomalyTracker->getAlarmTimestampSec(dimensionKey));
    299     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    300 
    301     // Release wakelock "wc1" in bucket #0.
    302     auto release_event = CreateReleaseWakelockEvent(
    303         attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 1);
    304     processor->OnLogEvent(release_event.get());
    305     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    306     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    307 
    308     // Acquire wakelock "wc1" in bucket #1.
    309     acquire_event = CreateAcquireWakelockEvent(
    310         attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
    311     processor->OnLogEvent(acquire_event.get());
    312     EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
    313               anomalyTracker->getAlarmTimestampSec(dimensionKey));
    314     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    315 
    316     release_event = CreateReleaseWakelockEvent(
    317         attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 100);
    318     processor->OnLogEvent(release_event.get());
    319     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    320     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    321 
    322     // Acquire wakelock "wc2" in bucket #2.
    323     acquire_event = CreateAcquireWakelockEvent(
    324         attributions3, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1);
    325     processor->OnLogEvent(acquire_event.get());
    326     EXPECT_EQ((bucketStartTimeNs + 2 *  bucketSizeNs) / NS_PER_SEC + 2,
    327               anomalyTracker->getAlarmTimestampSec(dimensionKey2));
    328     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
    329 
    330     // Release wakelock "wc2" in bucket #2.
    331     release_event = CreateReleaseWakelockEvent(
    332         attributions3, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC);
    333     processor->OnLogEvent(release_event.get());
    334     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
    335     EXPECT_EQ(refractory_period_sec +
    336                    (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC,
    337               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
    338 
    339     // Acquire wakelock "wc1" in bucket #2.
    340     acquire_event = CreateAcquireWakelockEvent(
    341         attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC);
    342     processor->OnLogEvent(acquire_event.get());
    343     EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1,
    344               anomalyTracker->getAlarmTimestampSec(dimensionKey));
    345     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    346 
    347     // Release wakelock "wc1" in bucket #2.
    348     release_event = CreateReleaseWakelockEvent(
    349         attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC);
    350     processor->OnLogEvent(release_event.get());
    351     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    352     EXPECT_EQ(refractory_period_sec +
    353                    (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) / NS_PER_SEC + 1,
    354               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    355 
    356     acquire_event = CreateAcquireWakelockEvent(
    357         attributions3, "wl2", bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4);
    358     processor->OnLogEvent(acquire_event.get());
    359     acquire_event = CreateAcquireWakelockEvent(
    360         attributions1, "wl1", bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5);
    361     processor->OnLogEvent(acquire_event.get());
    362     EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
    363               anomalyTracker->getAlarmTimestampSec(dimensionKey));
    364     EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
    365               anomalyTracker->getAlarmTimestampSec(dimensionKey2));
    366 
    367     release_event = CreateReleaseWakelockEvent(
    368         attributions3, "wl2", bucketStartTimeNs + 6 * bucketSizeNs + 2);
    369     processor->OnLogEvent(release_event.get());
    370     release_event = CreateReleaseWakelockEvent(
    371         attributions1, "wl1", bucketStartTimeNs + 6 * bucketSizeNs + 6);
    372     processor->OnLogEvent(release_event.get());
    373     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    374     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
    375     // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
    376     EXPECT_EQ(refractory_period_sec +
    377                    (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
    378               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    379 }
    380 
    381 TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
    382     const int num_buckets = 2;
    383     const uint64_t threshold_ns = 3 * NS_PER_SEC;
    384     auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
    385     int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
    386     int64_t bucketSizeNs =
    387         TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
    388 
    389     const uint64_t alert_id = config.alert(0).id();
    390     const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
    391     config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
    392 
    393     ConfigKey cfgKey;
    394     auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
    395     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
    396     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
    397     EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
    398 
    399     sp<AnomalyTracker> anomalyTracker =
    400         processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
    401 
    402     auto screen_off_event = CreateScreenStateChangedEvent(
    403             android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 1);
    404     processor->OnLogEvent(screen_off_event.get());
    405 
    406     // Acquire wakelock "wc1" in bucket #0.
    407     auto acquire_event = CreateAcquireWakelockEvent(
    408         attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 100);
    409     processor->OnLogEvent(acquire_event.get());
    410     EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
    411               anomalyTracker->getAlarmTimestampSec(dimensionKey));
    412     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    413 
    414     // Acquire the wakelock "wc1" again.
    415     acquire_event = CreateAcquireWakelockEvent(
    416         attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1);
    417     processor->OnLogEvent(acquire_event.get());
    418     // The alarm does not change.
    419     EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
    420               anomalyTracker->getAlarmTimestampSec(dimensionKey));
    421     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    422 
    423     // Anomaly alarm fired late.
    424     const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
    425     auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
    426             static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC));
    427     EXPECT_EQ(1u, alarmSet.size());
    428     processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet);
    429     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    430     EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
    431               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    432 
    433     acquire_event = CreateAcquireWakelockEvent(
    434         attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs - 100);
    435     processor->OnLogEvent(acquire_event.get());
    436     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    437     EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
    438               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    439 
    440     auto release_event = CreateReleaseWakelockEvent(
    441         attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 1);
    442     processor->OnLogEvent(release_event.get());
    443     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    444     // Within the refractory period. No anomaly.
    445     EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
    446               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    447 
    448     // A new wakelock, but still within refractory period.
    449     acquire_event = CreateAcquireWakelockEvent(
    450         attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC);
    451     processor->OnLogEvent(acquire_event.get());
    452     EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
    453               anomalyTracker->getAlarmTimestampSec(dimensionKey));
    454 
    455     release_event = CreateReleaseWakelockEvent(
    456         attributions1, "wl1", bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC);
    457     // Still in the refractory period. No anomaly.
    458     processor->OnLogEvent(release_event.get());
    459     EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
    460               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
    461 
    462     acquire_event = CreateAcquireWakelockEvent(
    463         attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5);
    464     processor->OnLogEvent(acquire_event.get());
    465     EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
    466               anomalyTracker->getAlarmTimestampSec(dimensionKey));
    467 
    468     release_event = CreateReleaseWakelockEvent(
    469         attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4);
    470     processor->OnLogEvent(release_event.get());
    471     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
    472 
    473     acquire_event = CreateAcquireWakelockEvent(
    474         attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3);
    475     processor->OnLogEvent(acquire_event.get());
    476     EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
    477               anomalyTracker->getAlarmTimestampSec(dimensionKey));
    478 }
    479 
    480 #else
    481 GTEST_LOG_(INFO) << "This test does nothing.\n";
    482 #endif
    483 
    484 }  // namespace statsd
    485 }  // namespace os
    486 }  // namespace android
    487