Add unique identifier to configmetricsreportlist

1. Add incrementing report number to both configmetricsreportlist and
   statsdstats
2. Add hash to both configmetricsreportlist and statsdstats
3. Print hash in print-stats
4. Move init_random_seed to main.cpp

Ignore-AOSP-First: merge conflict
Bug: 293200782
Test: atest statsd_test
Change-Id: Idb7bce7ec39c66248f44d3c1b719f0b89b44c082
Merged-In: Idb7bce7ec39c66248f44d3c1b719f0b89b44c082
(cherry picked from commit 96554d2c5ab9dc93c82284a9681e093479bef96b)
diff --git a/statsd/src/StatsLogProcessor.cpp b/statsd/src/StatsLogProcessor.cpp
index 1f697c7..e8260ad 100644
--- a/statsd/src/StatsLogProcessor.cpp
+++ b/statsd/src/StatsLogProcessor.cpp
@@ -63,6 +63,8 @@
 // for ConfigKey
 const int FIELD_ID_UID = 1;
 const int FIELD_ID_ID = 2;
+const int FIELD_ID_REPORT_NUMBER = 3;
+const int FIELD_ID_STATSD_STATS_ID = 4;
 // for ConfigMetricsReport
 // const int FIELD_ID_METRICS = 1; // written in MetricsManager.cpp
 const int FIELD_ID_UID_MAP = 2;
@@ -693,6 +695,18 @@
     } else {
         ALOGW("Config source %s does not exist", key.ToString().c_str());
     }
