1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <gtest/gtest.h>
16 
17 #include "src/StatsLogProcessor.h"
18 #include "src/stats_log_util.h"
19 #include "tests/statsd_test_util.h"
20 
21 #include <vector>
22 
23 namespace android {
24 namespace os {
25 namespace statsd {
26 
27 #ifdef __ANDROID__
28 
29 namespace {
30 
CreateStatsdConfig(int num_buckets,int threshold)31 StatsdConfig CreateStatsdConfig(int num_buckets, int threshold) {
32     StatsdConfig config;
33     config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
34     auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
35 
36     *config.add_atom_matcher() = wakelockAcquireMatcher;
37 
38     auto countMetric = config.add_count_metric();
39     countMetric->set_id(123456);
40     countMetric->set_what(wakelockAcquireMatcher.id());
41     *countMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
42             android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
43     countMetric->set_bucket(FIVE_MINUTES);
44 
45     auto alert = config.add_alert();
46     alert->set_id(StringToId("alert"));
47     alert->set_metric_id(123456);
48     alert->set_num_buckets(num_buckets);
49     alert->set_refractory_period_secs(10);
50     alert->set_trigger_if_sum_gt(threshold);
51     return config;
52 }
53 
54 }  // namespace
55 
TEST(AnomalyDetectionE2eTest,TestSlicedCountMetric_single_bucket)56 TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket) {
57     const int num_buckets = 1;
58     const int threshold = 3;
59     auto config = CreateStatsdConfig(num_buckets, threshold);
60     const uint64_t alert_id = config.alert(0).id();
61     const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
62 
63     int64_t bucketStartTimeNs = 10000000000;
64     int64_t bucketSizeNs =
65         TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
66 
67     ConfigKey cfgKey;
68     auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
69     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
70     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
71     EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
72 
73     sp<AnomalyTracker> anomalyTracker =
74         processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
75 
76     std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
77     std::vector<AttributionNodeInternal> attributions2 = {
78         CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1")};
79     std::vector<AttributionNodeInternal> attributions3 = {
80         CreateAttribution(111, "App1"), CreateAttribution(333, "App3")};
81     std::vector<AttributionNodeInternal> attributions4 = {
82         CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(333, "App3")};
83     std::vector<AttributionNodeInternal> attributions5 = {
84         CreateAttribution(222, "GMSCoreModule1") };
85 
86     FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
87                            Value((int32_t)111));
88     HashableDimensionKey whatKey1({fieldValue1});
89     MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
90 
91     FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
92                            Value((int32_t)222));
93     HashableDimensionKey whatKey2({fieldValue2});
94     MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
95 
96     auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
97     processor->OnLogEvent(event.get());
98     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
99 
100     event = CreateAcquireWakelockEvent(attributions4, "wl2", bucketStartTimeNs + 2);
101     processor->OnLogEvent(event.get());
102     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
103 
104     event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 3);
105     processor->OnLogEvent(event.get());
106     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
107 
108     event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + 3);
109     processor->OnLogEvent(event.get());
110     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
111 
112     event = CreateAcquireWakelockEvent(attributions3, "wl1", bucketStartTimeNs + 4);
113     processor->OnLogEvent(event.get());
114     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
115 
116     event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + 4);
117     processor->OnLogEvent(event.get());
118     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
119 
120     // Fired alarm and refractory period end timestamp updated.
121     event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 5);
122     processor->OnLogEvent(event.get());
123     EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
124               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
125 
126     event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 100);
127     processor->OnLogEvent(event.get());
128     EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
129               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
130 
131     event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 1);
132     processor->OnLogEvent(event.get());
133     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
134               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
135 
136     event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
137     processor->OnLogEvent(event.get());
138     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
139               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
140 
141     event = CreateAcquireWakelockEvent(attributions4, "wl2", bucketStartTimeNs + bucketSizeNs + 1);
142     processor->OnLogEvent(event.get());
143     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
144 
145     event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 2);
146     processor->OnLogEvent(event.get());
147     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
148 
149     event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 3);
150     processor->OnLogEvent(event.get());
151     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
152 
153     event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 4);
154     processor->OnLogEvent(event.get());
155     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 4) / NS_PER_SEC + 1,
156               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
157 }
158 
TEST(AnomalyDetectionE2eTest,TestSlicedCountMetric_multiple_buckets)159 TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets) {
160     const int num_buckets = 3;
161     const int threshold = 3;
162     auto config = CreateStatsdConfig(num_buckets, threshold);
163     const uint64_t alert_id = config.alert(0).id();
164     const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
165 
166     int64_t bucketStartTimeNs = 10000000000;
167     int64_t bucketSizeNs =
168         TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
169 
170     ConfigKey cfgKey;
171     auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
172     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
173     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
174     EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
175 
176     sp<AnomalyTracker> anomalyTracker =
177         processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
178 
179     std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
180     std::vector<AttributionNodeInternal> attributions2 = {
181         CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1")};
182     std::vector<AttributionNodeInternal> attributions3 = {
183         CreateAttribution(111, "App1"), CreateAttribution(333, "App3")};
184     std::vector<AttributionNodeInternal> attributions4 = {
185         CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(333, "App3")};
186     std::vector<AttributionNodeInternal> attributions5 = {
187         CreateAttribution(222, "GMSCoreModule1") };
188 
189     FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
190                            Value((int32_t)111));
191     HashableDimensionKey whatKey1({fieldValue1});
192     MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
193 
194     FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
195                            Value((int32_t)222));
196     HashableDimensionKey whatKey2({fieldValue2});
197     MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
198 
199     auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
200     processor->OnLogEvent(event.get());
201     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
202 
203     event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 3);
204     processor->OnLogEvent(event.get());
205     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
206 
207     // Fired alarm and refractory period end timestamp updated.
208     event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 4);
209     processor->OnLogEvent(event.get());
210     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
211 
212     event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
213     processor->OnLogEvent(event.get());
214     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
215               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
216 
217     event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 2);
218     processor->OnLogEvent(event.get());
219     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
220               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
221 
222     event = CreateAcquireWakelockEvent(
223         attributions2, "wl1", bucketStartTimeNs + 3 * bucketSizeNs + 1);
224     processor->OnLogEvent(event.get());
225     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
226               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
227 
228     event = CreateAcquireWakelockEvent(
229         attributions2, "wl1", bucketStartTimeNs + 3 * bucketSizeNs + 2);
230     processor->OnLogEvent(event.get());
231     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 3 * bucketSizeNs + 2) / NS_PER_SEC + 1,
232               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
233 }
234 
235 #else
236 GTEST_LOG_(INFO) << "This test does nothing.\n";
237 #endif
238 
239 }  // namespace statsd
240 }  // namespace os
241 }  // namespace android
242