Merge "Add a field in config to disable/enable the string hashing in metric report." into pi-dev
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 766c2d1..e7f1caf 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -385,7 +385,11 @@
     // This skips the uid map if it's an empty config.
     if (it->second->getNumMetrics() > 0) {
         uint64_t uidMapToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP);
-        mUidMap->appendUidMap(dumpTimeStampNs, key, &str_set, proto);
+        if (it->second->hashStringInReport()) {
+            mUidMap->appendUidMap(dumpTimeStampNs, key, &str_set, proto);
+        } else {
+            mUidMap->appendUidMap(dumpTimeStampNs, key, nullptr, proto);
+        }
         proto->end(uidMapToken);
     }
 
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 2d14b05..4fac0e1 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -74,6 +74,8 @@
                              mAllPeriodicAlarmTrackers, mConditionToMetricMap, mTrackerToMetricMap,
                              mTrackerToConditionMap, mNoReportMetricIds);
 
+    mHashStringsInReport = config.hash_strings_in_metric_report();
+
     if (config.allowed_log_source_size() == 0) {
         mConfigValid = false;
         ALOGE("Log source whitelist is empty! This config won't get any data. Suggest adding at "
@@ -201,8 +203,13 @@
         if (mNoReportMetricIds.find(producer->getMetricId()) == mNoReportMetricIds.end()) {
             uint64_t token = protoOutput->start(
                     FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
-            producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, str_set,
-                                   protoOutput);
+            if (mHashStringsInReport) {
+                producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, str_set,
+                                       protoOutput);
+            } else {
+                producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, nullptr,
+                                       protoOutput);
+            }
             protoOutput->end(token);
         } else {
             producer->clearPastBuckets(dumpTimeStampNs);
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index e143b5a..6f4db48 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -77,6 +77,10 @@
         return mTtlNs <= 0 || timestampNs < mTtlEndNs;
     };
 
+    inline bool hashStringInReport() const {
+        return mHashStringsInReport;
+    };
+
     void refreshTtl(const int64_t currentTimestampNs) {
         if (mTtlNs > 0) {
             mTtlEndNs = currentTimestampNs + mTtlNs;
@@ -118,6 +122,8 @@
 
     bool mConfigValid = false;
 
+    bool mHashStringsInReport = false;
+
     const int64_t mTtlNs;
     int64_t mTtlEndNs;
 
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index eb77299..cf55300 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -364,6 +364,8 @@
 
   optional int64 ttl_in_seconds = 15;
 
+  optional bool hash_strings_in_metric_report = 16 [default = true];
+
   // Field number 1000 is reserved for later use.
   reserved 1000;
 }
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
index dff7977..f038214 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
@@ -29,7 +29,8 @@
 namespace {
 
 StatsdConfig CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
-        DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
+        DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition,
+        bool hashStringInReport) {
     StatsdConfig config;
     config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
     *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
@@ -54,6 +55,7 @@
         syncDimension->add_child()->set_field(2 /* name field*/);
     }
 
+    config.set_hash_strings_in_metric_report(hashStringInReport);
     *config.add_predicate() = scheduledJobPredicate;
     *config.add_predicate() = screenIsOffPredicate;
     *config.add_predicate() = isSyncingPredicate;
@@ -80,258 +82,283 @@
 }  // namespace
 
 TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition) {
-    for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : { true, false }) {
-        for (auto aggregationType : {DurationMetric::MAX_SPARSE, DurationMetric::SUM}) {
-            ConfigKey cfgKey;
-            auto config = CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
-                    aggregationType, isDimensionInConditionSubSetOfConditionTrackerDimension);
-            int64_t bucketStartTimeNs = 10000000000;
-            int64_t bucketSizeNs =
-                    TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+    for (const bool hashStringInReport : { true, false }) {
+        for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : { true, false }) {
+            for (auto aggregationType : {DurationMetric::MAX_SPARSE, DurationMetric::SUM}) {
+                ConfigKey cfgKey;
+                auto config = CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
+                        aggregationType, isDimensionInConditionSubSetOfConditionTrackerDimension,
+                        hashStringInReport);
+                int64_t bucketStartTimeNs = 10000000000;
+                int64_t bucketSizeNs =
+                        TimeUnitToBucketSizeInMillis(
+                            config.duration_metric(0).bucket()) * 1000000LL;
 
-            auto processor = CreateStatsLogProcessor(
-                    bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-            EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-            EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+                auto processor = CreateStatsLogProcessor(
+                        bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+                EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+                EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
-            std::vector<AttributionNodeInternal> attributions1 = {
-                    CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
-                    CreateAttribution(222, "GMSCoreModule2")};
+                std::vector<AttributionNodeInternal> attributions1 = {
+                        CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
+                        CreateAttribution(222, "GMSCoreModule2")};
 
-            std::vector<AttributionNodeInternal> attributions2 = {
-                    CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
-                    CreateAttribution(555, "GMSCoreModule2")};
+                std::vector<AttributionNodeInternal> attributions2 = {
+                        CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
+                        CreateAttribution(555, "GMSCoreModule2")};
 
-            std::vector<std::unique_ptr<LogEvent>> events;
+                std::vector<std::unique_ptr<LogEvent>> events;
 
-            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                           bucketStartTimeNs + 11));
-            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                           bucketStartTimeNs + 40));
+                events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                               bucketStartTimeNs + 11));
+                events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                               bucketStartTimeNs + 40));
 
