Merge "Fix testPulledAnomalyDetection" into sc-v2-dev
diff --git a/framework/Android.bp b/framework/Android.bp
index 3c7597c..a1f33d4 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -77,6 +77,7 @@
     impl_library_visibility: [
         "//frameworks/base/apex/statsd/framework/test:__subpackages__",
         "//packages/modules/StatsD/framework/test:__subpackages__",
+        "//packages/modules/StatsD/service:__subpackages__",
     ],
 
     apex_available: [
diff --git a/service/Android.bp b/service/Android.bp
index da8db91..a0d281d 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -29,7 +29,9 @@
     sdk_version: "system_server_current",
     libs: [
         "framework-annotations-lib",
-        "framework-statsd",
+        // Use the implementation library directly.
+        // TODO(b/204183608): Remove when no longer necessary.
+        "framework-statsd.impl",
     ],
     static_libs: [
         "modules-utils-build",
diff --git a/tests/src/android/cts/statsd/atom/AtomTestCase.java b/tests/src/android/cts/statsd/atom/AtomTestCase.java
index 5f3d902..0380294 100644
--- a/tests/src/android/cts/statsd/atom/AtomTestCase.java
+++ b/tests/src/android/cts/statsd/atom/AtomTestCase.java
@@ -17,7 +17,6 @@
 
 import static android.cts.statsd.atom.DeviceAtomTestCase.DEVICE_SIDE_TEST_APK;
 import static android.cts.statsd.atom.DeviceAtomTestCase.DEVICE_SIDE_TEST_PACKAGE;
-
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
@@ -26,7 +25,6 @@
 import android.service.battery.BatteryServiceDumpProto;
 import android.service.batterystats.BatteryStatsServiceDumpProto;
 import android.service.procstats.ProcessStatsServiceDumpProto;
-
 import com.android.annotations.Nullable;
 import com.android.internal.os.StatsdConfigProto.AtomMatcher;
 import com.android.internal.os.StatsdConfigProto.EventMetric;
@@ -44,32 +42,30 @@
 import com.android.os.AtomsProto.ProcessStatsPackageProto;
 import com.android.os.AtomsProto.ProcessStatsProto;
 import com.android.os.AtomsProto.ProcessStatsStateProto;
+import com.android.os.StatsLog;
 import com.android.os.StatsLog.ConfigMetricsReport;
 import com.android.os.StatsLog.ConfigMetricsReportList;
+import com.android.os.StatsLog.CountMetricData;
 import com.android.os.StatsLog.DurationMetricData;
 import com.android.os.StatsLog.EventMetricData;
 import com.android.os.StatsLog.GaugeBucketInfo;
 import com.android.os.StatsLog.GaugeMetricData;
-import com.android.os.StatsLog.CountMetricData;
 import com.android.os.StatsLog.StatsLogReport;
+import com.android.os.StatsLog.StatsLogReport.GaugeMetricDataWrapper;
 import com.android.os.StatsLog.ValueMetricData;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil;
 import com.android.tradefed.util.CommandResult;
 import com.android.tradefed.util.CommandStatus;
-
+import com.android.tradefed.util.Pair;
 import com.google.common.collect.Range;
 import com.google.common.io.Files;
 import com.google.protobuf.ByteString;
-
-import perfetto.protos.PerfettoConfig.DataSourceConfig;
-import perfetto.protos.PerfettoConfig.FtraceConfig;
-import perfetto.protos.PerfettoConfig.TraceConfig;
-
 import java.io.File;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
@@ -84,6 +80,9 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import perfetto.protos.PerfettoConfig.DataSourceConfig;
+import perfetto.protos.PerfettoConfig.FtraceConfig;
+import perfetto.protos.PerfettoConfig.TraceConfig;
 
 /**
  * Base class for testing Statsd atoms.
@@ -335,7 +334,14 @@
 
         List<EventMetricData> data = new ArrayList<>();
         for (StatsLogReport metric : report.getMetricsList()) {
-            data.addAll(metric.getEventMetrics().getDataList());
+          for (EventMetricData metricData :
+               metric.getEventMetrics().getDataList()) {
+            if (metricData.hasAtom()) {
+              data.add(metricData);
+            } else {
+              data.addAll(backfillAggregatedAtomsInEventMetric(metricData));
+            }
+          }
         }
         data.sort(Comparator.comparing(EventMetricData::getElapsedTimestampNanos));
 
@@ -363,11 +369,15 @@
                 report.getMetrics(0).getGaugeMetrics().getDataList()) {
             assertThat(gaugeMetricData.getBucketInfoCount()).isEqualTo(1);
             GaugeBucketInfo bucketInfo = gaugeMetricData.getBucketInfo(0);
-            for (Atom atom : bucketInfo.getAtomList()) {
-                data.add(atom);
+            if (bucketInfo.getAtomCount() != 0) {
+                for (Atom atom : bucketInfo.getAtomList()) {
+                    data.add(atom);
+                }
+            } else {
+                data.addAll(backFillGaugeBucketAtoms(bucketInfo.getAggregatedAtomInfoList()));
             }
             if (checkTimestampTruncated) {
-                for (long timestampNs: bucketInfo.getElapsedTimestampNanosList()) {
+                for (long timestampNs : bucketInfo.getElapsedTimestampNanosList()) {
                     assertTimestampIsTruncated(timestampNs);
                 }
             }
@@ -380,6 +390,55 @@
         return data;
     }
 
+    private List<Atom> backFillGaugeBucketAtoms(
+            List<StatsLog.AggregatedAtomInfo> atomInfoList) {
+        List<Pair<Atom, Long>> atomTimestamp = new ArrayList<>();
+        for (StatsLog.AggregatedAtomInfo atomInfo : atomInfoList) {
+            for (long timestampNs : atomInfo.getElapsedTimestampNanosList()) {
+                atomTimestamp.add(Pair.create(atomInfo.getAtom(), timestampNs));
+            }
+        }
+        atomTimestamp.sort(Comparator.comparing(o -> o.second));
+        return atomTimestamp.stream().map(p -> p.first).collect(Collectors.toList());
+    }
+
+    protected GaugeMetricDataWrapper backfillGaugeMetricData(GaugeMetricDataWrapper dataWrapper) {
+        GaugeMetricDataWrapper.Builder dataWrapperBuilder = dataWrapper.toBuilder();
+        List<GaugeMetricData> backfilledMetricData = new ArrayList<>();
+        for (GaugeMetricData gaugeMetricData : dataWrapperBuilder.getDataList()) {
+            GaugeMetricData.Builder gaugeMetricDataBuilder = gaugeMetricData.toBuilder();
+            List<GaugeBucketInfo> backfilledBuckets = new ArrayList<>();
+            for (GaugeBucketInfo bucketInfo : gaugeMetricData.getBucketInfoList()) {
+                backfilledBuckets.add(backfillGaugeBucket(bucketInfo.toBuilder()));
+            }
+            gaugeMetricDataBuilder.clearBucketInfo();
+            gaugeMetricDataBuilder.addAllBucketInfo(backfilledBuckets);
+            backfilledMetricData.add(gaugeMetricDataBuilder.build());
+        }
+        dataWrapperBuilder.clearData();
+        dataWrapperBuilder.addAllData(backfilledMetricData);
+        return dataWrapperBuilder.build();
+    }
+
+    private GaugeBucketInfo backfillGaugeBucket(GaugeBucketInfo.Builder bucketInfoBuilder) {
+        if (bucketInfoBuilder.getAtomCount() != 0) {
+            return bucketInfoBuilder.build();
+        }
+        List<Pair<Atom, Long>> atomTimestampData = new ArrayList<>();
+        for (StatsLog.AggregatedAtomInfo atomInfo : bucketInfoBuilder.getAggregatedAtomInfoList()) {
+            for (long timestampNs : atomInfo.getElapsedTimestampNanosList()) {
+                atomTimestampData.add(Pair.create(atomInfo.getAtom(), timestampNs));
+            }
+        }
+        atomTimestampData.sort(Comparator.comparing(o -> o.second));
+        bucketInfoBuilder.clearAggregatedAtomInfo();
+        for (Pair<Atom, Long> atomTimestamp : atomTimestampData) {
+            bucketInfoBuilder.addAtom(atomTimestamp.first);
+            bucketInfoBuilder.addElapsedTimestampNanos(atomTimestamp.second);
+        }
+        return bucketInfoBuilder.build();
+    }
+
     /**
      * Gets the statsd report and extract duration metric data.
      * Note that this also deletes that report from statsd.
@@ -1184,4 +1243,20 @@
         assertWithMessage("Timestamp is not truncated")
                 .that(timestampNs % fiveMinutesInNs).isEqualTo(0);
     }
+
+    protected List<EventMetricData> backfillAggregatedAtomsInEventMetric(
+            EventMetricData metricData) {
+      if (!metricData.hasAggregatedAtomInfo()) {
+        return Collections.singletonList(metricData);
+      }
+      List<EventMetricData> data = new ArrayList<>();
+      StatsLog.AggregatedAtomInfo atomInfo = metricData.getAggregatedAtomInfo();
+      for (long timestamp : atomInfo.getElapsedTimestampNanosList()) {
+        data.add(EventMetricData.newBuilder()
+                     .setAtom(atomInfo.getAtom())
+                     .setElapsedTimestampNanos(timestamp)
+                     .build());
+      }
+      return data;
+    }
 }
diff --git a/tests/src/android/cts/statsd/metadata/MetadataTests.java b/tests/src/android/cts/statsd/metadata/MetadataTests.java
index 7022732..5c59b61 100644
--- a/tests/src/android/cts/statsd/metadata/MetadataTests.java
+++ b/tests/src/android/cts/statsd/metadata/MetadataTests.java
@@ -73,7 +73,7 @@
             Thread.sleep(10);
         }
         doAppBreadcrumbReportedStart(/* irrelevant val */ 6); // Event, after TTL_TIME_SEC secs.
-        Thread.sleep(WAIT_TIME_SHORT);
+        Thread.sleep(WAIT_TIME_LONG);
         report = getStatsdStatsReport();
         LogUtil.CLog.d("got following statsdstats report: " + report.toString());
         foundActiveConfig = false;
diff --git a/tests/src/android/cts/statsd/metric/GaugeMetricsTests.java b/tests/src/android/cts/statsd/metric/GaugeMetricsTests.java
index 2280e13..db6a818 100644
--- a/tests/src/android/cts/statsd/metric/GaugeMetricsTests.java
+++ b/tests/src/android/cts/statsd/metric/GaugeMetricsTests.java
@@ -122,6 +122,7 @@
       assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.GAUGE_METRIC_ID);
       assertThat(metricReport.hasGaugeMetrics()).isTrue();
       StatsLogReport.GaugeMetricDataWrapper gaugeData = metricReport.getGaugeMetrics();
