blob: 4f9f3153e404dd4047a21809eff0eed847c5e225 [file] [log] [blame]
Yangster-macbe10ddf2018-03-13 15:39:51 -07001// 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(
Jeffrey Huang3eb84d42020-03-17 10:31:22 -070048 util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
Yangster-macbe10ddf2018-03-13 15:39:51 -070049 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() =
Jeffrey Huang3eb84d42020-03-17 10:31:22 -070060 CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
Yangster-macbe10ddf2018-03-13 15:39:51 -070061 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
tsaichristine7747d372020-02-28 17:36:59 -080072std::vector<int> attributionUids1 = {111, 222};
73std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1"};
Yangster-macbe10ddf2018-03-13 15:39:51 -070074
tsaichristine7747d372020-02-28 17:36:59 -080075std::vector<int> attributionUids2 = {111, 222};
76std::vector<string> attributionTags2 = {"App2", "GMSCoreModule1"};
Yangster-macbe10ddf2018-03-13 15:39:51 -070077
tsaichristine7747d372020-02-28 17:36:59 -080078std::vector<int> attributionUids3 = {222};
79std::vector<string> attributionTags3 = {"GMSCoreModule1"};
Yangster-macbe10ddf2018-03-13 15:39:51 -070080
tsaichristine7747d372020-02-28 17:36:59 -080081MetricDimensionKey dimensionKey1(
Jeffrey Huang3eb84d42020-03-17 10:31:22 -070082 HashableDimensionKey({FieldValue(Field(util::WAKELOCK_STATE_CHANGED,
tsaichristine7747d372020-02-28 17:36:59 -080083 (int32_t)0x02010101),
84 Value((int32_t)111))}),
85 DEFAULT_DIMENSION_KEY);
Yangster-macbe10ddf2018-03-13 15:39:51 -070086
87MetricDimensionKey dimensionKey2(
Jeffrey Huang3eb84d42020-03-17 10:31:22 -070088 HashableDimensionKey({FieldValue(Field(util::WAKELOCK_STATE_CHANGED,
Yangster-macbe10ddf2018-03-13 15:39:51 -070089 (int32_t)0x02010101), Value((int32_t)222))}),
90 DEFAULT_DIMENSION_KEY);
91
tsaichristine7747d372020-02-28 17:36:59 -080092} // namespace
93
94TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
95 const int num_buckets = 1;
96 const uint64_t threshold_ns = NS_PER_SEC;
97 auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
98 const uint64_t alert_id = config.alert(0).id();
99 const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
100
101 int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
102 int64_t bucketSizeNs =
103 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
104
105 ConfigKey cfgKey;
106 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
107 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
108 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
109 EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
110
111 sp<AnomalyTracker> anomalyTracker =
112 processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
113
114 auto screen_on_event = CreateScreenStateChangedEvent(
115 bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
116 auto screen_off_event = CreateScreenStateChangedEvent(
117 bucketStartTimeNs + 10, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
118 processor->OnLogEvent(screen_on_event.get());
119 processor->OnLogEvent(screen_off_event.get());
120
121 // Acquire wakelock wl1.
122 auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 11, attributionUids1,
123 attributionTags1, "wl1");
124 processor->OnLogEvent(acquire_event.get());
125 EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1,
126 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
127 EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
128
129 // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event.
130 auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 101, attributionUids1,
131 attributionTags1, "wl1");
132 processor->OnLogEvent(release_event.get());
133 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
134 EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
135
136 // Acquire wakelock wl1 within bucket #0.
137 acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 110, attributionUids2,
138 attributionTags2, "wl1");
139 processor->OnLogEvent(acquire_event.get());
140 EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns - 90) / NS_PER_SEC + 1,
141 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
142 EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
143
144 // Release wakelock wl1. One anomaly detected.
145 release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 109,
146 attributionUids2, attributionTags2, "wl1");
147 processor->OnLogEvent(release_event.get());
148 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
149 EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
150 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
151
152 // Acquire wakelock wl1.
153 acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 112,
154 attributionUids1, attributionTags1, "wl1");
155 processor->OnLogEvent(acquire_event.get());
156 // Wakelock has been hold longer than the threshold in bucket #0. The alarm is set at the
157 // end of the refractory period.
158 const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
159 EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
160 (uint32_t)alarmFiredTimestampSec0);
161
162 // Anomaly alarm fired.
163 auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
164 static_cast<uint32_t>(alarmFiredTimestampSec0));
165 EXPECT_EQ(1u, alarmSet.size());
166 processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
167 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
168 EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
169 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
170
171 // Release wakelock wl1.
172 release_event =
173 CreateReleaseWakelockEvent(alarmFiredTimestampSec0 * NS_PER_SEC + NS_PER_SEC + 1,
174 attributionUids1, attributionTags1, "wl1");
175 processor->OnLogEvent(release_event.get());
176 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
177 // Within refractory period. No more anomaly detected.
178 EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
179 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
180
181 // Acquire wakelock wl1.
182 acquire_event =
183 CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11,
184 attributionUids2, attributionTags2, "wl1");
185 processor->OnLogEvent(acquire_event.get());
186 const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
187 EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
188 (uint64_t)alarmFiredTimestampSec1);
189
190 // Release wakelock wl1.
191 release_event =
192 CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10,
193 attributionUids2, attributionTags2, "wl1");
194 processor->OnLogEvent(release_event.get());
195 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
196 EXPECT_EQ(refractory_period_sec +
197 (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1,
198 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
199
200 alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
201 static_cast<uint32_t>(alarmFiredTimestampSec1));
202 EXPECT_EQ(0u, alarmSet.size());
203
204 // Acquire wakelock wl1 near the end of bucket #0.
205 acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 2,
206 attributionUids1, attributionTags1, "wl1");
207 processor->OnLogEvent(acquire_event.get());
208 EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
209 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
210
211 // Release the event at early bucket #1.
212 release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1,
213 attributionUids1, attributionTags1, "wl1");
214 processor->OnLogEvent(release_event.get());
215 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
216 // Anomaly detected when stopping the alarm. The refractory period does not change.
217 EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
218 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
219
220 // Condition changes to false.
221 screen_on_event =
222 CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 20,
223 android::view::DisplayStateEnum::DISPLAY_STATE_ON);
224 processor->OnLogEvent(screen_on_event.get());
225 EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
226 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
227 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
228
229 acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 30,
230 attributionUids2, attributionTags2, "wl1");
231 processor->OnLogEvent(acquire_event.get());
232 // The condition is false. Do not start the alarm.
233 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
234 EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
235 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
236
237 // Condition turns true.
238 screen_off_event =
239 CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC,
240 android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
241 processor->OnLogEvent(screen_off_event.get());
242 EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
243 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
244
245 // Condition turns to false.
246 screen_on_event =
247 CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1,
248 android::view::DisplayStateEnum::DISPLAY_STATE_ON);
249 processor->OnLogEvent(screen_on_event.get());
250 // Condition turns to false. Cancelled the alarm.
251 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
252 // Detected one anomaly.
253 EXPECT_EQ(refractory_period_sec +
254 (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1) / NS_PER_SEC + 1,
255 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
256
257 // Condition turns to true again.
258 screen_off_event =
259 CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 2,
260 android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
261 processor->OnLogEvent(screen_off_event.get());
262 EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
263 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
264
265 release_event =
266 CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC,
267 attributionUids2, attributionTags2, "wl1");
268 processor->OnLogEvent(release_event.get());
269 EXPECT_EQ(refractory_period_sec +
270 (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC,
271 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
272 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
273}
274
275TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
276 const int num_buckets = 3;
277 const uint64_t threshold_ns = NS_PER_SEC;
278 auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
279 const uint64_t alert_id = config.alert(0).id();
280 const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
281
282 int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
283 int64_t bucketSizeNs =
284 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
285
286 ConfigKey cfgKey;
287 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
288 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
289 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
290 EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
291
292 sp<AnomalyTracker> anomalyTracker =
293 processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
294
295 auto screen_off_event = CreateScreenStateChangedEvent(
296 bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
297 processor->OnLogEvent(screen_off_event.get());
298
299 // Acquire wakelock "wc1" in bucket #0.
300 auto acquire_event =
301 CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1,
302 attributionUids1, attributionTags1, "wl1");
303 processor->OnLogEvent(acquire_event.get());
304 EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
305 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
306 EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
307
308 // Release wakelock "wc1" in bucket #0.
309 auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
310 attributionUids1, attributionTags1, "wl1");
311 processor->OnLogEvent(release_event.get());
312 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
313 EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
314
315 // Acquire wakelock "wc1" in bucket #1.
316 acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1,
317 attributionUids2, attributionTags2, "wl1");
318 processor->OnLogEvent(acquire_event.get());
319 EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
320 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
321 EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
322
323 release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 100,
324 attributionUids2, attributionTags2, "wl1");
325 processor->OnLogEvent(release_event.get());
326 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
327 EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
328
329 // Acquire wakelock "wc2" in bucket #2.
330 acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
331 attributionUids3, attributionTags3, "wl2");
332 processor->OnLogEvent(acquire_event.get());
333 EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2,
334 anomalyTracker->getAlarmTimestampSec(dimensionKey2));
335 EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
336
337 // Release wakelock "wc2" in bucket #2.
338 release_event =
339 CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
340 attributionUids3, attributionTags3, "wl2");
341 processor->OnLogEvent(release_event.get());
342 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
343 EXPECT_EQ(refractory_period_sec +
344 (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC,
345 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
346
347 // Acquire wakelock "wc1" in bucket #2.
348 acquire_event =
349 CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
350 attributionUids2, attributionTags2, "wl1");
351 processor->OnLogEvent(acquire_event.get());
352 EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1,
353 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
354 EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
355
356 // Release wakelock "wc1" in bucket #2.
357 release_event =
358 CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC,
359 attributionUids2, attributionTags2, "wl1");
360 processor->OnLogEvent(release_event.get());
361 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
362 EXPECT_EQ(refractory_period_sec +
363 (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) /
364 NS_PER_SEC +
365 1,
366 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
367
368 acquire_event =
369 CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4,
370 attributionUids3, attributionTags3, "wl2");
371 processor->OnLogEvent(acquire_event.get());
372 acquire_event =
373 CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5,
374 attributionUids1, attributionTags1, "wl1");
375 processor->OnLogEvent(acquire_event.get());
376 EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
377 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
378 EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
379 anomalyTracker->getAlarmTimestampSec(dimensionKey2));
380
381 release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 2,
382 attributionUids3, attributionTags3, "wl2");
383 processor->OnLogEvent(release_event.get());
384 release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 6,
385 attributionUids1, attributionTags1, "wl1");
386 processor->OnLogEvent(release_event.get());
387 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
388 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
389 // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
390 EXPECT_EQ(refractory_period_sec + (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC +
391 1,
392 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
393}
394
395TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
396 const int num_buckets = 2;
397 const uint64_t threshold_ns = 3 * NS_PER_SEC;
398 auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
399 int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
400 int64_t bucketSizeNs =
401 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
402
403 const uint64_t alert_id = config.alert(0).id();
404 const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
405 config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
406
407 ConfigKey cfgKey;
408 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
409 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
410 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
411 EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
412
413 sp<AnomalyTracker> anomalyTracker =
414 processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
415
416 auto screen_off_event = CreateScreenStateChangedEvent(
417 bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
418 processor->OnLogEvent(screen_off_event.get());
419
420 // Acquire wakelock "wc1" in bucket #0.
421 auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 100,
422 attributionUids1, attributionTags1, "wl1");
423 processor->OnLogEvent(acquire_event.get());
424 EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
425 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
426 EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
427
428 // Acquire the wakelock "wc1" again.
429 acquire_event =
430 CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1,
431 attributionUids1, attributionTags1, "wl1");
432 processor->OnLogEvent(acquire_event.get());
433 // The alarm does not change.
434 EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
435 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
436 EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
437
438 // Anomaly alarm fired late.
439 const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
440 auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
441 static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC));
442 EXPECT_EQ(1u, alarmSet.size());
443 processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet);
444 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
445 EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
446 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
447
448 acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
449 attributionUids1, attributionTags1, "wl1");
450 processor->OnLogEvent(acquire_event.get());
451 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
452 EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
453 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
454
455 auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
456 attributionUids1, attributionTags1, "wl1");
457 processor->OnLogEvent(release_event.get());
458 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
459 // Within the refractory period. No anomaly.
460 EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
461 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
462
463 // A new wakelock, but still within refractory period.
464 acquire_event =
465 CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC,
466 attributionUids1, attributionTags1, "wl1");
467 processor->OnLogEvent(acquire_event.get());
468 EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
469 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
470
471 release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC,
472 attributionUids1, attributionTags1, "wl1");
473 // Still in the refractory period. No anomaly.
474 processor->OnLogEvent(release_event.get());
475 EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
476 anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
477
478 acquire_event =
479 CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5,
480 attributionUids1, attributionTags1, "wl1");
481 processor->OnLogEvent(acquire_event.get());
482 EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
483 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
484
485 release_event =
486 CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4,
487 attributionUids1, attributionTags1, "wl1");
488 processor->OnLogEvent(release_event.get());
489 EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
490
491 acquire_event =
492 CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3,
493 attributionUids1, attributionTags1, "wl1");
494 processor->OnLogEvent(acquire_event.get());
495 EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
496 anomalyTracker->getAlarmTimestampSec(dimensionKey1));
497}
Yangster-macbe10ddf2018-03-13 15:39:51 -0700498
499#else
500GTEST_LOG_(INFO) << "This test does nothing.\n";
501#endif
502
503} // namespace statsd
504} // namespace os
505} // namespace android