-            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                           bucketStartTimeNs + 102));
-            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                           bucketStartTimeNs + 450));
+                events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                               bucketStartTimeNs + 102));
+                events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                               bucketStartTimeNs + 450));
 
-            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                           bucketStartTimeNs + 650));
-            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                           bucketStartTimeNs + bucketSizeNs + 100));
+                events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                               bucketStartTimeNs + 650));
+                events.push_back(CreateScreenStateChangedEvent(
+                                    android::view::DISPLAY_STATE_ON,
+                                    bucketStartTimeNs + bucketSizeNs + 100));
 
-            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                           bucketStartTimeNs + bucketSizeNs + 640));
-            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                           bucketStartTimeNs + bucketSizeNs + 650));
+                events.push_back(CreateScreenStateChangedEvent(
+                                    android::view::DISPLAY_STATE_OFF,
+                                    bucketStartTimeNs + bucketSizeNs + 640));
+                events.push_back(CreateScreenStateChangedEvent(
+                                    android::view::DISPLAY_STATE_ON,
+                                    bucketStartTimeNs + bucketSizeNs + 650));
 
-            events.push_back(CreateStartScheduledJobEvent(
-                    {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 2));
-            events.push_back(CreateFinishScheduledJobEvent(
-                    {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
+                events.push_back(CreateStartScheduledJobEvent(
+                        {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 2));
+                events.push_back(CreateFinishScheduledJobEvent(
+                        {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
 
-            events.push_back(CreateStartScheduledJobEvent(
-                    {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
-            events.push_back(CreateFinishScheduledJobEvent(
-                    {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
+                events.push_back(CreateStartScheduledJobEvent(
+                        {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
+                events.push_back(CreateFinishScheduledJobEvent(
+                        {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
 
-            events.push_back(CreateStartScheduledJobEvent(
-                    {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
-            events.push_back(CreateFinishScheduledJobEvent(
-                    {CreateAttribution(8888, "")}, "job2",bucketStartTimeNs + bucketSizeNs + 850));
+                events.push_back(CreateStartScheduledJobEvent(
+                        {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
+                events.push_back(CreateFinishScheduledJobEvent(
+                        {CreateAttribution(8888, "")}, "job2",
+                        bucketStartTimeNs + bucketSizeNs + 850));
 
-            events.push_back(CreateStartScheduledJobEvent(
-                    {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 600));
-            events.push_back(CreateFinishScheduledJobEvent(
-                    {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 900));
+                events.push_back(CreateStartScheduledJobEvent(
+                        {CreateAttribution(8888, "")}, "job1",
+                        bucketStartTimeNs + bucketSizeNs + 600));
+                events.push_back(CreateFinishScheduledJobEvent(
+                        {CreateAttribution(8888, "")}, "job1",
+                        bucketStartTimeNs + bucketSizeNs + 900));
 
-            events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
-                                                  bucketStartTimeNs + 10));
-            events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
-                                                bucketStartTimeNs + 50));
+                events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+                                                      bucketStartTimeNs + 10));
+                events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+                                                    bucketStartTimeNs + 50));
 
-            events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
-                                                  bucketStartTimeNs + 200));
-            events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
-                                                bucketStartTimeNs + bucketSizeNs + 300));
+                events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+                                                      bucketStartTimeNs + 200));
+                events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+                                                    bucketStartTimeNs + bucketSizeNs + 300));
 
-            events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
-                                                  bucketStartTimeNs + 400));
-            events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
-                                                bucketStartTimeNs + bucketSizeNs - 1));
+                events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
+                                                      bucketStartTimeNs + 400));
+                events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
+                                                    bucketStartTimeNs + bucketSizeNs - 1));
 
-            events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
-                                                  bucketStartTimeNs + 401));
-            events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
-                                                bucketStartTimeNs + bucketSizeNs + 700));
+                events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
+                                                      bucketStartTimeNs + 401));
+                events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
+                                                    bucketStartTimeNs + bucketSizeNs + 700));
 
