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