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 <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
CreateCountMetric_NoLink_CombinationCondition_Config()31 StatsdConfig CreateCountMetric_NoLink_CombinationCondition_Config() {
32 StatsdConfig config;
33 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
34 auto screenBrightnessChangeAtomMatcher = CreateScreenBrightnessChangedAtomMatcher();
35 *config.add_atom_matcher() = screenBrightnessChangeAtomMatcher;
36 *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
37 *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
38 *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
39 *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
40
41 auto screenIsOffPredicate = CreateScreenIsOffPredicate();
42 *config.add_predicate() = screenIsOffPredicate;
43
44 auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
45 // The predicate is dimensioning by any attribution node and both by uid and tag.
46 *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() =
47 CreateAttributionUidAndTagDimensions(android::util::WAKELOCK_STATE_CHANGED,
48 {Position::FIRST});
49 *config.add_predicate() = holdingWakelockPredicate;
50
51 auto combinationPredicate = config.add_predicate();
52 combinationPredicate->set_id(987654);
53 combinationPredicate->mutable_combination()->set_operation(LogicalOperation::OR);
54 addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
55 addPredicateToPredicateCombination(holdingWakelockPredicate, combinationPredicate);
56
57 auto metric = config.add_count_metric();
58 metric->set_id(StringToId("ScreenBrightnessChangeMetric"));
59 metric->set_what(screenBrightnessChangeAtomMatcher.id());
60 metric->set_condition(combinationPredicate->id());
61 *metric->mutable_dimensions_in_what() =
62 CreateDimensions(android::util::SCREEN_BRIGHTNESS_CHANGED, {1 /* level */});
63 *metric->mutable_dimensions_in_condition() = CreateAttributionUidDimensions(
64 android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
65 metric->set_bucket(FIVE_MINUTES);
66 return config;
67 }
68
69 } // namespace
70
TEST(DimensionInConditionE2eTest,TestCreateCountMetric_NoLink_OR_CombinationCondition)71 TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition) {
72 ConfigKey cfgKey;
73 auto config = CreateCountMetric_NoLink_CombinationCondition_Config();
74 int64_t bucketStartTimeNs = 10000000000;
75 int64_t bucketSizeNs =
76 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
77
78 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
79 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
80 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
81
82 std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
83 CreateAttribution(222, "GMSCoreModule1"),
84 CreateAttribution(222, "GMSCoreModule2")};
85
86 std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(333, "App2"),
87 CreateAttribution(222, "GMSCoreModule1"),
88 CreateAttribution(555, "GMSCoreModule2")};
89
90 std::vector<std::unique_ptr<LogEvent>> events;
91 events.push_back(
92 CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10));
93 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
94 bucketStartTimeNs + 100));
95 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
96 bucketStartTimeNs + bucketSizeNs + 1));
97 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
98 bucketStartTimeNs + 2 * bucketSizeNs - 10));
99
100 events.push_back(CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 200));
101 events.push_back(
102 CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1));
103
104 events.push_back(CreateAcquireWakelockEvent(attributions2, "wl2",
105 bucketStartTimeNs + bucketSizeNs - 100));
106 events.push_back(CreateReleaseWakelockEvent(attributions2, "wl2",
107 bucketStartTimeNs + 2 * bucketSizeNs - 50));
108
109 events.push_back(CreateScreenBrightnessChangedEvent(123, bucketStartTimeNs + 11));
110 events.push_back(CreateScreenBrightnessChangedEvent(123, bucketStartTimeNs + 101));
111 events.push_back(CreateScreenBrightnessChangedEvent(123, bucketStartTimeNs + 201));
112 events.push_back(CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + 203));
113 events.push_back(
114 CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + bucketSizeNs - 99));
115 events.push_back(CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + bucketSizeNs - 2));
116 events.push_back(CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + bucketSizeNs - 1));
117 events.push_back(CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + bucketSizeNs + 2));
118 events.push_back(
119 CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + 2 * bucketSizeNs - 11));
120 events.push_back(
121 CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + 2 * bucketSizeNs - 9));
122 events.push_back(
123 CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + 2 * bucketSizeNs - 1));
124
125 sortLogEventsByTimestamp(&events);
126
127 for (const auto& event : events) {
128 processor->OnLogEvent(event.get());
129 }
130
131 ConfigMetricsReportList reports;
132 vector<uint8_t> buffer;
133 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
134 &buffer);
135 EXPECT_TRUE(buffer.size() > 0);
136 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
137 backfillDimensionPath(&reports);
138 backfillStringInReport(&reports);
139 backfillStartEndTimestamp(&reports);
140
141 EXPECT_EQ(reports.reports_size(), 1);
142 EXPECT_EQ(reports.reports(0).metrics_size(), 1);
143 StatsLogReport::CountMetricDataWrapper countMetrics;
144 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
145
146 EXPECT_EQ(countMetrics.data_size(), 7);
147 auto data = countMetrics.data(0);
148 EXPECT_EQ(data.bucket_info_size(), 1);
149 EXPECT_EQ(data.bucket_info(0).count(), 1);
150 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
151 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
152 EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
153 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
154 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
155 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 123);
156 EXPECT_FALSE(data.dimensions_in_condition().has_field());
157
158 data = countMetrics.data(1);
159 EXPECT_EQ(data.bucket_info_size(), 1);
160 EXPECT_EQ(data.bucket_info(0).count(), 1);
161 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
162 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
163 EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
164 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
165 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
166 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 123);
167 ValidateAttributionUidDimension(data.dimensions_in_condition(),
168 android::util::WAKELOCK_STATE_CHANGED, 111);
169
170 data = countMetrics.data(2);
171 EXPECT_EQ(data.bucket_info_size(), 1);
172 EXPECT_EQ(data.bucket_info(0).count(), 3);
173 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
174 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
175 EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
176 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
177 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
178 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 456);
179 ValidateAttributionUidDimension(data.dimensions_in_condition(),
180 android::util::WAKELOCK_STATE_CHANGED, 111);
181
182 data = countMetrics.data(3);
183 EXPECT_EQ(data.bucket_info_size(), 2);
184 EXPECT_EQ(data.bucket_info(0).count(), 2);
185 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
186 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
187 EXPECT_EQ(data.bucket_info(1).count(), 1);
188 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
189 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
190 EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
191 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
192 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
193 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 456);
194 ValidateAttributionUidDimension(data.dimensions_in_condition(),
195 android::util::WAKELOCK_STATE_CHANGED, 333);
196
197 data = countMetrics.data(4);
198 EXPECT_EQ(data.bucket_info_size(), 1);
199 EXPECT_EQ(data.bucket_info(0).count(), 2);
200 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
201 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
202 EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
203 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
204 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
205 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 789);
206 EXPECT_FALSE(data.dimensions_in_condition().has_field());
207
208 data = countMetrics.data(5);
209 EXPECT_EQ(data.bucket_info_size(), 1);
210 EXPECT_EQ(data.bucket_info(0).count(), 1);
211 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
212 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
213 EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
214 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
215 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
216 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 789);
217 ValidateAttributionUidDimension(data.dimensions_in_condition(),
218 android::util::WAKELOCK_STATE_CHANGED, 111);
219
220 data = countMetrics.data(6);
221 EXPECT_EQ(data.bucket_info_size(), 1);
222 EXPECT_EQ(data.bucket_info(0).count(), 1);
223 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
224 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
225 EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
226 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
227 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
228 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 789);
229 ValidateAttributionUidDimension(data.dimensions_in_condition(),
230 android::util::WAKELOCK_STATE_CHANGED, 333);
231 }
232
233 namespace {
234
CreateCountMetric_Link_CombinationCondition()235 StatsdConfig CreateCountMetric_Link_CombinationCondition() {
236 StatsdConfig config;
237 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
238 auto appCrashMatcher = CreateProcessCrashAtomMatcher();
239 *config.add_atom_matcher() = appCrashMatcher;
240 *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
241 *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
242 *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
243 *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
244
245 auto screenIsOffPredicate = CreateScreenIsOffPredicate();
246 auto isSyncingPredicate = CreateIsSyncingPredicate();
247 auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
248 *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
249 {Position::FIRST});
250 syncDimension->add_child()->set_field(2 /* name field*/);
251
252 *config.add_predicate() = screenIsOffPredicate;
253 *config.add_predicate() = isSyncingPredicate;
254 auto combinationPredicate = config.add_predicate();
255 combinationPredicate->set_id(987654);
256 combinationPredicate->mutable_combination()->set_operation(LogicalOperation::OR);
257 addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
258 addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
259
260 auto metric = config.add_count_metric();
261 metric->set_bucket(FIVE_MINUTES);
262 metric->set_id(StringToId("AppCrashMetric"));
263 metric->set_what(appCrashMatcher.id());
264 metric->set_condition(combinationPredicate->id());
265 *metric->mutable_dimensions_in_what() =
266 CreateDimensions(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1 /* uid */});
267 *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
268 android::util::SYNC_STATE_CHANGED, {Position::FIRST});
269
270 // Links between crash atom and condition of app is in syncing.
271 auto links = metric->add_links();
272 links->set_condition(isSyncingPredicate.id());
273 auto dimensionWhat = links->mutable_fields_in_what();
274 dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
275 dimensionWhat->add_child()->set_field(1); // uid field.
276 *links->mutable_fields_in_condition() =
277 CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
278 return config;
279 }
280
281 } // namespace
282
TEST(DimensionInConditionE2eTest,TestCreateCountMetric_Link_OR_CombinationCondition)283 TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition) {
284 ConfigKey cfgKey;
285 auto config = CreateCountMetric_Link_CombinationCondition();
286 int64_t bucketStartTimeNs = 10000000000;
287 int64_t bucketSizeNs =
288 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
289
290 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
291 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
292 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
293 std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
294 CreateAttribution(222, "GMSCoreModule1"),
295 CreateAttribution(222, "GMSCoreModule2")};
296
297 std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(333, "App2"),
298 CreateAttribution(222, "GMSCoreModule1"),
299 CreateAttribution(555, "GMSCoreModule2")};
300
301 std::vector<std::unique_ptr<LogEvent>> events;
302
303 events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + 11));
304 events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + 101));
305 events.push_back(CreateAppCrashEvent(222, bucketStartTimeNs + 101));
306
307 events.push_back(CreateAppCrashEvent(222, bucketStartTimeNs + 201));
308 events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + 211));
309 events.push_back(CreateAppCrashEvent(333, bucketStartTimeNs + 211));
310
311 events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + 401));
312 events.push_back(CreateAppCrashEvent(333, bucketStartTimeNs + 401));
313 events.push_back(CreateAppCrashEvent(555, bucketStartTimeNs + 401));
314
315 events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + bucketSizeNs + 301));
316 events.push_back(CreateAppCrashEvent(333, bucketStartTimeNs + bucketSizeNs + 301));
317
318 events.push_back(CreateAppCrashEvent(777, bucketStartTimeNs + bucketSizeNs + 701));
319
320 events.push_back(
321 CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10));
322 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
323 bucketStartTimeNs + 100));
324 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
325 bucketStartTimeNs + 202));
326 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
327 bucketStartTimeNs + bucketSizeNs + 700));
328
329 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 200));
330 events.push_back(
331 CreateSyncEndEvent(attributions1, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300));
332
333 events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", bucketStartTimeNs + 400));
334 events.push_back(
335 CreateSyncEndEvent(attributions1, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1));
336
337 events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 400));
338 events.push_back(
339 CreateSyncEndEvent(attributions2, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 600));
340
341 sortLogEventsByTimestamp(&events);
342
343 for (const auto& event : events) {
344 processor->OnLogEvent(event.get());
345 }
346
347 ConfigMetricsReportList reports;
348 vector<uint8_t> buffer;
349 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
350 &buffer);
351 EXPECT_TRUE(buffer.size() > 0);
352 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
353 backfillDimensionPath(&reports);
354 backfillStringInReport(&reports);
355 backfillStartEndTimestamp(&reports);
356
357 EXPECT_EQ(reports.reports_size(), 1);
358 EXPECT_EQ(reports.reports(0).metrics_size(), 1);
359 StatsLogReport::CountMetricDataWrapper countMetrics;
360 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
361
362 EXPECT_EQ(countMetrics.data_size(), 5);
363 auto data = countMetrics.data(0);
364 EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
365 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
366 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
367 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
368 EXPECT_FALSE(data.dimensions_in_condition().has_field());
369 EXPECT_EQ(data.bucket_info_size(), 1);
370 EXPECT_EQ(data.bucket_info(0).count(), 1);
371 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
372 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
373
374 data = countMetrics.data(1);
375 EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
376 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
377 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
378 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
379 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
380 android::util::SYNC_STATE_CHANGED, 111, "App1");
381 EXPECT_EQ(data.bucket_info_size(), 1);
382 EXPECT_EQ(data.bucket_info(0).count(), 2);
383 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
384 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
385
386 data = countMetrics.data(2);
387 EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
388 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
389 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
390 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 222);
391 EXPECT_FALSE(data.dimensions_in_condition().has_field());
392 EXPECT_EQ(data.bucket_info_size(), 1);
393 EXPECT_EQ(data.bucket_info(0).count(), 2);
394 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
395 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
396
397 data = countMetrics.data(3);
398 EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
399 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
400 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
401 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 333);
402 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
403 android::util::SYNC_STATE_CHANGED, 333, "App2");
404 EXPECT_EQ(data.bucket_info_size(), 2);
405 EXPECT_EQ(data.bucket_info(0).count(), 1);
406 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
407 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
408 EXPECT_EQ(data.bucket_info(1).count(), 1);
409 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
410 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
411
412 data = countMetrics.data(4);
413 EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
414 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
415 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
416 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 777);
417 EXPECT_FALSE(data.dimensions_in_condition().has_field());
418 EXPECT_EQ(data.bucket_info_size(), 1);
419 EXPECT_EQ(data.bucket_info(0).count(), 1);
420 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
421 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
422 }
423
424 namespace {
425
CreateDurationMetricConfig_NoLink_CombinationCondition(DurationMetric::AggregationType aggregationType)426 StatsdConfig CreateDurationMetricConfig_NoLink_CombinationCondition(
427 DurationMetric::AggregationType aggregationType) {
428 StatsdConfig config;
429 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
430 *config.add_atom_matcher() = CreateBatterySaverModeStartAtomMatcher();
431 *config.add_atom_matcher() = CreateBatterySaverModeStopAtomMatcher();
432 *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
433 *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
434 *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
435 *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
436
437 auto inBatterySaverModePredicate = CreateBatterySaverModePredicate();
438
439 auto screenIsOffPredicate = CreateScreenIsOffPredicate();
440 auto isSyncingPredicate = CreateIsSyncingPredicate();
441 auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
442 *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
443 {Position::FIRST});
444 syncDimension->add_child()->set_field(2 /* name field */);
445
446 *config.add_predicate() = inBatterySaverModePredicate;
447 *config.add_predicate() = screenIsOffPredicate;
448 *config.add_predicate() = isSyncingPredicate;
449 auto combinationPredicate = config.add_predicate();
450 combinationPredicate->set_id(987654);
451 combinationPredicate->mutable_combination()->set_operation(LogicalOperation::OR);
452 addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
453 addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
454
455 auto metric = config.add_duration_metric();
456 metric->set_bucket(FIVE_MINUTES);
457 metric->set_id(StringToId("BatterySaverModeDurationMetric"));
458 metric->set_what(inBatterySaverModePredicate.id());
459 metric->set_condition(combinationPredicate->id());
460 metric->set_aggregation_type(aggregationType);
461 *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
462 android::util::SYNC_STATE_CHANGED, {Position::FIRST});
463 return config;
464 }
465
466 } // namespace
467
TEST(DimensionInConditionE2eTest,TestDurationMetric_NoLink_OR_CombinationCondition)468 TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition) {
469 for (auto aggregationType : { DurationMetric::MAX_SPARSE, DurationMetric::SUM}) {
470 ConfigKey cfgKey;
471 auto config = CreateDurationMetricConfig_NoLink_CombinationCondition(aggregationType);
472 int64_t bucketStartTimeNs = 10000000000;
473 int64_t bucketSizeNs =
474 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
475
476 auto processor = CreateStatsLogProcessor(
477 bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
478 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
479 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
480
481 std::vector<AttributionNodeInternal> attributions1 = {
482 CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
483 CreateAttribution(222, "GMSCoreModule2")};
484
485 std::vector<AttributionNodeInternal> attributions2 = {
486 CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
487 CreateAttribution(555, "GMSCoreModule2")};
488
489 std::vector<std::unique_ptr<LogEvent>> events;
490
491 events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 1));
492 events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 101));
493 events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 110));
494
495 events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 201));
496 events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 500));
497
498 events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 600));
499 events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + bucketSizeNs + 850));
500
501 events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + bucketSizeNs + 870));
502 events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + bucketSizeNs + 900));
503
504 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
505 bucketStartTimeNs + 10));
506 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
507 bucketStartTimeNs + 100));
508 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
509 bucketStartTimeNs + 202));
510 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
511 bucketStartTimeNs + bucketSizeNs + 800));
512
513 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 200));
514 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
515 bucketStartTimeNs + bucketSizeNs + 300));
516
517 events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", bucketStartTimeNs + 400));
518 events.push_back(
519 CreateSyncEndEvent(attributions1, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1));
520
521 events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 401));
522 events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
523 bucketStartTimeNs + bucketSizeNs + 700));
524
525 sortLogEventsByTimestamp(&events);
526
527 for (const auto& event : events) {
528 processor->OnLogEvent(event.get());
529 }
530
531 ConfigMetricsReportList reports;
532 vector<uint8_t> buffer;
533 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
534 &buffer);
535 EXPECT_TRUE(buffer.size() > 0);
536 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
537 backfillDimensionPath(&reports);
538 backfillStringInReport(&reports);
539 backfillStartEndTimestamp(&reports);
540
541 EXPECT_EQ(reports.reports_size(), 1);
542 EXPECT_EQ(reports.reports(0).metrics_size(), 1);
543 StatsLogReport::DurationMetricDataWrapper metrics;
544 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metrics);
545
546 EXPECT_EQ(metrics.data_size(), 3);
547 auto data = metrics.data(0);
548 EXPECT_FALSE(data.dimensions_in_what().has_field());
549 EXPECT_FALSE(data.dimensions_in_condition().has_field());
550 if (aggregationType == DurationMetric::SUM) {
551 EXPECT_EQ(data.bucket_info_size(), 2);
552 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
553 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
554 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
555 bucketStartTimeNs + bucketSizeNs);
556 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 30);
557 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
558 bucketStartTimeNs + bucketSizeNs);
559 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
560 bucketStartTimeNs + 2 * bucketSizeNs);
561 } else {
562 EXPECT_EQ(data.bucket_info_size(), 2);
563 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
564 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
565 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
566 bucketStartTimeNs + bucketSizeNs);
567 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 30);
568 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
569 bucketStartTimeNs + bucketSizeNs);
570 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
571 bucketStartTimeNs + 2 * bucketSizeNs);
572 }
573
574 data = metrics.data(1);
575 EXPECT_FALSE(data.dimensions_in_what().has_field());
576 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
577 android::util::SYNC_STATE_CHANGED, 111, "App1");
578 EXPECT_EQ(data.bucket_info_size(), 2);
579
580 if (aggregationType == DurationMetric::SUM) {
581 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201 + bucketSizeNs - 600);
582 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 300);
583 } else {
584 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201);
585 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 300);
586 }
587 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
588 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
589 bucketStartTimeNs + bucketSizeNs);
590 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
591 bucketStartTimeNs + bucketSizeNs);
592 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
593 bucketStartTimeNs + 2 * bucketSizeNs);
594
595 data = metrics.data(2);
596 EXPECT_FALSE(data.dimensions_in_what().has_field());
597 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
598 android::util::SYNC_STATE_CHANGED, 333, "App2");
599 EXPECT_EQ(data.bucket_info_size(), 2);
600 if (aggregationType == DurationMetric::SUM) {
601 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 + bucketSizeNs - 600);
602 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
603 } else {
604 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401);
605 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs + 700 - 600);
606 }
607 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
608 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
609 bucketStartTimeNs + bucketSizeNs);
610 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
611 bucketStartTimeNs + bucketSizeNs);
612 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
613 bucketStartTimeNs + 2 * bucketSizeNs);
614 }
615 }
616
617 namespace {
618
CreateDurationMetricConfig_Link_CombinationCondition(DurationMetric::AggregationType aggregationType)619 StatsdConfig CreateDurationMetricConfig_Link_CombinationCondition(
620 DurationMetric::AggregationType aggregationType) {
621 StatsdConfig config;
622 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
623 *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
624 *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
625 *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
626 *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
627 *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
628 *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
629
630 auto screenIsOffPredicate = CreateScreenIsOffPredicate();
631 auto isSyncingPredicate = CreateIsSyncingPredicate();
632 auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
633 *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
634 {Position::FIRST});
635 syncDimension->add_child()->set_field(2 /* name field */);
636
637 auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
638 *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
639 CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */});
640
641 *config.add_predicate() = screenIsOffPredicate;
642 *config.add_predicate() = isSyncingPredicate;
643 *config.add_predicate() = isInBackgroundPredicate;
644 auto combinationPredicate = config.add_predicate();
645 combinationPredicate->set_id(987654);
646 combinationPredicate->mutable_combination()->set_operation(LogicalOperation::OR);
647 addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
648 addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
649
650 auto metric = config.add_duration_metric();
651 metric->set_bucket(FIVE_MINUTES);
652 metric->set_id(StringToId("AppInBackgroundMetric"));
653 metric->set_what(isInBackgroundPredicate.id());
654 metric->set_condition(combinationPredicate->id());
655 metric->set_aggregation_type(aggregationType);
656 *metric->mutable_dimensions_in_what() =
657 CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */});
658 *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
659 android::util::SYNC_STATE_CHANGED, {Position::FIRST});
660
661 // Links between crash atom and condition of app is in syncing.
662 auto links = metric->add_links();
663 links->set_condition(isSyncingPredicate.id());
664 auto dimensionWhat = links->mutable_fields_in_what();
665 dimensionWhat->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
666 dimensionWhat->add_child()->set_field(1); // uid field.
667 *links->mutable_fields_in_condition() =
668 CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
669 return config;
670 }
671
672 } // namespace
673
TEST(DimensionInConditionE2eTest,TestDurationMetric_Link_OR_CombinationCondition)674 TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_OR_CombinationCondition) {
675 for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
676 ConfigKey cfgKey;
677 auto config = CreateDurationMetricConfig_Link_CombinationCondition(aggregationType);
678 int64_t bucketStartTimeNs = 10000000000;
679 int64_t bucketSizeNs =
680 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
681
682 auto processor = CreateStatsLogProcessor(
683 bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
684 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
685 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
686
687 std::vector<AttributionNodeInternal> attributions1 = {
688 CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
689 CreateAttribution(222, "GMSCoreModule2")};
690
691 std::vector<AttributionNodeInternal> attributions2 = {
692 CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
693 CreateAttribution(555, "GMSCoreModule2")};
694
695 std::vector<std::unique_ptr<LogEvent>> events;
696
697 events.push_back(CreateMoveToBackgroundEvent(111, bucketStartTimeNs + 101));
698 events.push_back(CreateMoveToForegroundEvent(111, bucketStartTimeNs + 110));
699
700 events.push_back(CreateMoveToBackgroundEvent(111, bucketStartTimeNs + 201));
701 events.push_back(CreateMoveToForegroundEvent(111, bucketStartTimeNs + bucketSizeNs + 100));
702
703 events.push_back(CreateMoveToBackgroundEvent(333, bucketStartTimeNs + 399));
704 events.push_back(CreateMoveToForegroundEvent(333, bucketStartTimeNs + bucketSizeNs + 800));
705
706 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
707 bucketStartTimeNs + 10));
708 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
709 bucketStartTimeNs + 100));
710 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
711 bucketStartTimeNs + 202));
712 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
713 bucketStartTimeNs + bucketSizeNs + 801));
714
715 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 200));
716 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
717 bucketStartTimeNs + bucketSizeNs + 300));
718
719 events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", bucketStartTimeNs + 400));
720 events.push_back(
721 CreateSyncEndEvent(attributions1, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1));
722
723 events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 401));
724 events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
725 bucketStartTimeNs + bucketSizeNs + 700));
726
727 sortLogEventsByTimestamp(&events);
728
729 for (const auto& event : events) {
730 processor->OnLogEvent(event.get());
731 }
732
733 ConfigMetricsReportList reports;
734 vector<uint8_t> buffer;
735 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
736 &buffer);
737 EXPECT_TRUE(buffer.size() > 0);
738 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
739 backfillDimensionPath(&reports);
740 backfillStringInReport(&reports);
741 backfillStartEndTimestamp(&reports);
742
743 EXPECT_EQ(reports.reports_size(), 1);
744 EXPECT_EQ(reports.reports(0).metrics_size(), 1);
745 StatsLogReport::DurationMetricDataWrapper metrics;
746 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metrics);
747
748 EXPECT_EQ(metrics.data_size(), 3);
749 auto data = metrics.data(0);
750 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
751 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
752 EXPECT_FALSE(data.dimensions_in_condition().has_field());
753 EXPECT_EQ(data.bucket_info_size(), 1);
754 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
755 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
756 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
757
758 data = metrics.data(1);
759 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
760 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
761 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
762 android::util::SYNC_STATE_CHANGED, 111, "App1");
763 if (aggregationType == DurationMetric::SUM) {
764 EXPECT_EQ(data.bucket_info_size(), 2);
765 EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 201);
766 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
767 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
768 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
769 bucketStartTimeNs + bucketSizeNs);
770 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
771 bucketStartTimeNs + bucketSizeNs);
772 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
773 bucketStartTimeNs + 2 * bucketSizeNs);
774 } else {
775 EXPECT_EQ(data.bucket_info_size(), 1);
776 EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs + 100 - 201);
777 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
778 bucketStartTimeNs + bucketSizeNs);
779 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
780 bucketStartTimeNs + 2 * bucketSizeNs);
781 }
782
783 data = metrics.data(2);
784 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
785 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 333);
786 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
787 android::util::SYNC_STATE_CHANGED, 333, "App2");
788 if (aggregationType == DurationMetric::SUM) {
789 EXPECT_EQ(data.bucket_info_size(), 2);
790 EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 401);
791 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
792 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
793 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
794 bucketStartTimeNs + bucketSizeNs);
795 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
796 bucketStartTimeNs + bucketSizeNs);
797 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
798 bucketStartTimeNs + 2 * bucketSizeNs);
799 } else {
800 EXPECT_EQ(data.bucket_info_size(), 1);
801 EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs + 299);
802 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
803 bucketStartTimeNs + bucketSizeNs);
804 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
805 bucketStartTimeNs + 2 * bucketSizeNs);
806 }
807 }
808 }
809
810 #else
811 GTEST_LOG_(INFO) << "This test does nothing.\n";
812 #endif
813
814 } // namespace statsd
815 } // namespace os
816 } // namespace android
817