-            sortLogEventsByTimestamp(&events);
+                sortLogEventsByTimestamp(&events);
 
-            for (const auto& event : events) {
-                processor->OnLogEvent(event.get());
-            }
+                for (const auto& event : events) {
+                    processor->OnLogEvent(event.get());
+                }
 
-            ConfigMetricsReportList reports;
-            vector<uint8_t> buffer;
-            processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
-                                    ADB_DUMP, &buffer);
-            EXPECT_TRUE(buffer.size() > 0);
-            EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-            backfillDimensionPath(&reports);
-            backfillStringInReport(&reports);
-            backfillStartEndTimestamp(&reports);
+                ConfigMetricsReportList reports;
+                vector<uint8_t> buffer;
+                processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
+                                        ADB_DUMP, &buffer);
+                EXPECT_TRUE(buffer.size() > 0);
+                EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+                backfillDimensionPath(&reports);
+                backfillStringInReport(&reports);
+                backfillStartEndTimestamp(&reports);
 
-            EXPECT_EQ(reports.reports_size(), 1);
-            EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-            StatsLogReport::DurationMetricDataWrapper metrics;
-            sortMetricDataByDimensionsValue(
-                    reports.reports(0).metrics(0).duration_metrics(), &metrics);
-            if (aggregationType == DurationMetric::SUM) {
-                EXPECT_EQ(metrics.data_size(), 4);
-                auto data = metrics.data(0);
-                EXPECT_EQ(data.dimensions_in_what().field(),
-                          android::util::SCHEDULED_JOB_STATE_CHANGED);
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
-                          2);  // job name field
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
-                          "job0");  // job name
-                ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
-                                                      android::util::SYNC_STATE_CHANGED, 111, "App1");
-                EXPECT_EQ(data.bucket_info_size(), 1);
-                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40 - 11);
-                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
-                          bucketStartTimeNs);
-                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                    bucketStartTimeNs + bucketSizeNs);
+                EXPECT_EQ(reports.reports_size(), 1);
+                EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+                StatsLogReport::DurationMetricDataWrapper metrics;
+                sortMetricDataByDimensionsValue(
+                        reports.reports(0).metrics(0).duration_metrics(), &metrics);
+                if (aggregationType == DurationMetric::SUM) {
+                    EXPECT_EQ(metrics.data_size(), 4);
+                    auto data = metrics.data(0);
+                    EXPECT_EQ(data.dimensions_in_what().field(),
+                              android::util::SCHEDULED_JOB_STATE_CHANGED);
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+                              2);  // job name field
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().
+                                    dimensions_value(0).value_str(),
+                              "job0");  // job name
+                    ValidateAttributionUidAndTagDimension(
+                            data.dimensions_in_condition(),
+                            android::util::SYNC_STATE_CHANGED, 111, "App1");
+                    EXPECT_EQ(data.bucket_info_size(), 1);
+                    EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40 - 11);
+                    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+                              bucketStartTimeNs);
+                    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                        bucketStartTimeNs + bucketSizeNs);
 
 
-                data = metrics.data(1);
-                EXPECT_EQ(data.dimensions_in_what().field(),
-                          android::util::SCHEDULED_JOB_STATE_CHANGED);
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
-                          2);  // job name field
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
-                          "job1");  // job name
-                ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
-                                                      android::util::SYNC_STATE_CHANGED, 333, "App2");
-                EXPECT_EQ(data.bucket_info_size(), 1);
-                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 10);
-                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + bucketSizeNs);
-                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                    bucketStartTimeNs + 2 * bucketSizeNs);
+                    data = metrics.data(1);
+                    EXPECT_EQ(data.dimensions_in_what().field(),
+                              android::util::SCHEDULED_JOB_STATE_CHANGED);
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+                              2);  // job name field
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().
+                                    dimensions_value(0).value_str(),
+                              "job1");  // job name
+                    ValidateAttributionUidAndTagDimension(
+                            data.dimensions_in_condition(),
+                            android::util::SYNC_STATE_CHANGED, 333, "App2");
+                    EXPECT_EQ(data.bucket_info_size(), 1);
+                    EXPECT_EQ(data.bucket_info(0).duration_nanos(), 10);
+                    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + bucketSizeNs);
+                    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                        bucketStartTimeNs + 2 * bucketSizeNs);
 
