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 24namespace android { 25namespace os { 26namespace statsd { 27 28#ifdef __ANDROID__ 29 30namespace { 31 32StatsdConfig 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 74std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"), 75 CreateAttribution(222, "GMSCoreModule1")}; 76 77std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App2"), 78 CreateAttribution(222, "GMSCoreModule1")}; 79 80std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1")}; 81 82MetricDimensionKey dimensionKey( 83 HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED, 84 (int32_t)0x02010101), Value((int32_t)111))}), 85 DEFAULT_DIMENSION_KEY); 86 87MetricDimensionKey dimensionKey2( 88 HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED, 89 (int32_t)0x02010101), Value((int32_t)222))}), 90 DEFAULT_DIMENSION_KEY); 91 92TEST(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 269TEST(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 381TEST(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 481GTEST_LOG_(INFO) << "This test does nothing.\n"; 482#endif 483 484} // namespace statsd 485} // namespace os 486} // namespace android 487