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 <android/binder_ibinder.h>
16 #include <android/binder_interface_utils.h>
17 #include <gtest/gtest.h>
18 
19 #include <vector>
20 
21 #include "src/StatsLogProcessor.h"
22 #include "src/StatsService.h"
23 #include "src/anomaly/DurationAnomalyTracker.h"
24 #include "src/packages/UidMap.h"
25 #include "src/stats_log_util.h"
26 #include "tests/statsd_test_util.h"
27 
28 using ::ndk::SharedRefBase;
29 
30 namespace android {
31 namespace os {
32 namespace statsd {
33 
34 #ifdef __ANDROID__
35 
36 namespace {
37 
CreateStatsdConfig(int num_buckets,uint64_t threshold_ns,DurationMetric::AggregationType aggregationType,bool nesting)38 StatsdConfig CreateStatsdConfig(int num_buckets,
39                                 uint64_t threshold_ns,
40                                 DurationMetric::AggregationType aggregationType,
41                                 bool nesting) {
42     StatsdConfig config;
43     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
44     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
45     *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
46     *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
47 
48     auto screenIsOffPredicate = CreateScreenIsOffPredicate();
49     *config.add_predicate() = screenIsOffPredicate;
50 
51     auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
52     FieldMatcher dimensions = CreateAttributionUidDimensions(
53             util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
54     dimensions.add_child()->set_field(3);  // The wakelock tag is set in field 3 of the wakelock.
55     *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
56     holdingWakelockPredicate.mutable_simple_predicate()->set_count_nesting(nesting);
57     *config.add_predicate() = holdingWakelockPredicate;
58 
59     auto durationMetric = config.add_duration_metric();
60     durationMetric->set_id(StringToId("WakelockDuration"));
61     durationMetric->set_what(holdingWakelockPredicate.id());
62     durationMetric->set_condition(screenIsOffPredicate.id());
63     durationMetric->set_aggregation_type(aggregationType);
64     *durationMetric->mutable_dimensions_in_what() =
65         CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
66     durationMetric->set_bucket(FIVE_MINUTES);
67 
68     auto alert = config.add_alert();
69     alert->set_id(StringToId("alert"));
70     alert->set_metric_id(StringToId("WakelockDuration"));
71     alert->set_num_buckets(num_buckets);
72     alert->set_refractory_period_secs(2);
73     alert->set_trigger_if_sum_gt(threshold_ns);
74     return config;
75 }
76 
77 std::vector<int> attributionUids1 = {111, 222};
78 std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1"};
79 
80 std::vector<int> attributionUids2 = {111, 222};
81 std::vector<string> attributionTags2 = {"App2", "GMSCoreModule1"};
82 
83 std::vector<int> attributionUids3 = {222};
84 std::vector<string> attributionTags3 = {"GMSCoreModule1"};
85 
86 MetricDimensionKey dimensionKey1(
87         HashableDimensionKey({FieldValue(Field(util::WAKELOCK_STATE_CHANGED,
88                                                (int32_t)0x02010101),
89                                          Value((int32_t)111))}),
90         DEFAULT_DIMENSION_KEY);
91 
92 MetricDimensionKey dimensionKey2(
93     HashableDimensionKey({FieldValue(Field(util::WAKELOCK_STATE_CHANGED,
94                                            (int32_t)0x02010101), Value((int32_t)222))}),
95     DEFAULT_DIMENSION_KEY);
96 
97 }  // namespace
98 
99 // Setup for test fixture.
100 class AnomalyDurationDetectionE2eTest : public StatsServiceConfigTest {};
101 
TEST_F(AnomalyDurationDetectionE2eTest,TestDurationMetric_SUM_single_bucket)102 TEST_F(AnomalyDurationDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
103     const int num_buckets = 1;
104     const uint64_t threshold_ns = NS_PER_SEC;
105     auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
106     const uint64_t alert_id = config.alert(0).id();
107     const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
108 
109     sendConfig(config);
110 
111     auto processor = service->mProcessor;
112     ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
113     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
114     ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
115 
116     int64_t bucketStartTimeNs = processor->mTimeBaseNs;
117     int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
118     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
119 
120     sp<AnomalyTracker> anomalyTracker =
121             processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
122 
123     auto screen_on_event = CreateScreenStateChangedEvent(
124             bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
125     auto screen_off_event = CreateScreenStateChangedEvent(
126             bucketStartTimeNs + 10, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
127     processor->OnLogEvent(screen_on_event.get());
128     processor->OnLogEvent(screen_off_event.get());
129 
130     // Acquire wakelock wl1.
131     auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 11, attributionUids1,
132                                                     attributionTags1, "wl1");
133     processor->OnLogEvent(acquire_event.get());
134     EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1,
135               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
136     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
137 
138     // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event.
139     auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 101, attributionUids1,
140                                                     attributionTags1, "wl1");
141     processor->OnLogEvent(release_event.get());
142     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
143     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
144 
145     // Acquire wakelock wl1 within bucket #0.
146     acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 110, attributionUids2,
147                                                attributionTags2, "wl1");
148     processor->OnLogEvent(acquire_event.get());
149     EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns - 90) / NS_PER_SEC + 1,
150               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
151     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
152 
153     // Release wakelock wl1. One anomaly detected.
154     release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 109,
155                                                attributionUids2, attributionTags2, "wl1");
156     processor->OnLogEvent(release_event.get());
157     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
158     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
159               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
160 
161     // Acquire wakelock wl1.
162     acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 112,
163                                                attributionUids1, attributionTags1, "wl1");
164     processor->OnLogEvent(acquire_event.get());
165     // Wakelock has been hold longer than the threshold in bucket #0. The alarm is set at the
166     // end of the refractory period.
167     const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
168     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
169               (uint32_t)alarmFiredTimestampSec0);
170     EXPECT_EQ(alarmFiredTimestampSec0,
171               processor->getAnomalyAlarmMonitor()->getRegisteredAlarmTimeSec());
172 
173     // Anomaly alarm fired.
174     auto alarmTriggerEvent = CreateBatterySaverOnEvent(alarmFiredTimestampSec0 * NS_PER_SEC);
175     processor->OnLogEvent(alarmTriggerEvent.get(), alarmFiredTimestampSec0 * NS_PER_SEC);
176 
177     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
178     EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
179               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
180 
181     // Release wakelock wl1.
182     release_event =
183             CreateReleaseWakelockEvent(alarmFiredTimestampSec0 * NS_PER_SEC + NS_PER_SEC + 1,
184                                        attributionUids1, attributionTags1, "wl1");
185     processor->OnLogEvent(release_event.get());
186     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
187     // Within refractory period. No more anomaly detected.
188     EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
189               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
190 
191     // Acquire wakelock wl1.
192     acquire_event = CreateAcquireWakelockEvent(
193             roundedBucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11, attributionUids2,
194             attributionTags2, "wl1");
195     processor->OnLogEvent(acquire_event.get());
196     const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
197     EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
198               (uint64_t)alarmFiredTimestampSec1);
199 
200     // Release wakelock wl1.
201     int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10;
202     release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
203                                                attributionTags2, "wl1");
204     processor->OnLogEvent(release_event.get(), release_event_time);
205     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
206     EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1,
207               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
208 
209     auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
210             static_cast<uint32_t>(alarmFiredTimestampSec1));
211     ASSERT_EQ(0u, alarmSet.size());
212 
213     // Acquire wakelock wl1 near the end of bucket #0.
214     acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 2,
215                                                attributionUids1, attributionTags1, "wl1");
216     processor->OnLogEvent(acquire_event.get());
217     EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
218               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
219 
220     // Release the event at early bucket #1.
221     release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1;
222     release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
223                                                attributionTags1, "wl1");
224     processor->OnLogEvent(release_event.get(), release_event_time);
225     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
226     // Anomaly detected when stopping the alarm. The refractory period does not change.
227     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
228               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
229 
230     // Condition changes to false.
231     screen_on_event =
232             CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 20,
233                                           android::view::DisplayStateEnum::DISPLAY_STATE_ON);
234     processor->OnLogEvent(screen_on_event.get());
235     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
236               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
237     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
238 
239     acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 30,
240                                                attributionUids2, attributionTags2, "wl1");
241     processor->OnLogEvent(acquire_event.get());
242     // The condition is false. Do not start the alarm.
243     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
244     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
245               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
246 
247     // Condition turns true.
248     screen_off_event =
249             CreateScreenStateChangedEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC,
250                                           android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
251     processor->OnLogEvent(screen_off_event.get());
252     EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
253               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
254 
255     // Condition turns to false.
256     int64_t condition_false_time = bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1;
257     screen_on_event = CreateScreenStateChangedEvent(
258             condition_false_time, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
259     processor->OnLogEvent(screen_on_event.get(), condition_false_time);
260     // Condition turns to false. Cancelled the alarm.
261     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
262     //  Detected one anomaly.
263     EXPECT_EQ(refractory_period_sec +
264                       (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1) / NS_PER_SEC + 1,
265               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
266 
267     // Condition turns to true again.
268     screen_off_event =
269             CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 2,
270                                           android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
271     processor->OnLogEvent(screen_off_event.get());
272     EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
273               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
274 
275     release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC;
276     release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
277                                                attributionTags2, "wl1");
278     processor->OnLogEvent(release_event.get());
279     EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC,
280               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
281     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
282 }
283 
TEST_F(AnomalyDurationDetectionE2eTest,TestDurationMetric_SUM_multiple_buckets)284 TEST_F(AnomalyDurationDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
285     const int num_buckets = 3;
286     const uint64_t threshold_ns = NS_PER_SEC;
287     auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
288     const uint64_t alert_id = config.alert(0).id();
289     const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
290 
291     sendConfig(config);
292 
293     auto processor = service->mProcessor;
294     ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
295     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
296     ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
297 
298     int64_t bucketStartTimeNs = processor->mTimeBaseNs;
299     int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
300     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
301 
302     sp<AnomalyTracker> anomalyTracker =
303             processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
304 
305     auto screen_off_event = CreateScreenStateChangedEvent(
306             bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
307     processor->OnLogEvent(screen_off_event.get());
308 
309     // Acquire wakelock "wc1" in bucket #0.
310     auto acquire_event =
311             CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1,
312                                        attributionUids1, attributionTags1, "wl1");
313     processor->OnLogEvent(acquire_event.get());
314     EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
315               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
316     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
317 
318     // Release wakelock "wc1" in bucket #0.
319     int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 1;
320     auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
321                                                     attributionTags1, "wl1");
322     processor->OnLogEvent(release_event.get(), release_event_time);
323     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
324     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
325 
326     // Acquire wakelock "wc1" in bucket #1.
327     acquire_event =
328             CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 1,
329                                        attributionUids2, attributionTags2, "wl1");
330     processor->OnLogEvent(acquire_event.get());
331     EXPECT_EQ((bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC + 1,
332               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
333     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
334 
335     release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 100;
336     release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
337                                                attributionTags2, "wl1");
338     processor->OnLogEvent(release_event.get(), release_event_time);
339     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
340     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
341 
342     // Acquire wakelock "wc2" in bucket #2.
343     acquire_event =
344             CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + 1,
345                                        attributionUids3, attributionTags3, "wl2");
346     processor->OnLogEvent(acquire_event.get());
347     EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3,
348               anomalyTracker->getAlarmTimestampSec(dimensionKey2));
349     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
350 
351     // Release wakelock "wc2" in bucket #2.
352     release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC;
353     release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3,
354                                                attributionTags3, "wl2");
355     processor->OnLogEvent(release_event.get(), release_event_time);
356     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
357     EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC,
358               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
359 
360     // Acquire wakelock "wc1" in bucket #2.
361     acquire_event =
362             CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC,
363                                        attributionUids2, attributionTags2, "wl1");
364     processor->OnLogEvent(acquire_event.get());
365     EXPECT_EQ((roundedBucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3 + 1,
366               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
367     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
368 
369     // Release wakelock "wc1" in bucket #2.
370     release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3.5 * NS_PER_SEC;
371     release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
372                                                attributionTags2, "wl1");
373     processor->OnLogEvent(release_event.get(), release_event_time);
374     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
375     EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1,
376               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
377 
378     acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 4,
379                                                attributionUids3, attributionTags3, "wl2");
380     processor->OnLogEvent(acquire_event.get());
381     acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 5,
382                                                attributionUids1, attributionTags1, "wl1");
383     processor->OnLogEvent(acquire_event.get());
384     EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2,
385               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
386     EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2,
387               anomalyTracker->getAlarmTimestampSec(dimensionKey2));
388 
389     release_event_time = roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC + 2;
390     release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3,
391                                                attributionTags3, "wl2");
392     processor->OnLogEvent(release_event.get(), release_event_time);
393     release_event = CreateReleaseWakelockEvent(release_event_time + 4, attributionUids1,
394                                                attributionTags1, "wl1");
395     processor->OnLogEvent(release_event.get(), release_event_time + 4);
396     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
397     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
398     // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
399     EXPECT_EQ(refractory_period_sec +
400                       (int64_t)(roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC) /
401                               NS_PER_SEC +
402                       1,
403               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
404 }
405 
TEST_F(AnomalyDurationDetectionE2eTest,TestDurationMetric_SUM_partial_bucket)406 TEST_F(AnomalyDurationDetectionE2eTest, TestDurationMetric_SUM_partial_bucket) {
407     const int num_buckets = 1;
408     const uint64_t threshold_ns = NS_PER_SEC;
409     auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
410     const uint64_t alert_id = config.alert(0).id();
411     const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
412 
413     sendConfig(config);
414 
415     auto processor = service->mProcessor;
416     ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
417     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
418     ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
419 
420     int64_t bucketStartTimeNs = processor->mTimeBaseNs;
421     int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
422     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
423 
424     UidData uidData;
425     *uidData.add_app_info() = createApplicationInfo(/*uid*/ 1, /*version*/ 1, "v1", "randomApp");
426     processor->getUidMap()->updateMap(bucketStartTimeNs, uidData);
427 
428     sp<AnomalyTracker> anomalyTracker =
429             processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
430 
431     auto screen_off_event = CreateScreenStateChangedEvent(
432             bucketStartTimeNs + 10, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
433     processor->OnLogEvent(screen_off_event.get());
434 
435     // Acquire wakelock wl1.
436     auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 11, attributionUids1,
437                                                     attributionTags1, "wl1");
438     processor->OnLogEvent(acquire_event.get());
439     EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1,
440               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
441     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
442 
443     // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event.
444     // 90 ns accumulated.
445     auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 101, attributionUids1,
446                                                     attributionTags1, "wl1");
447     processor->OnLogEvent(release_event.get());
448     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
449     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
450 
451     // Acquire wakelock wl2.
452     acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 110, attributionUids3,
453                                                attributionTags3, "wl2");
454     processor->OnLogEvent(acquire_event.get());
455     int64_t wl2AlarmTimeNs = bucketStartTimeNs + 110 + threshold_ns;
456     EXPECT_EQ(wl2AlarmTimeNs / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
457     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
458 
459     // Partial bucket split.
460     int64_t appUpgradeTimeNs = bucketStartTimeNs + 500;
461     service->mUidMap->updateApp(appUpgradeTimeNs, "randomApp", 1, 2, "v2", "",
462                                 /* certificateHash */ {});
463     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
464     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
465     EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns) / NS_PER_SEC + 1,
466               anomalyTracker->getAlarmTimestampSec(dimensionKey2));
467     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
468 
469     // Acquire wakelock wl1. Subtract 100 ns since that accumulated before the bucket split.
470     acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 510, attributionUids1,
471                                                attributionTags1, "wl1");
472     processor->OnLogEvent(acquire_event.get());
473     int64_t wl1AlarmTimeNs = bucketStartTimeNs + 510 + threshold_ns - 90;
474     EXPECT_EQ(wl1AlarmTimeNs / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
475     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
476 
477     // Release wakelock wl1. One anomaly detected.
478     release_event = CreateReleaseWakelockEvent(wl1AlarmTimeNs + 1, attributionUids2,
479                                                attributionTags2, "wl1");
480     processor->OnLogEvent(release_event.get());
481     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
482     EXPECT_EQ(refractory_period_sec + (wl1AlarmTimeNs + 1) / NS_PER_SEC + 1,
483               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
484 
485     // Anomaly alarm fired.
486     auto alarmTriggerEvent = CreateBatterySaverOnEvent(wl2AlarmTimeNs);
487     processor->OnLogEvent(alarmTriggerEvent.get(), wl2AlarmTimeNs);
488 
489     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
490     EXPECT_EQ(refractory_period_sec + wl2AlarmTimeNs / NS_PER_SEC + 1,
491               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
492 }
493 
TEST_F(AnomalyDurationDetectionE2eTest,TestDurationMetric_SUM_long_refractory_period)494 TEST_F(AnomalyDurationDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
495     const int num_buckets = 2;
496     const uint64_t threshold_ns = 3 * NS_PER_SEC;
497     auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
498     const uint64_t alert_id = config.alert(0).id();
499     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
500     const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
501     config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
502 
503     sendConfig(config);
504 
505     auto processor = service->mProcessor;
506     ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
507     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
508     ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
509 
510     int64_t bucketStartTimeNs = processor->mTimeBaseNs;
511     int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
512 
513     sp<AnomalyTracker> anomalyTracker =
514             processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
515 
516     auto screen_off_event = CreateScreenStateChangedEvent(
517             bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
518     processor->OnLogEvent(screen_off_event.get());
519 
520     // Acquire wakelock "wc1" in bucket #0.
521     auto acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 100,
522                                                     attributionUids1, attributionTags1, "wl1");
523     processor->OnLogEvent(acquire_event.get());
524     EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
525               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
526     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
527 
528     // Acquire the wakelock "wc1" again.
529     acquire_event =
530             CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1,
531                                        attributionUids1, attributionTags1, "wl1");
532     processor->OnLogEvent(acquire_event.get());
533     // The alarm does not change.
534     EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
535               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
536     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
537 
538     // Anomaly alarm fired late.
539     const int64_t firedAlarmTimestampNs = roundedBucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
540     auto alarmTriggerEvent = CreateBatterySaverOnEvent(firedAlarmTimestampNs);
541     processor->OnLogEvent(alarmTriggerEvent.get(), firedAlarmTimestampNs);
542     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
543     EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
544               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
545 
546     acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs - 100,
547                                                attributionUids1, attributionTags1, "wl1");
548     processor->OnLogEvent(acquire_event.get());
549     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
550     EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
551               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
552 
553     int64_t release_event_time = bucketStartTimeNs + 2 * bucketSizeNs + 1;
554     auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
555                                                     attributionTags1, "wl1");
556     processor->OnLogEvent(release_event.get(), release_event_time);
557     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
558     // Within the refractory period. No anomaly.
559     EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
560               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
561 
562     // A new wakelock, but still within refractory period.
563     acquire_event = CreateAcquireWakelockEvent(
564             roundedBucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC, attributionUids1,
565             attributionTags1, "wl1");
566     processor->OnLogEvent(acquire_event.get());
567     EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
568               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
569 
570     release_event =
571             CreateReleaseWakelockEvent(roundedBucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC,
572                                        attributionUids1, attributionTags1, "wl1");
573     // Still in the refractory period. No anomaly.
574     processor->OnLogEvent(release_event.get());
575     EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
576               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
577 
578     acquire_event = CreateAcquireWakelockEvent(
579             roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 5, attributionUids1,
580             attributionTags1, "wl1");
581     processor->OnLogEvent(acquire_event.get());
582     EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1,
583               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
584 
585     release_event_time = roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 4;
586     release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
587                                                attributionTags1, "wl1");
588     processor->OnLogEvent(release_event.get(), release_event_time);
589     EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
590 
591     acquire_event = CreateAcquireWakelockEvent(
592             roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 3, attributionUids1,
593             attributionTags1, "wl1");
594     processor->OnLogEvent(acquire_event.get());
595     EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1,
596               anomalyTracker->getAlarmTimestampSec(dimensionKey1));
597 }
598 
599 #else
600 GTEST_LOG_(INFO) << "This test does nothing.\n";
601 #endif
602 
603 }  // namespace statsd
604 }  // namespace os
605 }  // namespace android
606