-                data = metrics.data(2);
-                EXPECT_EQ(data.dimensions_in_what().field(),
-                          android::util::SCHEDULED_JOB_STATE_CHANGED);
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
-                          2);  // job name field
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
-                          "job2");  // job name
-                ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
-                                                      android::util::SYNC_STATE_CHANGED, 111, "App1");
-                EXPECT_EQ(data.bucket_info_size(), 2);
-                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + bucketSizeNs);
-                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201 + bucketSizeNs - 600);
-                EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
-                EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + bucketSizeNs);
-                EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + 2 * bucketSizeNs);
+                    data = metrics.data(2);
+                    EXPECT_EQ(data.dimensions_in_what().field(),
+                              android::util::SCHEDULED_JOB_STATE_CHANGED);
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+                              2);  // job name field
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().
+                                    dimensions_value(0).value_str(),
+                              "job2");  // job name
+                    ValidateAttributionUidAndTagDimension(
+                            data.dimensions_in_condition(),
+                            android::util::SYNC_STATE_CHANGED, 111, "App1");
+                    EXPECT_EQ(data.bucket_info_size(), 2);
+                    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+                    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + bucketSizeNs);
+                    EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201 + bucketSizeNs - 600);
+                    EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
+                    EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + bucketSizeNs);
+                    EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + 2 * bucketSizeNs);
 
-                data = metrics.data(3);
-                EXPECT_EQ(data.dimensions_in_what().field(),
-                          android::util::SCHEDULED_JOB_STATE_CHANGED);
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
-                          2);  // job name field
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
-                          "job2");  // job name
-                ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
-                                                      android::util::SYNC_STATE_CHANGED, 333, "App2");
-                EXPECT_EQ(data.bucket_info_size(), 2);
-                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401 + bucketSizeNs - 600);
-                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + bucketSizeNs);
-                EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100 + 650 - 640);
-                EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + bucketSizeNs);
-                EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + 2 * bucketSizeNs);
-            } else {
-                EXPECT_EQ(metrics.data_size(), 4);
-                auto data = metrics.data(0);
-                EXPECT_EQ(data.dimensions_in_what().field(),
-                          android::util::SCHEDULED_JOB_STATE_CHANGED);
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
-                          2);  // job name field
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
-                          "job0");  // job name
-                ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
-                                                      android::util::SYNC_STATE_CHANGED, 111, "App1");
-                EXPECT_EQ(data.bucket_info_size(), 1);
-                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40 - 11);
-                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
-                          bucketStartTimeNs);
-                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                    bucketStartTimeNs + bucketSizeNs);
+                    data = metrics.data(3);
+                    EXPECT_EQ(data.dimensions_in_what().field(),
+                              android::util::SCHEDULED_JOB_STATE_CHANGED);
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+                              2);  // job name field
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().
+                                    dimensions_value(0).value_str(),
+                              "job2");  // job name
+                    ValidateAttributionUidAndTagDimension(
+                            data.dimensions_in_condition(),
+                            android::util::SYNC_STATE_CHANGED, 333, "App2");
+                    EXPECT_EQ(data.bucket_info_size(), 2);
+                    EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401 + bucketSizeNs - 600);
+                    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+                    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + bucketSizeNs);
+                    EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100 + 650 - 640);
+                    EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + bucketSizeNs);
+                    EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + 2 * bucketSizeNs);
+                } else {
+                    EXPECT_EQ(metrics.data_size(), 4);
+                    auto data = metrics.data(0);
+                    EXPECT_EQ(data.dimensions_in_what().field(),
+                              android::util::SCHEDULED_JOB_STATE_CHANGED);
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+                              2);  // job name field
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().
+                                    dimensions_value(0).value_str(),
+                              "job0");  // job name
+                    ValidateAttributionUidAndTagDimension(
+                            data.dimensions_in_condition(),
+                            android::util::SYNC_STATE_CHANGED, 111, "App1");
+                    EXPECT_EQ(data.bucket_info_size(), 1);
+                    EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40 - 11);
+                    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+                              bucketStartTimeNs);
+                    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                        bucketStartTimeNs + bucketSizeNs);
 
