Home | History | Annotate | Download | only in e2e
      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