+
+    if (erase_data) {
+        ++mDumpReportNumbers[key];
+    }
+    proto->write(FIELD_TYPE_INT32 | FIELD_ID_REPORT_NUMBER, mDumpReportNumbers[key]);
+
+    proto->write(FIELD_TYPE_INT32 | FIELD_ID_STATSD_STATS_ID,
+                 StatsdStats::getInstance().getStatsdStatsId());
+    if (erase_data) {
+        StatsdStats::getInstance().noteMetricsReportSent(key, proto->size(),
+                                                         mDumpReportNumbers[key]);
+    }
 }
 
 /*
@@ -711,8 +725,6 @@
         flushProtoToBuffer(proto, outData);
         VLOG("output data size %zu", outData->size());
     }
-
-    StatsdStats::getInstance().noteMetricsReportSent(key, proto.size());
 }
 
 /*
@@ -844,6 +856,8 @@
     StatsdStats::getInstance().noteConfigRemoved(key);
 
     mLastBroadcastTimes.erase(key);
+    mLastByteSizeTimes.erase(key);
+    mDumpReportNumbers.erase(key);
 
     int uid = key.GetUid();
     bool lastConfigForUid = true;
diff --git a/statsd/src/StatsLogProcessor.h b/statsd/src/StatsLogProcessor.h
index 4841263..77463d9 100644
--- a/statsd/src/StatsLogProcessor.h
+++ b/statsd/src/StatsLogProcessor.h
@@ -202,6 +202,9 @@
     // Tracks when we last checked the bytes consumed for each config key.
     std::unordered_map<ConfigKey, int64_t> mLastByteSizeTimes;
 
+    // Tracks the number of times a config with a specified config key has been dumped.
+    std::unordered_map<ConfigKey, int32_t> mDumpReportNumbers;
+
     // Tracks when we last checked the ttl for restricted metrics.
     int64_t mLastTtlTime;
 
diff --git a/statsd/src/StatsService.cpp b/statsd/src/StatsService.cpp
index 00152ea..ed717a3 100644
--- a/statsd/src/StatsService.cpp
+++ b/statsd/src/StatsService.cpp
@@ -230,8 +230,6 @@
 
     init_system_properties();
 
-    init_seed_random();
-
     if (mEventQueue != nullptr) {
         std::thread pushedEventThread([this] { readLogs(); });
         pushedEventThread.detach();
@@ -266,18 +264,6 @@
     }
 }
 
-void StatsService::init_seed_random() {
-    unsigned int seed = 0;
-    // getrandom() reads bytes from urandom source into buf. If getrandom()
-    // is unable to read from urandom source, then it returns -1 and we set
-    // out seed to be time(nullptr) as a fallback.
-    if (TEMP_FAILURE_RETRY(
-                getrandom(static_cast<void*>(&seed), sizeof(unsigned int), GRND_NONBLOCK)) < 0) {
-        seed = time(nullptr);
-    }
-    srand(seed);
-}
-
 void StatsService::init_build_type_callback(void* cookie, const char* /*name*/, const char* value,
                                             uint32_t serial) {
     if (0 == strcmp("eng", value) || 0 == strcmp("userdebug", value)) {
diff --git a/statsd/src/StatsService.h b/statsd/src/StatsService.h
index a10a15e..4026417 100644
--- a/statsd/src/StatsService.h
+++ b/statsd/src/StatsService.h
@@ -266,11 +266,6 @@
     void init_system_properties();
 
     /**
-     * Initiates srand for randomness.
-     */
-    static void init_seed_random();
-
-    /**
      * Helper for loading system properties.
      */
     static void init_build_type_callback(void* cookie, const char* name, const char* value,
diff --git a/statsd/src/guardrail/StatsdStats.cpp b/statsd/src/guardrail/StatsdStats.cpp
index 8e3fb7f..3e38977 100644
--- a/statsd/src/guardrail/StatsdStats.cpp
+++ b/statsd/src/guardrail/StatsdStats.cpp
@@ -58,6 +58,7 @@
 const int FIELD_ID_ACTIVATION_BROADCAST_GUARDRAIL = 19;
 const int FIELD_ID_RESTRICTED_METRIC_QUERY_STATS = 20;
 const int FIELD_ID_SHARD_OFFSET = 21;
+const int FIELD_ID_STATSD_STATS_ID = 22;
 
 const int FIELD_ID_RESTRICTED_METRIC_QUERY_STATS_CALLING_UID = 1;
 const int FIELD_ID_RESTRICTED_METRIC_QUERY_STATS_CONFIG_ID = 2;
@@ -121,6 +122,7 @@
 const int FIELD_ID_CONFIG_STATS_RESTRICTED_CONFIG_FLUSH_LATENCY = 28;
 const int FIELD_ID_CONFIG_STATS_RESTRICTED_CONFIG_DB_SIZE_TIME_SEC = 29;
 const int FIELD_ID_CONFIG_STATS_RESTRICTED_CONFIG_DB_SIZE_BYTES = 30;
+const int FIELD_ID_CONFIG_STATS_DUMP_REPORT_NUMBER = 31;
 
 const int FIELD_ID_INVALID_CONFIG_REASON_ENUM = 1;
 const int FIELD_ID_INVALID_CONFIG_REASON_METRIC_ID = 2;
@@ -162,7 +164,7 @@
         {util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
 };
 
-StatsdStats::StatsdStats() {
+StatsdStats::StatsdStats() : mStatsdStatsId(rand()) {
     mPushedAtomStats.resize(kMaxPushedAtomId + 1);
     mStartTimeSec = getWallClockSec();
 }
@@ -344,22 +346,24 @@
     it->second->data_drop_bytes.push_back(totalBytes);
 }
 
-void StatsdStats::noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes) {
-    noteMetricsReportSent(key, num_bytes, getWallClockSec());
+void StatsdStats::noteMetricsReportSent(const ConfigKey& key, const size_t numBytes,
+                                        const int32_t reportNumber) {
+    noteMetricsReportSent(key, numBytes, getWallClockSec(), reportNumber);
 }
 
-void StatsdStats::noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes,
-                                        int32_t timeSec) {
+void StatsdStats::noteMetricsReportSent(const ConfigKey& key, const size_t numBytes,
+                                        int32_t timeSec, const int32_t reportNumber) {
     lock_guard<std::mutex> lock(mLock);
     auto it = mConfigStats.find(key);
     if (it == mConfigStats.end()) {
         ALOGE("Config key %s not found!", key.ToString().c_str());
         return;
     }
+
     if (it->second->dump_report_stats.size() == kMaxTimestampCount) {
         it->second->dump_report_stats.pop_front();
     }
-    it->second->dump_report_stats.push_back(std::make_pair(timeSec, num_bytes));
+    it->second->dump_report_stats.emplace_back(timeSec, numBytes, reportNumber);
 }
 
 void StatsdStats::noteDeviceInfoTableCreationFailed(const ConfigKey& key) {
@@ -1010,9 +1014,10 @@
         }
 
         for (const auto& dump : configStats->dump_report_stats) {
-            dprintf(out, "\tdump report time: %s(%lld) bytes: %lld\n",
-                    buildTimeString(dump.first).c_str(), (long long)dump.first,
-                    (long long)dump.second);
+            dprintf(out, "\tdump report time: %s(%lld) bytes: %d reportNumber: %d\n",
+                    buildTimeString(dump.mDumpReportTimeSec).c_str(),
+                    (long long)dump.mDumpReportTimeSec, dump.mDumpReportSizeBytes,
+                    dump.mDumpReportNumber);
         }
 
         for (const auto& stats : pair.second->matcher_stats) {
@@ -1173,6 +1178,8 @@
             }
         }
     }
+    dprintf(out, "********Statsd Stats Id***********\n");
+    dprintf(out, "Statsd Stats Id %d\n", mStatsdStatsId);
     dprintf(out, "********Shard Offset Provider stats***********\n");
     dprintf(out, "Shard Offset: %u\n", ShardOffsetProvider::getInstance().getShardOffset());
 }
