MediaMetrics: Garbage collection fixes
1) Correct TransactionLog low water mark
2) Limit number of items historically stored in any TimeMachine property.
Test: Special instrumented atest
Bug: 150547711
Bug: 150598686
Change-Id: I67b25c84b1fb62ce83caa5ec48b800cab85467c9
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index 811e135..d27fa5e 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -113,6 +113,7 @@
case AID_MEDIA_CODEC:
case AID_MEDIA_EX:
case AID_MEDIA_DRM:
+ // case AID_SHELL: // DEBUG ONLY - used for mediametrics_tests to add new keys
case AID_SYSTEM:
// trusted source, only override default values
isTrusted = true;
@@ -145,9 +146,10 @@
}
}
- ALOGV("%s: given uid %d; sanitized uid: %d sanitized pkg: %s "
+ ALOGV("%s: isTrusted:%d given uid %d; sanitized uid: %d sanitized pkg: %s "
"sanitized pkg version: %lld",
__func__,
+ (int)isTrusted,
uid_given, item->getUid(),
item->getPkgName().c_str(),
(long long)item->getPkgVersionCode());
diff --git a/services/mediametrics/TimeMachine.h b/services/mediametrics/TimeMachine.h
index e048d0e..f0bb2fb 100644
--- a/services/mediametrics/TimeMachine.h
+++ b/services/mediametrics/TimeMachine.h
@@ -124,12 +124,23 @@
T&& e, int64_t time = 0) {
if (time == 0) time = systemTime(SYSTEM_TIME_BOOTTIME);
mLastModificationTime = time;
+ if (mPropertyMap.size() >= kKeyMaxProperties &&
+ !mPropertyMap.count(property)) {
+ ALOGV("%s: too many properties, rejecting %s", __func__, property.c_str());
+ return;
+ }
auto& timeSequence = mPropertyMap[property];
Elem el{std::forward<T>(e)};
if (timeSequence.empty() // no elements
|| property.back() == AMEDIAMETRICS_PROP_SUFFIX_CHAR_DUPLICATES_ALLOWED
|| timeSequence.rbegin()->second != el) { // value changed
timeSequence.emplace(time, std::move(el));
+
+ if (timeSequence.size() > kTimeSequenceMaxElements) {
+ ALOGV("%s: restricting maximum elements (discarding oldest) for %s",
+ __func__, property.c_str());
+ timeSequence.erase(timeSequence.begin());
+ }
}
}
@@ -188,6 +199,8 @@
using History = std::map<std::string /* key */, std::shared_ptr<KeyHistory>>;
+ static inline constexpr size_t kTimeSequenceMaxElements = 100;
+ static inline constexpr size_t kKeyMaxProperties = 100;
static inline constexpr size_t kKeyLowWaterMark = 500;
static inline constexpr size_t kKeyHighWaterMark = 1000;
@@ -239,6 +252,9 @@
const int64_t time = item->getTimestamp();
const std::string &key = item->getKey();
+ ALOGV("%s(%zu, %zu): key: %s isTrusted:%d size:%zu",
+ __func__, mKeyLowWaterMark, mKeyHighWaterMark,
+ key.c_str(), (int)isTrusted, item->count());
std::shared_ptr<KeyHistory> keyHistory;
{
std::vector<std::any> garbage;
@@ -446,6 +462,9 @@
/**
* Garbage collects if the TimeMachine size exceeds the high water mark.
*
+ * This GC operation limits the number of keys stored (not the size of properties
+ * stored in each key).
+ *
* \param garbage a type-erased vector of elements to be destroyed
* outside of lock. Move large items to be destroyed here.
*
diff --git a/services/mediametrics/TransactionLog.h b/services/mediametrics/TransactionLog.h
index 27e2c14..190a99e 100644
--- a/services/mediametrics/TransactionLog.h
+++ b/services/mediametrics/TransactionLog.h
@@ -264,7 +264,7 @@
return ret;
}
- const size_t mLowWaterMark = kLogItemsHighWater;
+ const size_t mLowWaterMark = kLogItemsLowWater;
const size_t mHighWaterMark = kLogItemsHighWater;
mutable std::mutex mLock;
diff --git a/services/mediametrics/tests/mediametrics_tests.cpp b/services/mediametrics/tests/mediametrics_tests.cpp
index 27b72eb..b8e566e 100644
--- a/services/mediametrics/tests/mediametrics_tests.cpp
+++ b/services/mediametrics/tests/mediametrics_tests.cpp
@@ -846,3 +846,21 @@
ASSERT_EQ(ll, (int32_t) countNewlines(s.c_str()));
}
}
+
+#if 0
+// Stress test code for garbage collection, you need to enable AID_SHELL as trusted to run
+// in MediaMetricsService.cpp.
+//
+// TODO: Make a dedicated stress test.
+//
+TEST(mediametrics_tests, gc_same_key) {
+ // random keys ignored when empty
+ for (int i = 0; i < 10000000; ++i) {
+ std::unique_ptr<mediametrics::Item> test_key(mediametrics::Item::create("audio.zzz.123"));
+ test_key->set("event#", "hello");
+ test_key->set("value", (int)10);
+ test_key->selfrecord();
+ }
+ //mediaMetrics->dump(fileno(stdout), {} /* args */);
+}
+#endif