Fix recovery of stats data from previous input while using
ProtoOutputStream
- Specify the length of message to avoid libprotoutil from thinking that
we are trying to write bool
- We only attach the previous dump file to the upload file where config
key matches
- Store ConfigMetricsReport (instead of ConfigMetricsReportList) onto
disk
- Stop use stack after scope in StorageManager
- Migrate UidMap to use ProtoOutputStream and renaming variables to
prevent confusion
Bug: 74021554
Bug: 75968524
Test: manual test, statsd_test, CTS tests
Change-Id: Iedf52633d7f5b985f5a934a3fb5a0c3c3b2e7fd1
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 652ec9d..4a1e3d6 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -231,14 +231,13 @@
}
}
+/*
+ * onDumpReport dumps serialized ConfigMetricsReportList into outData.
+ */
void StatsLogProcessor::onDumpReport(const ConfigKey& key, const uint64_t dumpTimeStampNs,
vector<uint8_t>* outData) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
- onDumpReportLocked(key, dumpTimeStampNs, outData);
-}
-void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t dumpTimeStampNs,
- vector<uint8_t>* outData) {
auto it = mMetricsManagers.find(key);
if (it == mMetricsManagers.end()) {
ALOGW("Config source %s does not exist", key.ToString().c_str());
@@ -261,35 +260,14 @@
// Start of ConfigMetricsReport (reports).
uint64_t reportsToken =
proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
-
- int64_t lastReportTimeNs = it->second->getLastReportTimeNs();
- int64_t lastReportWallClockNs = it->second->getLastReportWallClockNs();
-
- // First, fill in ConfigMetricsReport using current data on memory, which
- // starts from filling in StatsLogReport's.
- it->second->onDumpReport(dumpTimeStampNs, &proto);
-
- // Fill in UidMap.
- vector<uint8_t> uidMap;
- mUidMap->getOutput(key, &uidMap);
- proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP, uidMap.data());
-
- // Fill in the timestamps.
- proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS,
- (long long)lastReportTimeNs);
- proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS,
- (long long)dumpTimeStampNs);
- proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS,
- (long long)lastReportWallClockNs);
- proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS,
- (long long)getWallClockNs());
-
- // End of ConfigMetricsReport (reports).
+ onConfigMetricsReportLocked(key, dumpTimeStampNs, &proto);
proto.end(reportsToken);
+ // End of ConfigMetricsReport (reports).
+
// Then, check stats-data directory to see there's any file containing
// ConfigMetricsReport from previous shutdowns to concatenate to reports.
- StorageManager::appendConfigMetricsReport(proto);
+ StorageManager::appendConfigMetricsReport(key, &proto);
if (outData != nullptr) {
outData->clear();
@@ -307,6 +285,40 @@
StatsdStats::getInstance().noteMetricsReportSent(key);
}
+/*
+ * onConfigMetricsReportLocked dumps serialized ConfigMetricsReport into outData.
+ */
+void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
+ const uint64_t dumpTimeStampNs,
+ ProtoOutputStream* proto) {
+ // We already checked whether key exists in mMetricsManagers in
+ // WriteDataToDisk.
+ auto it = mMetricsManagers.find(key);
+ int64_t lastReportTimeNs = it->second->getLastReportTimeNs();
+ int64_t lastReportWallClockNs = it->second->getLastReportWallClockNs();
+
+ // First, fill in ConfigMetricsReport using current data on memory, which
+ // starts from filling in StatsLogReport's.
+ it->second->onDumpReport(dumpTimeStampNs, proto);
+
+ // Fill in UidMap.
+ uint64_t uidMapToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP);
+ mUidMap->appendUidMap(key, proto);
+ proto->end(uidMapToken);
+
+ // Fill in the timestamps.
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS,
+ (long long)lastReportTimeNs);
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS,
+ (long long)dumpTimeStampNs);
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS,
+ (long long)lastReportWallClockNs);
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS,
+ (long long)getWallClockNs());
+
+
+}
+
void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
auto it = mMetricsManagers.find(key);
@@ -360,11 +372,17 @@
std::lock_guard<std::mutex> lock(mMetricsMutex);
for (auto& pair : mMetricsManagers) {
const ConfigKey& key = pair.first;
- vector<uint8_t> data;
- onDumpReportLocked(key, getElapsedRealtimeNs(), &data);
+ ProtoOutputStream proto;
+ onConfigMetricsReportLocked(key, getElapsedRealtimeNs(), &proto);
string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
(long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
- StorageManager::writeFile(file_name.c_str(), &data[0], data.size());
+ android::base::unique_fd fd(open(file_name.c_str(),
+ O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR));
+ if (fd == -1) {
+ VLOG("Attempt to write %s but failed", file_name.c_str());
+ return;
+ }
+ proto.flush(fd.get());
}
}