@@ -1262,15 +1269,21 @@
     }
 
     for (const auto& dump : configStats.dump_report_stats) {
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DUMP_REPORT_TIME |
-                     FIELD_COUNT_REPEATED,
-                     dump.first);
+        proto->write(
+                FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DUMP_REPORT_TIME | FIELD_COUNT_REPEATED,
+                dump.mDumpReportTimeSec);
     }
 
     for (const auto& dump : configStats.dump_report_stats) {
-        proto->write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_STATS_DUMP_REPORT_BYTES |
-                     FIELD_COUNT_REPEATED,
-                     (long long)dump.second);
+        proto->write(
+                FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DUMP_REPORT_BYTES | FIELD_COUNT_REPEATED,
+                (long long)dump.mDumpReportSizeBytes);
+    }
+
+    for (const auto& dump : configStats.dump_report_stats) {
+        proto->write(
+                FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DUMP_REPORT_NUMBER | FIELD_COUNT_REPEATED,
+                dump.mDumpReportNumber);
     }
 
     for (const auto& annotation : configStats.annotations) {
@@ -1520,6 +1533,8 @@
     proto.write(FIELD_TYPE_UINT32 | FIELD_ID_SHARD_OFFSET,
                 static_cast<long>(ShardOffsetProvider::getInstance().getShardOffset()));
 
+    proto.write(FIELD_TYPE_INT32 | FIELD_ID_STATSD_STATS_ID, mStatsdStatsId);
+
     output->clear();
     size_t bufferSize = proto.size();
     output->resize(bufferSize);
diff --git a/statsd/src/guardrail/StatsdStats.h b/statsd/src/guardrail/StatsdStats.h
index 4bf6ffd..8b06f08 100644
--- a/statsd/src/guardrail/StatsdStats.h
+++ b/statsd/src/guardrail/StatsdStats.h
@@ -73,6 +73,17 @@
     int64_t categoryChangedCount = 0;
 } RestrictedMetricStats;
 
+struct DumpReportStats {
+    DumpReportStats(int32_t dumpReportSec, int32_t dumpReportSize, int32_t reportNumber)
+        : mDumpReportTimeSec(dumpReportSec),
+          mDumpReportSizeBytes(dumpReportSize),
+          mDumpReportNumber(reportNumber) {
+    }
+    int32_t mDumpReportTimeSec = 0;
+    int32_t mDumpReportSizeBytes = 0;
+    int32_t mDumpReportNumber = 0;
+};
+
 struct ConfigStats {
     int32_t uid;
     int64_t id;
@@ -101,7 +112,8 @@
     std::list<int32_t> data_drop_time_sec;
     // Number of bytes dropped at corresponding time.
     std::list<int64_t> data_drop_bytes;
-    std::list<std::pair<int32_t, int64_t>> dump_report_stats;
+
+    std::list<DumpReportStats> dump_report_stats;
 
     // Stores how many times a matcher have been matched. The map size is capped by kMaxConfigCount.
     std::map<const int64_t, int> matcher_stats;
@@ -316,7 +328,8 @@
      *
      * The report may be requested via StatsManager API, or through adb cmd.
      */
-    void noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes);
+    void noteMetricsReportSent(const ConfigKey& key, const size_t numBytes,
+                               const int32_t reportNumber);
 
     /**
      * Report failure in creating the device info metadata table for restricted configs.
@@ -637,6 +650,14 @@
      */
     static std::pair<size_t, size_t> getAtomDimensionKeySizeLimits(const int atomId = -1);
 
