• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2017 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 "src/metrics/EventMetricProducer.h"
16 
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19 #include <stdio.h>
20 
21 #include <vector>
22 
23 #include "metrics_test_helper.h"
24 #include "stats_event.h"
25 #include "tests/statsd_test_util.h"
26 
27 using namespace testing;
28 using android::sp;
29 using std::set;
30 using std::unordered_map;
31 using std::vector;
32 
33 #ifdef __ANDROID__
34 
35 namespace android {
36 namespace os {
37 namespace statsd {
38 
39 
40 namespace {
41 const ConfigKey kConfigKey(0, 12345);
42 const uint64_t protoHash = 0x1234567890;
43 
makeLogEvent(LogEvent * logEvent,int32_t atomId,int64_t timestampNs,string str,vector<uint8_t> * bytesField=nullptr)44 void makeLogEvent(LogEvent* logEvent, int32_t atomId, int64_t timestampNs, string str,
45                   vector<uint8_t>* bytesField = nullptr) {
46     AStatsEvent* statsEvent = AStatsEvent_obtain();
47     AStatsEvent_setAtomId(statsEvent, atomId);
48     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
49     AStatsEvent_writeString(statsEvent, str.c_str());
50     if (bytesField != nullptr) {
51         AStatsEvent_writeByteArray(statsEvent, bytesField->data(), bytesField->size());
52     }
53 
54     parseStatsEventToLogEvent(statsEvent, logEvent);
55 }
56 }  // anonymous namespace
57 
58 class EventMetricProducerTest : public ::testing::Test {
SetUp()59     void SetUp() override {
60         FlagProvider::getInstance().overrideFuncs(&isAtLeastSFuncTrue);
61     }
62 
TearDown()63     void TearDown() override {
64         FlagProvider::getInstance().resetOverrides();
65     }
66 };
67 
TEST_F(EventMetricProducerTest,TestNoCondition)68 TEST_F(EventMetricProducerTest, TestNoCondition) {
69     int64_t bucketStartTimeNs = 10000000000;
70     int64_t eventStartTimeNs = bucketStartTimeNs + 1;
71     int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
72 
73     EventMetric metric;
74     metric.set_id(1);
75 
76     LogEvent event1(/*uid=*/0, /*pid=*/0);
77     CreateNoValuesLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1);
78 
79     LogEvent event2(/*uid=*/0, /*pid=*/0);
80     CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 2);
81 
82     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
83 
84     EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
85                                       wizard, protoHash, bucketStartTimeNs);
86 
87     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
88     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
89 
90     // Check dump report content.
91     ProtoOutputStream output;
92     std::set<string> strSet;
93     eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
94                                true /*erase data*/, FAST, &strSet, &output);
95 
96     StatsLogReport report = outputStreamToProto(&output);
97     backfillAggregatedAtoms(&report);
98     EXPECT_TRUE(report.has_event_metrics());
99     ASSERT_EQ(2, report.event_metrics().data_size());
100     EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos());
101     EXPECT_EQ(bucketStartTimeNs + 2, report.event_metrics().data(1).elapsed_timestamp_nanos());
102 }
103 
TEST_F(EventMetricProducerTest,TestEventsWithNonSlicedCondition)104 TEST_F(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
105     int64_t bucketStartTimeNs = 10000000000;
106     int64_t eventStartTimeNs = bucketStartTimeNs + 1;
107     int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
108 
109     EventMetric metric;
110     metric.set_id(1);
111     metric.set_condition(StringToId("SCREEN_ON"));
112 
113     LogEvent event1(/*uid=*/0, /*pid=*/0);
114     CreateNoValuesLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1);
115 
116     LogEvent event2(/*uid=*/0, /*pid=*/0);
117     CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 10);
118 
119     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
120 
121     EventMetricProducer eventProducer(kConfigKey, metric, 0 /*condition index*/,
122                                       {ConditionState::kUnknown}, wizard, protoHash,
123                                       bucketStartTimeNs);
124 
125     eventProducer.onConditionChanged(true /*condition*/, bucketStartTimeNs);
126     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
127 
128     eventProducer.onConditionChanged(false /*condition*/, bucketStartTimeNs + 2);
129 
130     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
131 
132     // Check dump report content.
133     ProtoOutputStream output;
134     std::set<string> strSet;
135     eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
136                                true /*erase data*/, FAST, &strSet, &output);
137 
138     StatsLogReport report = outputStreamToProto(&output);
139     EXPECT_TRUE(report.has_event_metrics());
140     backfillAggregatedAtoms(&report);
141     ASSERT_EQ(1, report.event_metrics().data_size());
142     EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos());
143 }
144 
TEST_F(EventMetricProducerTest,TestEventsWithSlicedCondition)145 TEST_F(EventMetricProducerTest, TestEventsWithSlicedCondition) {
146     int64_t bucketStartTimeNs = 10000000000;
147     int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
148 
149     int tagId = 1;
150     int conditionTagId = 2;
151 
152     EventMetric metric;
153     metric.set_id(1);
154     metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
155     MetricConditionLink* link = metric.add_links();
156     link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
157     buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
158     buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
159 
160     LogEvent event1(/*uid=*/0, /*pid=*/0);
161     makeLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1, "111");
162     ConditionKey key1;
163     key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
164             getMockedDimensionKey(conditionTagId, 2, "111")};
165 
166     LogEvent event2(/*uid=*/0, /*pid=*/0);
167     makeLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 10, "222");
168     ConditionKey key2;
169     key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
170             getMockedDimensionKey(conditionTagId, 2, "222")};
171 
172     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
173     // Condition is false for first event.
174     EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
175     // Condition is true for second event.
176     EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
177 
178     EventMetricProducer eventProducer(kConfigKey, metric, 0 /*condition index*/,
179                                       {ConditionState::kUnknown}, wizard, protoHash,
180                                       bucketStartTimeNs);
181 
182     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
183     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
184 
185     // Check dump report content.
186     ProtoOutputStream output;
187     std::set<string> strSet;
188     eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
189                                true /*erase data*/, FAST, &strSet, &output);
190 
191     StatsLogReport report = outputStreamToProto(&output);
192     backfillAggregatedAtoms(&report);
193     EXPECT_TRUE(report.has_event_metrics());
194     ASSERT_EQ(1, report.event_metrics().data_size());
195     EXPECT_EQ(bucketStartTimeNs + 10, report.event_metrics().data(0).elapsed_timestamp_nanos());
196 }
197 
TEST_F(EventMetricProducerTest,TestOneAtomTagAggregatedEvents)198 TEST_F(EventMetricProducerTest, TestOneAtomTagAggregatedEvents) {
199     int64_t bucketStartTimeNs = 10000000000;
200     int tagId = 1;
201 
202     EventMetric metric;
203     metric.set_id(1);
204 
205     LogEvent event1(/*uid=*/0, /*pid=*/0);
206     makeLogEvent(&event1, tagId, bucketStartTimeNs + 10, "111");
207     LogEvent event2(/*uid=*/0, /*pid=*/0);
208     makeLogEvent(&event2, tagId, bucketStartTimeNs + 20, "111");
209     LogEvent event3(/*uid=*/0, /*pid=*/0);
210     makeLogEvent(&event3, tagId, bucketStartTimeNs + 30, "111");
211 
212     LogEvent event4(/*uid=*/0, /*pid=*/0);
213     makeLogEvent(&event4, tagId, bucketStartTimeNs + 40, "222");
214 
215     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
216     EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
217                                       wizard, protoHash, bucketStartTimeNs);
218 
219     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
220     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
221     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event3);
222     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event4);
223 
224     // Check dump report content.
225     ProtoOutputStream output;
226     std::set<string> strSet;
227     eventProducer.onDumpReport(bucketStartTimeNs + 50, true /*include current partial bucket*/,
228                                true /*erase data*/, FAST, &strSet, &output);
229 
230     StatsLogReport report = outputStreamToProto(&output);
231     EXPECT_TRUE(report.has_event_metrics());
232     ASSERT_EQ(2, report.event_metrics().data_size());
233 
234     for (EventMetricData metricData : report.event_metrics().data()) {
235         AggregatedAtomInfo atomInfo = metricData.aggregated_atom_info();
236         if (atomInfo.elapsed_timestamp_nanos_size() == 1) {
237             EXPECT_EQ(atomInfo.elapsed_timestamp_nanos(0), bucketStartTimeNs + 40);
238         } else if (atomInfo.elapsed_timestamp_nanos_size() == 3) {
239             EXPECT_EQ(atomInfo.elapsed_timestamp_nanos(0), bucketStartTimeNs + 10);
240             EXPECT_EQ(atomInfo.elapsed_timestamp_nanos(1), bucketStartTimeNs + 20);
241             EXPECT_EQ(atomInfo.elapsed_timestamp_nanos(2), bucketStartTimeNs + 30);
242         } else {
243             FAIL();
244         }
245     }
246 }
247 
TEST_F(EventMetricProducerTest,TestBytesFieldAggregatedEvents)248 TEST_F(EventMetricProducerTest, TestBytesFieldAggregatedEvents) {
249     int64_t bucketStartTimeNs = 10000000000;
250     int tagId = 1;
251 
252     EventMetric metric;
253     metric.set_id(1);
254 
255     vector<uint8_t> bytesField1{10, 20, 30};
256     vector<uint8_t> bytesField2{10, 20, 30, 40};
257     LogEvent event1(/*uid=*/0, /*pid=*/0);
258     makeLogEvent(&event1, tagId, bucketStartTimeNs + 10, "111", &bytesField1);
259     LogEvent event2(/*uid=*/0, /*pid=*/0);
260     makeLogEvent(&event2, tagId, bucketStartTimeNs + 20, "111", &bytesField1);
261     LogEvent event3(/*uid=*/0, /*pid=*/0);
262     makeLogEvent(&event3, tagId, bucketStartTimeNs + 30, "111", &bytesField1);
263 
264     LogEvent event4(/*uid=*/0, /*pid=*/0);
265     makeLogEvent(&event4, tagId, bucketStartTimeNs + 40, "111", &bytesField2);
266 
267     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
268     EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
269                                       wizard, protoHash, bucketStartTimeNs);
270 
271     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
272     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
273     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event3);
274     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event4);
275 
276     // Check dump report content.
277     ProtoOutputStream output;
278     std::set<string> strSet;
279     eventProducer.onDumpReport(bucketStartTimeNs + 50, true /*include current partial bucket*/,
280                                true /*erase data*/, FAST, &strSet, &output);
281 
282     StatsLogReport report = outputStreamToProto(&output);
283     EXPECT_TRUE(report.has_event_metrics());
284     ASSERT_EQ(2, report.event_metrics().data_size());
285 
286     for (EventMetricData metricData : report.event_metrics().data()) {
287         AggregatedAtomInfo atomInfo = metricData.aggregated_atom_info();
288         if (atomInfo.elapsed_timestamp_nanos_size() == 1) {
289             EXPECT_EQ(atomInfo.elapsed_timestamp_nanos(0), bucketStartTimeNs + 40);
290         } else if (atomInfo.elapsed_timestamp_nanos_size() == 3) {
291             EXPECT_EQ(atomInfo.elapsed_timestamp_nanos(0), bucketStartTimeNs + 10);
292             EXPECT_EQ(atomInfo.elapsed_timestamp_nanos(1), bucketStartTimeNs + 20);
293             EXPECT_EQ(atomInfo.elapsed_timestamp_nanos(2), bucketStartTimeNs + 30);
294         } else {
295             FAIL();
296         }
297     }
298 }
299 
TEST_F(EventMetricProducerTest,TestTwoAtomTagAggregatedEvents)300 TEST_F(EventMetricProducerTest, TestTwoAtomTagAggregatedEvents) {
301     int64_t bucketStartTimeNs = 10000000000;
302     int tagId = 1;
303     int tagId2 = 0;
304 
305     EventMetric metric;
306     metric.set_id(1);
307 
308     LogEvent event1(/*uid=*/0, /*pid=*/0);
309     makeLogEvent(&event1, tagId, bucketStartTimeNs + 10, "111");
310     LogEvent event2(/*uid=*/0, /*pid=*/0);
311     makeLogEvent(&event2, tagId, bucketStartTimeNs + 20, "111");
312 
313     LogEvent event3(/*uid=*/0, /*pid=*/0);
314     makeLogEvent(&event3, tagId2, bucketStartTimeNs + 40, "222");
315 
316     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
317     EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
318                                       wizard, protoHash, bucketStartTimeNs);
319 
320     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
321     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
322     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event3);
323 
324     // Check dump report content.
325     ProtoOutputStream output;
326     std::set<string> strSet;
327     eventProducer.onDumpReport(bucketStartTimeNs + 50, true /*include current partial bucket*/,
328                                true /*erase data*/, FAST, &strSet, &output);
329 
330     StatsLogReport report = outputStreamToProto(&output);
331     EXPECT_TRUE(report.has_event_metrics());
332     ASSERT_EQ(2, report.event_metrics().data_size());
333 
334     for (EventMetricData metricData : report.event_metrics().data()) {
335         AggregatedAtomInfo atomInfo = metricData.aggregated_atom_info();
336         if (atomInfo.elapsed_timestamp_nanos_size() == 1) {
337             EXPECT_EQ(atomInfo.elapsed_timestamp_nanos(0), bucketStartTimeNs + 40);
338         } else if (atomInfo.elapsed_timestamp_nanos_size() == 2) {
339             EXPECT_EQ(atomInfo.elapsed_timestamp_nanos(0), bucketStartTimeNs + 10);
340             EXPECT_EQ(atomInfo.elapsed_timestamp_nanos(1), bucketStartTimeNs + 20);
341         } else {
342             FAIL();
343         }
344     }
345 }
346 }  // namespace statsd
347 }  // namespace os
348 }  // namespace android
349 #else
350 GTEST_LOG_(INFO) << "This test does nothing.\n";
351 #endif
352