-                data = metrics.data(1);
-                EXPECT_EQ(data.dimensions_in_what().field(),
-                          android::util::SCHEDULED_JOB_STATE_CHANGED);
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
-                          2);  // job name field
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
-                          "job1");  // job name
-                ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
-                                                      android::util::SYNC_STATE_CHANGED, 333, "App2");
-                EXPECT_EQ(data.bucket_info_size(), 1);
-                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 10);
-                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + bucketSizeNs);
-                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                    bucketStartTimeNs + 2 * bucketSizeNs);
+                    data = metrics.data(1);
+                    EXPECT_EQ(data.dimensions_in_what().field(),
+                              android::util::SCHEDULED_JOB_STATE_CHANGED);
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+                              2);  // job name field
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().
+                                    dimensions_value(0).value_str(),
+                              "job1");  // job name
+                    ValidateAttributionUidAndTagDimension(
+                            data.dimensions_in_condition(),
+                            android::util::SYNC_STATE_CHANGED, 333, "App2");
+                    EXPECT_EQ(data.bucket_info_size(), 1);
+                    EXPECT_EQ(data.bucket_info(0).duration_nanos(), 10);
+                    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + bucketSizeNs);
+                    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                        bucketStartTimeNs + 2 * bucketSizeNs);
 
-                data = metrics.data(2);
-                EXPECT_EQ(data.dimensions_in_what().field(),
-                          android::util::SCHEDULED_JOB_STATE_CHANGED);
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
-                          2);  // job name field
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
-                          "job2");  // job name
-                ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
-                                                      android::util::SYNC_STATE_CHANGED, 111, "App1");
-                EXPECT_EQ(data.bucket_info_size(), 2);
-                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + bucketSizeNs);
-                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201);
-                EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
-                EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + bucketSizeNs);
-                EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + 2 * bucketSizeNs);
+                    data = metrics.data(2);
+                    EXPECT_EQ(data.dimensions_in_what().field(),
+                              android::util::SCHEDULED_JOB_STATE_CHANGED);
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+                              2);  // job name field
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+                              "job2");  // job name
+                    ValidateAttributionUidAndTagDimension(
+                            data.dimensions_in_condition(),
+                            android::util::SYNC_STATE_CHANGED, 111, "App1");
+                    EXPECT_EQ(data.bucket_info_size(), 2);
+                    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+                    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + bucketSizeNs);
+                    EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201);
+                    EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
+                    EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + bucketSizeNs);
+                    EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + 2 * bucketSizeNs);
 
-                data = metrics.data(3);
-                EXPECT_EQ(data.dimensions_in_what().field(),
-                          android::util::SCHEDULED_JOB_STATE_CHANGED);
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
-                          2);  // job name field
-                EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
-                          "job2");  // job name
-                ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
-                                                      android::util::SYNC_STATE_CHANGED, 333, "App2");
-                EXPECT_EQ(data.bucket_info_size(), 2);
-                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401);
-                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + bucketSizeNs);
-                EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 110);
-                EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + bucketSizeNs);
-                EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
-                          bucketStartTimeNs + 2 * bucketSizeNs);
+                    data = metrics.data(3);
+                    EXPECT_EQ(data.dimensions_in_what().field(),
+                              android::util::SCHEDULED_JOB_STATE_CHANGED);
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+                              2);  // job name field
+                    EXPECT_EQ(data.dimensions_in_what().value_tuple().
+                                    dimensions_value(0).value_str(),
+                              "job2");  // job name
+                    ValidateAttributionUidAndTagDimension(
+                            data.dimensions_in_condition(),
+                            android::util::SYNC_STATE_CHANGED, 333, "App2");
+                    EXPECT_EQ(data.bucket_info_size(), 2);
+                    EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401);
+                    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+                    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + bucketSizeNs);
+                    EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 110);
+                    EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + bucketSizeNs);
+                    EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+                              bucketStartTimeNs + 2 * bucketSizeNs);
+                }
             }
         }
     }
