• 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 <gtest/gtest.h>
16 
17 #include "src/statsd_metadata.pb.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 
24 namespace android {
25 namespace os {
26 namespace statsd {
27 
28 #ifdef __ANDROID__
29 
30 namespace {
31 
CreateStatsdConfig(int num_buckets,int threshold,int refractory_period_sec)32 StatsdConfig CreateStatsdConfig(int num_buckets, int threshold, int refractory_period_sec) {
33     StatsdConfig config;
34     config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
35     auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
36 
37     *config.add_atom_matcher() = wakelockAcquireMatcher;
38 
39     auto countMetric = config.add_count_metric();
40     countMetric->set_id(123456);
41     countMetric->set_what(wakelockAcquireMatcher.id());
42     *countMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
43             util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
44     countMetric->set_bucket(FIVE_MINUTES);
45 
46     auto alert = config.add_alert();
47     alert->set_id(StringToId("alert"));
48     alert->set_metric_id(123456);
49     alert->set_num_buckets(num_buckets);
50     alert->set_refractory_period_secs(refractory_period_sec);
51     alert->set_trigger_if_sum_gt(threshold);
52     return config;
53 }
54 
55 }  // namespace
56 
TEST(AnomalyDetectionE2eTest,TestSlicedCountMetric_single_bucket)57 TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket) {
58     const int num_buckets = 1;
59     const int threshold = 3;
60     const int refractory_period_sec = 10;
61     auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
62     const uint64_t alert_id = config.alert(0).id();
63 
64     int64_t bucketStartTimeNs = 10000000000;
65     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
66 
67     ConfigKey cfgKey;
68     auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
69     ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
70     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
71     ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
72 
73     sp<AnomalyTracker> anomalyTracker =
74             processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
75 
76     std::vector<int> attributionUids1 = {111};
77     std::vector<string> attributionTags1 = {"App1"};
78     std::vector<int> attributionUids2 = {111, 222};
79     std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
80     std::vector<int> attributionUids3 = {111, 333};
81     std::vector<string> attributionTags3 = {"App1", "App3"};
82     std::vector<int> attributionUids4 = {222, 333};
83     std::vector<string> attributionTags4 = {"GMSCoreModule1", "App3"};
84     std::vector<int> attributionUids5 = {222};
85     std::vector<string> attributionTags5 = {"GMSCoreModule1"};
86 
87     FieldValue fieldValue1(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
88                            Value((int32_t)111));
89     HashableDimensionKey whatKey1({fieldValue1});
90     MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
91 
92     FieldValue fieldValue2(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
93                            Value((int32_t)222));
94     HashableDimensionKey whatKey2({fieldValue2});
95     MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
96 
97     auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
98                                             attributionTags1, "wl1");
99     processor->OnLogEvent(event.get());
100     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
101 
102     event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids4, attributionTags4,
103                                        "wl2");
104     processor->OnLogEvent(event.get());
105     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
106 
107     event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids2, attributionTags2,
108                                        "wl1");
109     processor->OnLogEvent(event.get());
110     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
111 
112     event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids5, attributionTags5,
113                                        "wl2");
114     processor->OnLogEvent(event.get());
115     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
116 
117     event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids3, attributionTags3,
118                                        "wl1");
119     processor->OnLogEvent(event.get());
120     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
121 
122     event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids5, attributionTags5,
123                                        "wl2");
124     processor->OnLogEvent(event.get());
125     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
126 
127     // Fired alarm and refractory period end timestamp updated.
128     event = CreateAcquireWakelockEvent(bucketStartTimeNs + 5, attributionUids1, attributionTags1,
129                                        "wl1");
130     processor->OnLogEvent(event.get());
131     EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
132               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
133 
134     event = CreateAcquireWakelockEvent(bucketStartTimeNs + 100, attributionUids1, attributionTags1,
135                                        "wl1");
136     processor->OnLogEvent(event.get());
137     EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
138               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
139 
140     event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids1,
141                                        attributionTags1, "wl1");
142     processor->OnLogEvent(event.get());
143     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
144               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
145 
146     event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids1,
147                                        attributionTags1, "wl1");
148     processor->OnLogEvent(event.get());
149     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
150               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
151 
152     event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids4,
153                                        attributionTags4, "wl2");
154     processor->OnLogEvent(event.get());
155     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
156 
157     event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids5,
158                                        attributionTags5, "wl2");
159     processor->OnLogEvent(event.get());
160     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
161 
162     event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 3, attributionUids5,
163                                        attributionTags5, "wl2");
164     processor->OnLogEvent(event.get());
165     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
166 
167     event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 4, attributionUids5,
168                                        attributionTags5, "wl2");
169     processor->OnLogEvent(event.get());
170     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 4) / NS_PER_SEC + 1,
171               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
172 }
173 
TEST(AnomalyDetectionE2eTest,TestSlicedCountMetric_multiple_buckets)174 TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets) {
175     const int num_buckets = 3;
176     const int threshold = 3;
177     const int refractory_period_sec = 10;
178     auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
179     const uint64_t alert_id = config.alert(0).id();
180 
181     int64_t bucketStartTimeNs = 10000000000;
182     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
183 
184     ConfigKey cfgKey;
185     auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
186     ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
187     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
188     ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
189 
190     sp<AnomalyTracker> anomalyTracker =
191             processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
192 
193     std::vector<int> attributionUids1 = {111};
194     std::vector<string> attributionTags1 = {"App1"};
195     std::vector<int> attributionUids2 = {111, 222};
196     std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
197 
198     FieldValue fieldValue1(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
199                            Value((int32_t)111));
200     HashableDimensionKey whatKey1({fieldValue1});
201     MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
202 
203     auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
204                                             attributionTags1, "wl1");
205     processor->OnLogEvent(event.get());
206     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
207 
208     event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids2, attributionTags2,
209                                        "wl1");
210     processor->OnLogEvent(event.get());
211     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
212 
213     // Fired alarm and refractory period end timestamp updated.
214     event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids1, attributionTags1,
215                                        "wl1");
216     processor->OnLogEvent(event.get());
217     EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
218 
219     event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids1,
220                                        attributionTags1, "wl1");
221     processor->OnLogEvent(event.get());
222     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
223               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
224 
225     event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids2,
226                                        attributionTags2, "wl1");
227     processor->OnLogEvent(event.get());
228     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
229               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
230 
231     event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1, attributionUids2,
232                                        attributionTags2, "wl1");
233     processor->OnLogEvent(event.get());
234     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
235               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
236 
237     event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 2, attributionUids2,
238                                        attributionTags2, "wl1");
239     processor->OnLogEvent(event.get());
240     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 3 * bucketSizeNs + 2) / NS_PER_SEC + 1,
241               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
242 }
243 
TEST(AnomalyDetectionE2eTest,TestCountMetric_save_refractory_to_disk_no_data_written)244 TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk_no_data_written) {
245     const int num_buckets = 1;
246     const int threshold = 0;
247     const int refractory_period_sec = 86400 * 365; // 1 year
248     auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
249     const int64_t alert_id = config.alert(0).id();
250 
251     int64_t bucketStartTimeNs = 10000000000;
252 
253     int configUid = 2000;
254     int64_t configId = 1000;
255     ConfigKey cfgKey(configUid, configId);
256     auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
257     ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
258     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
259     ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
260 
261     metadata::StatsMetadataList result;
262     int64_t mockWallClockNs = 1584991200 * NS_PER_SEC;
263     int64_t mockElapsedTimeNs = bucketStartTimeNs + 5000 * NS_PER_SEC;
264     processor->WriteMetadataToProto(mockWallClockNs, mockElapsedTimeNs, &result);
265 
266     ASSERT_EQ(result.stats_metadata_size(), 0);
267 }
268 
TEST(AnomalyDetectionE2eTest,TestCountMetric_save_refractory_to_disk)269 TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk) {
270     const int num_buckets = 1;
271     const int threshold = 0;
272     const int refractory_period_sec = 86400 * 365; // 1 year
273     auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
274     const int64_t alert_id = config.alert(0).id();
275 
276     int64_t bucketStartTimeNs = 10000000000;
277 
278     int configUid = 2000;
279     int64_t configId = 1000;
280     ConfigKey cfgKey(configUid, configId);
281     auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
282     ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
283     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
284     ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
285 
286     sp<AnomalyTracker> anomalyTracker =
287             processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
288 
289     std::vector<int> attributionUids1 = {111};
290     std::vector<string> attributionTags1 = {"App1"};
291     std::vector<int> attributionUids2 = {111, 222};
292     std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
293 
294     FieldValue fieldValue1(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
295                            Value((int32_t)111));
296     HashableDimensionKey whatKey1({fieldValue1});
297     MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
298 
299     auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
300                                             attributionTags1, "wl1");
301     processor->OnLogEvent(event.get());
302     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 2) / NS_PER_SEC + 1,
303               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
304 
305     metadata::StatsMetadataList result;
306     int64_t mockWallClockNs = 1584991200 * NS_PER_SEC;
307     int64_t mockElapsedTimeNs = bucketStartTimeNs + 5000 * NS_PER_SEC;
308     processor->WriteMetadataToProto(mockWallClockNs, mockElapsedTimeNs, &result);
309 
310     metadata::StatsMetadata statsMetadata = result.stats_metadata(0);
311     ASSERT_EQ(result.stats_metadata_size(), 1);
312     EXPECT_EQ(statsMetadata.config_key().config_id(), configId);
313     EXPECT_EQ(statsMetadata.config_key().uid(), configUid);
314 
315     metadata::AlertMetadata alertMetadata = statsMetadata.alert_metadata(0);
316     ASSERT_EQ(statsMetadata.alert_metadata_size(), 1);
317     EXPECT_EQ(alertMetadata.alert_id(), alert_id);
318     metadata::AlertDimensionKeyedData keyedData = alertMetadata.alert_dim_keyed_data(0);
319     ASSERT_EQ(alertMetadata.alert_dim_keyed_data_size(), 1);
320     EXPECT_EQ(keyedData.last_refractory_ends_sec(),
321               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1) -
322               mockElapsedTimeNs / NS_PER_SEC +
323               mockWallClockNs / NS_PER_SEC);
324 
325     metadata::MetricDimensionKey metadataDimKey = keyedData.dimension_key();
326     metadata::FieldValue dimKeyInWhat = metadataDimKey.dimension_key_in_what(0);
327     EXPECT_EQ(dimKeyInWhat.field().tag(), fieldValue1.mField.getTag());
328     EXPECT_EQ(dimKeyInWhat.field().field(), fieldValue1.mField.getField());
329     EXPECT_EQ(dimKeyInWhat.value_int(), fieldValue1.mValue.int_value);
330 }
331 
TEST(AnomalyDetectionE2eTest,TestCountMetric_load_refractory_from_disk)332 TEST(AnomalyDetectionE2eTest, TestCountMetric_load_refractory_from_disk) {
333     const int num_buckets = 1;
334     const int threshold = 0;
335     const int refractory_period_sec = 86400 * 365; // 1 year
336     auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
337     const int64_t alert_id = config.alert(0).id();
338 
339     int64_t bucketStartTimeNs = 10000000000;
340 
341     int configUid = 2000;
342     int64_t configId = 1000;
343     ConfigKey cfgKey(configUid, configId);
344     auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
345     ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
346     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
347     ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
348 
349     sp<AnomalyTracker> anomalyTracker =
350             processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
351 
352     std::vector<int> attributionUids1 = {111};
353     std::vector<string> attributionTags1 = {"App1"};
354     std::vector<int> attributionUids2 = {111, 222};
355     std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
356 
357     FieldValue fieldValue1(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
358                            Value((int32_t)111));
359     HashableDimensionKey whatKey1({fieldValue1});
360     MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
361 
362     auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
363                                             attributionTags1, "wl1");
364     processor->OnLogEvent(event.get());
365     EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 2) / NS_PER_SEC + 1,
366               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
367 
368     int64_t mockWallClockNs = 1584991200 * NS_PER_SEC;
369     int64_t mockElapsedTimeNs = bucketStartTimeNs + 5000 * NS_PER_SEC;
370     processor->SaveMetadataToDisk(mockWallClockNs, mockElapsedTimeNs);
371 
372     auto processor2 = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
373     int64_t mockElapsedTimeSinceBoot = 10 * NS_PER_SEC;
374     processor2->LoadMetadataFromDisk(mockWallClockNs, mockElapsedTimeSinceBoot);
375 
376     sp<AnomalyTracker> anomalyTracker2 =
377                 processor2->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
378     EXPECT_EQ(anomalyTracker2->getRefractoryPeriodEndsSec(dimensionKey1) -
379               mockElapsedTimeSinceBoot / NS_PER_SEC,
380               anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1) -
381               mockElapsedTimeNs / NS_PER_SEC);
382 }
383 
384 #else
385 GTEST_LOG_(INFO) << "This test does nothing.\n";
386 #endif
387 
388 }  // namespace statsd
389 }  // namespace os
390 }  // namespace android
391