+      gaugeData = backfillGaugeMetricData(gaugeData);
       assertThat(gaugeData.getDataCount()).isEqualTo(1);
 
       int bucketCount = gaugeData.getData(0).getBucketInfoCount();
@@ -320,6 +321,7 @@
         assertThat(metricReport.getIsActive()).isFalse();
 
         StatsLogReport.GaugeMetricDataWrapper gaugeData = metricReport.getGaugeMetrics();
+        gaugeData = backfillGaugeMetricData(gaugeData);
         assertThat(gaugeData.getDataCount()).isEqualTo(1);
         assertThat(gaugeData.getData(0).getBucketInfoCount()).isEqualTo(2);
 
diff --git a/tests/src/android/cts/statsd/metric/MetricActivationTests.java b/tests/src/android/cts/statsd/metric/MetricActivationTests.java
index 339970a..25fa031 100644
--- a/tests/src/android/cts/statsd/metric/MetricActivationTests.java
+++ b/tests/src/android/cts/statsd/metric/MetricActivationTests.java
@@ -31,9 +31,11 @@
 import com.android.os.AtomsProto.Atom;
 import com.android.os.StatsLog.ConfigMetricsReport;
 import com.android.os.StatsLog.ConfigMetricsReportList;
+import com.android.os.StatsLog.EventMetricData;
 import com.android.os.StatsLog.StatsLogReport;
 import com.android.tradefed.log.LogUtil;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -557,9 +559,13 @@
         assertThat(metricReport.hasEventMetrics()).isEqualTo(dataCount > 0);
 
         StatsLogReport.EventMetricDataWrapper eventData = metricReport.getEventMetrics();
-        assertThat(eventData.getDataCount()).isEqualTo(dataCount);
-        for (int i = 0; i < eventData.getDataCount(); i++) {
-            AppBreadcrumbReported atom = eventData.getData(i).getAtom().getAppBreadcrumbReported();
+        List<EventMetricData> eventMetricDataList = new ArrayList<>();
+        for (EventMetricData eventMetricData : eventData.getDataList()) {
+            eventMetricDataList.addAll(backfillAggregatedAtomsInEventMetric(eventMetricData));
+        }
+        assertThat(eventMetricDataList).hasSize(dataCount);
+        for (EventMetricData eventMetricData : eventMetricDataList) {
+            AppBreadcrumbReported atom = eventMetricData.getAtom().getAppBreadcrumbReported();
             assertThat(atom.getLabel()).isEqualTo(metricMatcherLabel);
         }
     }