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