Snap for 8086475 from a51c7bc40555ddc8714d10308ea5e3b30bd8d907 to mainline-ipsec-release

Change-Id: Ic041177269261f5a3e47c1864c14b8c9abde15b3
diff --git a/statsd/src/FieldValue.cpp b/statsd/src/FieldValue.cpp
index c9ccfb9..e78edf0 100644
--- a/statsd/src/FieldValue.cpp
+++ b/statsd/src/FieldValue.cpp
@@ -415,6 +415,33 @@
     }
 }
 
+size_t Value::getSize() const {
+    size_t size = 0;
+    switch (type) {
+        case INT:
+            size = sizeof(int32_t);
+            break;
+        case LONG:
+            size = sizeof(int64_t);
+            break;
+        case FLOAT:
+            size = sizeof(float);
+            break;
+        case DOUBLE:
+            size = sizeof(double);
+            break;
+        case STRING:
+            size = sizeof(char) * str_value.length();
+            break;
+        case STORAGE:
+            size = sizeof(uint8_t) * storage_value.size();
+            break;
+        default:
+            break;
+    }
+    return size;
+}
+
 bool equalDimensions(const std::vector<Matcher>& dimension_a,
                      const std::vector<Matcher>& dimension_b) {
     bool eq = dimension_a.size() == dimension_b.size();
@@ -469,6 +496,14 @@
     return false;
 }
 
+size_t getSize(const std::vector<FieldValue>& fieldValues) {
+    size_t totalSize = 0;
+    for (const FieldValue& fieldValue : fieldValues) {
+        totalSize += fieldValue.getSize();
+    }
+    return totalSize;
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/statsd/src/FieldValue.h b/statsd/src/FieldValue.h
index 538d742..81fe28c 100644
--- a/statsd/src/FieldValue.h
+++ b/statsd/src/FieldValue.h
@@ -161,6 +161,10 @@
         return getDepth() >= depth && getRawPosAtDepth(depth) == kLastBitMask;
     }
 
+    inline size_t getSize() const {
+        return sizeof(mField) + sizeof(mTag);
+    }
+
     inline bool operator==(const Field& that) const {
         return mTag == that.getTag() && mField == that.getField();
     };
@@ -345,6 +349,8 @@
 
     double getDouble() const;
 
+    size_t getSize() const;
+
     Value(const Value& from);
 
     bool operator==(const Value& that) const;
@@ -433,6 +439,10 @@
         return false;
     }
 
+    size_t getSize() const {
+        return mField.getSize() + mValue.getSize();
+    }
+
     Field mField;
     Value mValue;
     Annotations mAnnotations;
@@ -457,6 +467,10 @@
 // Returns true if dimension_a is a subset of dimension_b.
 bool subsetDimensions(const std::vector<Matcher>& dimension_a,
                       const std::vector<Matcher>& dimension_b);
+
+// Estimate the memory size of the FieldValues. This is different from sizeof(FieldValue) because
+// the size is computed at runtime using the actual contents stored in the FieldValue.
+size_t getSize(const std::vector<FieldValue>& fieldValues);
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/statsd/src/metrics/EventMetricProducer.cpp b/statsd/src/metrics/EventMetricProducer.cpp
index cf994f4..31ad229 100644
--- a/statsd/src/metrics/EventMetricProducer.cpp
+++ b/statsd/src/metrics/EventMetricProducer.cpp
@@ -77,6 +77,7 @@
         }
         mConditionSliced = true;
     }
+    mTotalSize = 0;
     VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
          (long long)mBucketSizeNs, (long long)mTimeBaseNs);
 }
@@ -128,6 +129,7 @@
 
 void EventMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
     mAggregatedAtoms.clear();
+    mTotalSize = 0;
     StatsdStats::getInstance().noteBucketDropped(mMetricId);
 }
 
@@ -154,6 +156,7 @@
 
 void EventMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
     mAggregatedAtoms.clear();
+    mTotalSize = 0;
 }
 
 void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
@@ -186,6 +189,7 @@
     protoOutput->end(protoToken);
     if (erase_data) {
         mAggregatedAtoms.clear();
+        mTotalSize = 0;
     }
 }
 