@@ -588,7 +615,7 @@
 namespace {
 
 StatsdConfig CreateDurationMetricConfig_PartialLink_AND_CombinationCondition(
-        DurationMetric::AggregationType aggregationType) {
+        DurationMetric::AggregationType aggregationType, bool hashStringInReport) {
     StatsdConfig config;
     config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
     *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
@@ -612,6 +639,7 @@
 
     auto screenIsOffPredicate = CreateScreenIsOffPredicate();
 
+    config.set_hash_strings_in_metric_report(hashStringInReport);
     *config.add_predicate() = scheduledJobPredicate;
     *config.add_predicate() = screenIsOffPredicate;
     *config.add_predicate() = isSyncingPredicate;
@@ -645,242 +673,253 @@
 }  // namespace
 
 TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition) {
-    for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
-        ConfigKey cfgKey;
-        auto config =
-                CreateDurationMetricConfig_PartialLink_AND_CombinationCondition(aggregationType);
-        int64_t bucketStartTimeNs = 10000000000;
-        int64_t bucketSizeNs =
-                TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+    for (const bool hashStringInReport : {true, false}) {
+        for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
+            ConfigKey cfgKey;
+            auto config =
+                    CreateDurationMetricConfig_PartialLink_AND_CombinationCondition(
+                            aggregationType, hashStringInReport);
+            int64_t bucketStartTimeNs = 10000000000;
+            int64_t bucketSizeNs =
+                    TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
 
-        auto processor = CreateStatsLogProcessor(
-                bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-        EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-        EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+            auto processor = CreateStatsLogProcessor(
+                    bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+            EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+            EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
-        std::vector<AttributionNodeInternal> attributions1 = {
-                CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
-                CreateAttribution(222, "GMSCoreModule2")};
+            std::vector<AttributionNodeInternal> attributions1 = {
+                    CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
+                    CreateAttribution(222, "GMSCoreModule2")};
 
-        std::vector<AttributionNodeInternal> attributions2 = {
-                CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
-                CreateAttribution(555, "GMSCoreModule2")};
+            std::vector<AttributionNodeInternal> attributions2 = {
+                    CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
+                    CreateAttribution(555, "GMSCoreModule2")};
 
-        std::vector<AttributionNodeInternal> attributions3 = {
-                CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
-                CreateAttribution(555, "GMSCoreModule2")};
+            std::vector<AttributionNodeInternal> attributions3 = {
+                    CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
+                    CreateAttribution(555, "GMSCoreModule2")};
 
-        std::vector<std::unique_ptr<LogEvent>> events;
+            std::vector<std::unique_ptr<LogEvent>> events;
 
-        events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                       bucketStartTimeNs + 55));
-        events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                       bucketStartTimeNs + 120));
-        events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                       bucketStartTimeNs + 121));
-        events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                       bucketStartTimeNs + 450));
+            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                           bucketStartTimeNs + 55));
+            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                           bucketStartTimeNs + 120));
+            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                           bucketStartTimeNs + 121));
+            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                           bucketStartTimeNs + 450));
 
-        events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                       bucketStartTimeNs + 501));
-        events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                       bucketStartTimeNs + bucketSizeNs + 100));
+            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                           bucketStartTimeNs + 501));
+            events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                           bucketStartTimeNs + bucketSizeNs + 100));
 
-        events.push_back(CreateStartScheduledJobEvent(
-                {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
-        events.push_back(CreateFinishScheduledJobEvent(
-                {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
+            events.push_back(CreateStartScheduledJobEvent(
+                    {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
+            events.push_back(CreateFinishScheduledJobEvent(
+                    {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
 
-        events.push_back(CreateStartScheduledJobEvent(
-                {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
-        events.push_back(CreateFinishScheduledJobEvent(
-                {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
-        events.push_back(CreateStartScheduledJobEvent(
-                {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
-        events.push_back(CreateFinishScheduledJobEvent(
-                {CreateAttribution(333, "App2")}, "job2",
-                bucketStartTimeNs + bucketSizeNs + 850));
+            events.push_back(CreateStartScheduledJobEvent(
+                    {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
+            events.push_back(CreateFinishScheduledJobEvent(
+                    {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
+            events.push_back(CreateStartScheduledJobEvent(
+                    {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
+            events.push_back(CreateFinishScheduledJobEvent(
+                    {CreateAttribution(333, "App2")}, "job2",
+                    bucketStartTimeNs + bucketSizeNs + 850));
 
-        events.push_back(
-            CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
-                                         bucketStartTimeNs + bucketSizeNs - 2));
-        events.push_back(
-            CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
-                                          bucketStartTimeNs + bucketSizeNs + 900));
+            events.push_back(
+                CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
+                                             bucketStartTimeNs + bucketSizeNs - 2));
+            events.push_back(
+                CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
+                                              bucketStartTimeNs + bucketSizeNs + 900));
 
-        events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
-                                              bucketStartTimeNs + 50));
-        events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
-                                            bucketStartTimeNs + 110));
+            events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+                                                  bucketStartTimeNs + 50));
+            events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+                                                bucketStartTimeNs + 110));
 
-        events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
-                                              bucketStartTimeNs + 300));
-        events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
-                                            bucketStartTimeNs + bucketSizeNs + 700));
-        events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
-                                              bucketStartTimeNs + 400));
-        events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
-                                            bucketStartTimeNs + bucketSizeNs - 1));
+            events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
+                                                  bucketStartTimeNs + 300));
+            events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
+                                                bucketStartTimeNs + bucketSizeNs + 700));
+            events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
+                                                  bucketStartTimeNs + 400));
+            events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
+                                                bucketStartTimeNs + bucketSizeNs - 1));
 
-        events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
-                                              bucketStartTimeNs + 550));
-        events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
-                                            bucketStartTimeNs + 800));
-        events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
-                                              bucketStartTimeNs + bucketSizeNs - 1));
-        events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
-                                            bucketStartTimeNs + bucketSizeNs + 700));
+            events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
+                                                  bucketStartTimeNs + 550));
+            events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
+                                                bucketStartTimeNs + 800));
+            events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
+                                                  bucketStartTimeNs + bucketSizeNs - 1));
+            events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
+                                                bucketStartTimeNs + bucketSizeNs + 700));
 