+    /**
+     * Return the unique identifier for the statsd stats report. This id is
+     * reset on boot.
+     */
+    inline int32_t getStatsdStatsId() const {
+        return mStatsdStatsId;
+    }
+
     typedef struct PullTimeoutMetadata {
         int64_t pullTimeoutUptimeMillis;
         int64_t pullTimeoutElapsedMillis;
@@ -691,6 +712,11 @@
 
     int32_t mStartTimeSec;
 
+    // Random id set using rand() during the initialization. Used to uniquely
+    // identify a session. This is more reliable than mStartTimeSec due to the
+    // unreliable nature of wall clock times.
+    const int32_t mStatsdStatsId;
+
     // Track the number of dropped entries used by the uid map.
     UidMapStats mUidMapStats;
 
@@ -825,7 +851,8 @@
 
     void noteDataDropped(const ConfigKey& key, const size_t totalBytes, int32_t timeSec);
 
-    void noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes, int32_t timeSec);
+    void noteMetricsReportSent(const ConfigKey& key, const size_t numBytes, int32_t timeSec,
+                               const int32_t reportNumber);
 
     void noteBroadcastSent(const ConfigKey& key, int32_t timeSec);
 
diff --git a/statsd/src/main.cpp b/statsd/src/main.cpp
index 14b31a0..6f8c6e5 100644
--- a/statsd/src/main.cpp
+++ b/statsd/src/main.cpp
@@ -23,6 +23,7 @@
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <stdio.h>
+#include <sys/random.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -66,6 +67,18 @@
     sigaction(SIGTERM, &sa, nullptr);
 }
 
+void initSeedRandom() {
+    unsigned int seed = 0;
+    // getrandom() reads bytes from urandom source into buf. If getrandom()
+    // is unable to read from urandom source, then it returns -1 and we set
+    // out seed to be time(nullptr) as a fallback.
+    if (TEMP_FAILURE_RETRY(
+                getrandom(static_cast<void*>(&seed), sizeof(unsigned int), GRND_NONBLOCK)) < 0) {
+        seed = time(nullptr);
+    }
+    srand(seed);
+}
+
 int main(int /*argc*/, char** /*argv*/) {
     // Set up the looper
     sp<Looper> looper(Looper::prepare(0 /* opts */));
@@ -92,6 +105,7 @@
                                        STATSD_INIT_COMPLETED_NO_DELAY_FLAG, FLAG_FALSE)
                                        ? 0
                                        : StatsService::kStatsdInitDelaySecs;
+    initSeedRandom();
     // Create the service
     gStatsService =
             SharedRefBase::make<StatsService>(uidMap, eventQueue, logEventFilter, initEventDelay);
diff --git a/statsd/src/stats_log.proto b/statsd/src/stats_log.proto
index 44add93..15a36c6 100644
--- a/statsd/src/stats_log.proto
+++ b/statsd/src/stats_log.proto
@@ -436,6 +436,10 @@
 
   repeated ConfigMetricsReport reports = 2;
 
+  optional int32 report_number = 3;
+
+  optional int32 statsd_stats_id = 4;
+
   reserved 10 to 13, 101;
 }
 
@@ -510,6 +514,7 @@
         repeated int64 restricted_flush_latency = 28;
         repeated int64 restricted_db_size_time_sec = 29;
         repeated int64 restricted_db_size_bytes = 30;
+        repeated int32 dump_report_number = 31;
     }
 
     repeated ConfigStats config_stats = 3;
@@ -665,6 +670,7 @@
     }
     repeated RestrictedMetricQueryStats restricted_metric_query_stats = 20;
     optional uint32 shard_offset = 21;
+    optional int32 statsd_stats_id = 22;
 }
 
 message AlertTriggerDetails {
diff --git a/statsd/tests/e2e/EventMetric_e2e_test.cpp b/statsd/tests/e2e/EventMetric_e2e_test.cpp
index 81a6d91..a6763af 100644
--- a/statsd/tests/e2e/EventMetric_e2e_test.cpp
+++ b/statsd/tests/e2e/EventMetric_e2e_test.cpp
@@ -257,6 +257,42 @@
     EXPECT_THAT(atom.repeated_enum_field(), ElementsAreArray(enumArrayMatch));
 }
 