@@ -207,16 +211,15 @@
     AtomDimensionKey key(event.GetTagId(), HashableDimensionKey(event.getValues()));
 
     std::vector<int64_t>& aggregatedTimestampsNs = mAggregatedAtoms[key];
+    if (aggregatedTimestampsNs.empty()) {
+        mTotalSize += getSize(key.getAtomFieldValues().getValues());
+    }
     aggregatedTimestampsNs.push_back(elapsedTimeNs);
+    mTotalSize += sizeof(int64_t); // Add the size of the event timestamp
 }
 
 size_t EventMetricProducer::byteSizeLocked() const {
-    size_t totalSize = 0;
-    for (const auto& [atomDimensionKey, elapsedTimestampsNs] : mAggregatedAtoms) {
-        totalSize += sizeof(FieldValue) * atomDimensionKey.getAtomFieldValues().getValues().size();
-        totalSize += sizeof(int64_t) * elapsedTimestampsNs.size();
-    }
-    return totalSize;
+    return mTotalSize;
 }
 
 }  // namespace statsd
diff --git a/statsd/src/metrics/EventMetricProducer.h b/statsd/src/metrics/EventMetricProducer.h
index 2e3b2e6..76747b6 100644
--- a/statsd/src/metrics/EventMetricProducer.h
+++ b/statsd/src/metrics/EventMetricProducer.h
@@ -96,6 +96,7 @@
     // Maps the field/value pairs of an atom to a list of timestamps used to deduplicate atoms.
     std::unordered_map<AtomDimensionKey, std::vector<int64_t>> mAggregatedAtoms;
 
+    size_t mTotalSize;
 };
 
 }  // namespace statsd
diff --git a/tests/src/android/cts/statsd/alert/AnomalyDetectionTests.java b/tests/src/android/cts/statsd/alert/AnomalyDetectionTests.java
index 69e626c..f08a553 100644
--- a/tests/src/android/cts/statsd/alert/AnomalyDetectionTests.java
+++ b/tests/src/android/cts/statsd/alert/AnomalyDetectionTests.java
@@ -36,7 +36,7 @@
 import com.android.os.AtomsProto.AnomalyDetected;
 import com.android.os.AtomsProto.AppBreadcrumbReported;
 import com.android.os.AtomsProto.Atom;
-import com.android.os.AtomsProto.CpuActiveTime;
+import com.android.os.AtomsProto.DebugElapsedClock;
 import com.android.os.StatsLog.EventMetricData;
 import com.android.tradefed.log.LogUtil.CLog;
 import java.util.List;
@@ -370,10 +370,9 @@
 
     // Test that anomaly detection for pulled metrics work.
     public void testPulledAnomalyDetection() throws Exception {
-        final int ATOM_ID = Atom.CPU_ACTIVE_TIME_FIELD_NUMBER; // A pulled atom
-        final int SLICE_BY_FIELD = CpuActiveTime.UID_FIELD_NUMBER;
+        final int ATOM_ID = Atom.DEBUG_ELAPSED_CLOCK_FIELD_NUMBER; // A pulled atom
         final int VALUE_FIELD =
-                CpuActiveTime.TIME_MILLIS_FIELD_NUMBER; // Something that will be > 0.
+                DebugElapsedClock.ELAPSED_CLOCK_MILLIS_FIELD_NUMBER; // Something that will be > 0.
         final int ATOM_MATCHER_ID = 300;
 
         StatsdConfig.Builder config = getBaseConfig(10, 20, 0 /* threshold: value > 0 */)
@@ -388,11 +387,6 @@
                         .setWhat(ATOM_MATCHER_ID)
                         .setBucket(TimeUnit.CTS)
                         .setSamplingType(GaugeMetric.SamplingType.RANDOM_ONE_SAMPLE)
-                        // Slice by SLICE_BY_FIELD (typical usecase)
-                        .setDimensionsInWhat(FieldMatcher.newBuilder()
-                                .setField(ATOM_ID)
-                                .addChild(FieldMatcher.newBuilder().setField(SLICE_BY_FIELD))
-                        )
                         // Track the VALUE_FIELD (anomaly detection requires exactly one field here)
                         .setGaugeFieldsFilter(
                                 FieldFilter.newBuilder().setFields(FieldMatcher.newBuilder()
@@ -406,8 +400,7 @@
         Thread.sleep(6_000); // Wait long enough to ensure AlarmManager signals >= 1 pull
 
         List<EventMetricData> data = getEventMetricDataList();
-        // There will likely be many anomalies (one for each dimension). There must be at least one.
-        assertThat(data.size()).isAtLeast(1);
+        assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID);
     }
 
diff --git a/tests/src/android/cts/statsd/atom/AtomTestCase.java b/tests/src/android/cts/statsd/atom/AtomTestCase.java
index a4c43e0..1f33c20 100644
--- a/tests/src/android/cts/statsd/atom/AtomTestCase.java
+++ b/tests/src/android/cts/statsd/atom/AtomTestCase.java
@@ -404,17 +404,27 @@
         return atomTimestamp.stream().map(p -> p.first).collect(Collectors.toList());
     }
 