-        sortLogEventsByTimestamp(&events);
+            sortLogEventsByTimestamp(&events);
 
-        for (const auto& event : events) {
-            processor->OnLogEvent(event.get());
-        }
+            for (const auto& event : events) {
+                processor->OnLogEvent(event.get());
+            }
 
-        ConfigMetricsReportList reports;
-        vector<uint8_t> buffer;
-        processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
-                                &buffer);
-        EXPECT_TRUE(buffer.size() > 0);
-        EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-        backfillDimensionPath(&reports);
-        backfillStringInReport(&reports);
-        backfillStartEndTimestamp(&reports);
+            ConfigMetricsReportList reports;
+            vector<uint8_t> buffer;
+            processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
+                                    ADB_DUMP, &buffer);
+            EXPECT_TRUE(buffer.size() > 0);
+            EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+            backfillDimensionPath(&reports);
+            backfillStringInReport(&reports);
+            backfillStartEndTimestamp(&reports);
 
-        EXPECT_EQ(reports.reports_size(), 1);
-        EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-        StatsLogReport::DurationMetricDataWrapper metrics;
-        sortMetricDataByDimensionsValue(
-                reports.reports(0).metrics(0).duration_metrics(), &metrics);
-        if (aggregationType == DurationMetric::SUM) {
-            EXPECT_EQ(metrics.data_size(), 4);
-            auto data = metrics.data(0);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
-            EXPECT_EQ("ReadEmail",
-                      data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
-            EXPECT_EQ(data.bucket_info_size(), 1);
-            EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
-            EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
-                      bucketStartTimeNs);
-            EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + bucketSizeNs);
+            EXPECT_EQ(reports.reports_size(), 1);
+            EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+            StatsLogReport::DurationMetricDataWrapper metrics;
+            sortMetricDataByDimensionsValue(
+                    reports.reports(0).metrics(0).duration_metrics(), &metrics);
+            if (aggregationType == DurationMetric::SUM) {
+                EXPECT_EQ(metrics.data_size(), 4);
+                auto data = metrics.data(0);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
+                EXPECT_EQ("ReadEmail",
+                          data.dimensions_in_condition().value_tuple().
+                                dimensions_value(1).value_str());
+                EXPECT_EQ(data.bucket_info_size(), 1);
+                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
+                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+                          bucketStartTimeNs);
+                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + bucketSizeNs);
 
-            data = metrics.data(1);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
-            EXPECT_EQ("ReadDoc",
-                      data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
-            EXPECT_EQ(data.bucket_info_size(), 1);
-            EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-            EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + bucketSizeNs);
-            EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 1 - 600 + 50);
+                data = metrics.data(1);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
+                EXPECT_EQ("ReadDoc",
+                          data.dimensions_in_condition().value_tuple().
+                                dimensions_value(1).value_str());
+                EXPECT_EQ(data.bucket_info_size(), 1);
+                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + bucketSizeNs);
+                EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 1 - 600 + 50);
 