+TEST_F(EventMetricE2eTest, TestDumpReportIncrementsReportNumber) {
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+
+    AtomMatcher testAtomReportedStateFirstOnAtomMatcher =
+            CreateTestAtomRepeatedStateFirstOnAtomMatcher();
+    *config.add_atom_matcher() = testAtomReportedStateFirstOnAtomMatcher;
+
+    EventMetric testAtomReportedEventMetric = createEventMetric(
+            "EventTestAtomReported", testAtomReportedStateFirstOnAtomMatcher.id(), nullopt);
+    *config.add_event_metric() = testAtomReportedEventMetric;
+
+    ConfigKey key(123, 987);
+    uint64_t configUpdateTime = 10000000000;  // 0:10
+    sp<StatsLogProcessor> processor =
+            CreateStatsLogProcessor(configUpdateTime, configUpdateTime, config, key);
+
+    uint64_t dumpTimeNs = configUpdateTime + 100 * NS_PER_SEC;
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    ASSERT_EQ(reports.reports_size(), 1);
+
+    EXPECT_EQ(reports.report_number(), 1);
+    EXPECT_EQ(reports.statsd_stats_id(), StatsdStats::getInstance().getStatsdStatsId());
+
+    buffer.clear();
+    processor->onDumpReport(key, dumpTimeNs + 100, true, true, ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    ASSERT_EQ(reports.reports_size(), 1);
+
+    EXPECT_EQ(reports.report_number(), 2);
+    EXPECT_EQ(reports.statsd_stats_id(), StatsdStats::getInstance().getStatsdStatsId());
+}
+
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
diff --git a/statsd/tests/guardrail/StatsdStats_test.cpp b/statsd/tests/guardrail/StatsdStats_test.cpp
index a2f3280..2d831b1 100644
--- a/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -234,9 +234,9 @@
     stats.noteDataDropped(key, 123);
 
     // dump report -> 3
-    stats.noteMetricsReportSent(key, 0);
-    stats.noteMetricsReportSent(key, 0);
-    stats.noteMetricsReportSent(key, 0);
+    stats.noteMetricsReportSent(key, 0, 1);
+    stats.noteMetricsReportSent(key, 0, 2);
+    stats.noteMetricsReportSent(key, 0, 3);
 
     // activation_time_sec -> 2
     stats.noteActiveStatusChanged(key, true);
@@ -258,6 +258,10 @@
     EXPECT_EQ(123, configReport.data_drop_bytes(0));
     ASSERT_EQ(3, configReport.dump_report_time_sec_size());
     ASSERT_EQ(3, configReport.dump_report_data_size_size());
+    ASSERT_EQ(3, configReport.dump_report_number_size());
+    EXPECT_EQ(1, configReport.dump_report_number(0));
+    EXPECT_EQ(2, configReport.dump_report_number(1));
+    EXPECT_EQ(3, configReport.dump_report_number(2));
     ASSERT_EQ(2, configReport.activation_time_sec_size());
     ASSERT_EQ(1, configReport.deactivation_time_sec_size());
     ASSERT_EQ(1, configReport.annotation_size());
@@ -597,7 +601,7 @@
     for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
         stats.noteDataDropped(key, timestamps[i]);
         stats.noteBroadcastSent(key, timestamps[i]);
-        stats.noteMetricsReportSent(key, 0, timestamps[i]);
+        stats.noteMetricsReportSent(key, 0, timestamps[i], i + 1);
         stats.noteActiveStatusChanged(key, true, timestamps[i]);
         stats.noteActiveStatusChanged(key, false, timestamps[i]);
     }
@@ -607,7 +611,7 @@
     // now it should trigger removing oldest timestamp
     stats.noteDataDropped(key, 123, 10000);
     stats.noteBroadcastSent(key, 10000);
-    stats.noteMetricsReportSent(key, 0, 10000);
+    stats.noteMetricsReportSent(key, 0, 10000, 21);
     stats.noteActiveStatusChanged(key, true, 10000);
     stats.noteActiveStatusChanged(key, false, 10000);
 
@@ -624,7 +628,7 @@
     // the oldest timestamp is the second timestamp in history
     EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
     EXPECT_EQ(1, configStats->data_drop_bytes.front());
-    EXPECT_EQ(1, configStats->dump_report_stats.front().first);
+    EXPECT_EQ(1, configStats->dump_report_stats.front().mDumpReportTimeSec);
     EXPECT_EQ(1, configStats->activation_time_sec.front());
     EXPECT_EQ(1, configStats->deactivation_time_sec.front());
 
@@ -632,7 +636,7 @@
     EXPECT_EQ(newTimestamp, configStats->broadcast_sent_time_sec.back());
     EXPECT_EQ(newTimestamp, configStats->data_drop_time_sec.back());
     EXPECT_EQ(123, configStats->data_drop_bytes.back());
-    EXPECT_EQ(newTimestamp, configStats->dump_report_stats.back().first);
+    EXPECT_EQ(newTimestamp, configStats->dump_report_stats.back().mDumpReportTimeSec);
     EXPECT_EQ(newTimestamp, configStats->activation_time_sec.back());
     EXPECT_EQ(newTimestamp, configStats->deactivation_time_sec.back());
 }