-    protected void backfillGaugeMetricData(GaugeMetricDataWrapper dataWrapper) {
-        for (GaugeMetricData gaugeMetricData : dataWrapper.getDataList()) {
+    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()) {
-                backfillGaugeBucket(bucketInfo.toBuilder());
+                backfilledBuckets.add(backfillGaugeBucket(bucketInfo.toBuilder()));
             }
+            gaugeMetricDataBuilder.clearBucketInfo();
+            gaugeMetricDataBuilder.addAllBucketInfo(backfilledBuckets);
+            backfilledMetricData.add(gaugeMetricDataBuilder.build());
         }
+        dataWrapperBuilder.clearData();
+        dataWrapperBuilder.addAllData(backfilledMetricData);
+        return dataWrapperBuilder.build();
     }
 
-    private void backfillGaugeBucket(GaugeBucketInfo.Builder bucketInfoBuilder) {
+    private GaugeBucketInfo backfillGaugeBucket(GaugeBucketInfo.Builder bucketInfoBuilder) {
         if (bucketInfoBuilder.getAtomCount() != 0) {
-            return;
+            return bucketInfoBuilder.build();
         }
         List<Pair<Atom, Long>> atomTimestampData = new ArrayList<>();
         for (StatsLog.AggregatedAtomInfo atomInfo : bucketInfoBuilder.getAggregatedAtomInfoList()) {
@@ -428,6 +438,7 @@
             bucketInfoBuilder.addAtom(atomTimestamp.first);
             bucketInfoBuilder.addElapsedTimestampNanos(atomTimestamp.second);
         }
+        return bucketInfoBuilder.build();
     }
 
     /**
diff --git a/tests/src/android/cts/statsd/metric/GaugeMetricsTests.java b/tests/src/android/cts/statsd/metric/GaugeMetricsTests.java
index b5d6b83..db6a818 100644
--- a/tests/src/android/cts/statsd/metric/GaugeMetricsTests.java
+++ b/tests/src/android/cts/statsd/metric/GaugeMetricsTests.java
@@ -122,7 +122,7 @@
       assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.GAUGE_METRIC_ID);
       assertThat(metricReport.hasGaugeMetrics()).isTrue();
       StatsLogReport.GaugeMetricDataWrapper gaugeData = metricReport.getGaugeMetrics();
-      backfillGaugeMetricData(gaugeData);
+      gaugeData = backfillGaugeMetricData(gaugeData);
       assertThat(gaugeData.getDataCount()).isEqualTo(1);
 
       int bucketCount = gaugeData.getData(0).getBucketInfoCount();
@@ -321,7 +321,7 @@
         assertThat(metricReport.getIsActive()).isFalse();
 
         StatsLogReport.GaugeMetricDataWrapper gaugeData = metricReport.getGaugeMetrics();
-        backfillGaugeMetricData(gaugeData);
+        gaugeData = backfillGaugeMetricData(gaugeData);
         assertThat(gaugeData.getDataCount()).isEqualTo(1);
         assertThat(gaugeData.getData(0).getBucketInfoCount()).isEqualTo(2);