-            data = metrics.data(2);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
-            EXPECT_EQ("ReadEmail",
-                      data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
-            EXPECT_EQ(data.bucket_info_size(), 2);
-            EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-            EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + bucketSizeNs);
-            EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300 + bucketSizeNs - 600);
-            EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
-            EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + bucketSizeNs);
-            EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + 2 * bucketSizeNs);
+                data = metrics.data(2);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
+                EXPECT_EQ("ReadEmail",
+                          data.dimensions_in_condition().value_tuple().
+                                dimensions_value(1).value_str());
+                EXPECT_EQ(data.bucket_info_size(), 2);
+                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + bucketSizeNs);
+                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300 + bucketSizeNs - 600);
+                EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
+                EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + bucketSizeNs);
+                EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + 2 * bucketSizeNs);
 
-            data = metrics.data(3);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
-            EXPECT_EQ("ReadDoc",
-                      data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
-            EXPECT_EQ(data.bucket_info_size(), 2);
-            EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
-            EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-            EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + bucketSizeNs);
-            EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
-            EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + bucketSizeNs);
-            EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + 2 * bucketSizeNs);
-        } else {
-            EXPECT_EQ(metrics.data_size(), 4);
-            auto data = metrics.data(0);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
-            EXPECT_EQ("ReadEmail",
-                      data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
-            EXPECT_EQ(data.bucket_info_size(), 1);
-            EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
-            EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
-                      bucketStartTimeNs);
-            EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                bucketStartTimeNs + bucketSizeNs);
+                data = metrics.data(3);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
+                EXPECT_EQ("ReadDoc",
+                          data.dimensions_in_condition().value_tuple().
+                                dimensions_value(1).value_str());
+                EXPECT_EQ(data.bucket_info_size(), 2);
+                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
+                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + bucketSizeNs);
+                EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
+                EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + bucketSizeNs);
+                EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + 2 * bucketSizeNs);
+            } else {
+                EXPECT_EQ(metrics.data_size(), 4);
+                auto data = metrics.data(0);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
+                EXPECT_EQ("ReadEmail",
+                          data.dimensions_in_condition().value_tuple().
+                                dimensions_value(1).value_str());
+                EXPECT_EQ(data.bucket_info_size(), 1);
+                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
+                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+                          bucketStartTimeNs);
+                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                    bucketStartTimeNs + bucketSizeNs);
 
-            data = metrics.data(1);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
-            EXPECT_EQ("ReadDoc",
-                      data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
-            EXPECT_EQ(data.bucket_info_size(), 2);
-            EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-            EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + bucketSizeNs);
-            EXPECT_EQ(data.bucket_info(0).duration_nanos(), 50);
-            EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 1 - 600);
-            EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + bucketSizeNs);
-            EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + 2 * bucketSizeNs);
+                data = metrics.data(1);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
+                EXPECT_EQ("ReadDoc",
+                          data.dimensions_in_condition().value_tuple().
+                                dimensions_value(1).value_str());
+                EXPECT_EQ(data.bucket_info_size(), 2);
+                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + bucketSizeNs);
+                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 50);
+                EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 1 - 600);
+                EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + bucketSizeNs);
+                EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + 2 * bucketSizeNs);
 
-            data = metrics.data(2);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
-            EXPECT_EQ("ReadEmail",
-                      data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
-            EXPECT_EQ(data.bucket_info_size(), 2);
-            EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-            EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + bucketSizeNs);
-            EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300);
-            EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
-            EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + bucketSizeNs);
-            EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + 2 * bucketSizeNs);
+                data = metrics.data(2);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
+                EXPECT_EQ("ReadEmail",
+                          data.dimensions_in_condition().value_tuple().
+                                dimensions_value(1).value_str());
+                EXPECT_EQ(data.bucket_info_size(), 2);
+                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + bucketSizeNs);
+                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300);
+                EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
+                EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + bucketSizeNs);
+                EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + 2 * bucketSizeNs);
 
-            data = metrics.data(3);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
-            ValidateAttributionUidDimension(
-                data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
-            EXPECT_EQ("ReadDoc",
-                      data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
-            EXPECT_EQ(data.bucket_info_size(), 1);
-            EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101);
-            EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + bucketSizeNs);
-            EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
-                      bucketStartTimeNs + 2 * bucketSizeNs);
+                data = metrics.data(3);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
+                ValidateAttributionUidDimension(
+                    data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
+                EXPECT_EQ("ReadDoc",
+                          data.dimensions_in_condition().value_tuple().
+                                dimensions_value(1).value_str());
+                EXPECT_EQ(data.bucket_info_size(), 1);
+                EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101);
+                EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + bucketSizeNs);
+                EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+                          bucketStartTimeNs + 2 * bucketSizeNs);
+            }
         }
     }
 }