summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Siim Sammul <siims@google.com> 2022-04-25 19:55:20 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2022-04-25 19:55:20 +0000
commitba8ea9baef208b13f422a1a7ba90dec75b93833d (patch)
tree038953ec922d1e5a40c9a91f67e42ba4d8207123
parent6366b11d030260d34298617bb9381ce0257ab9b6 (diff)
parent48ecaf9d882adfe7f7110f19287b7419edbf1f33 (diff)
Merge "Count the number of dropped events due to rate limiting and attach that number to the header of the dropbox entry." into tm-dev am: 48ecaf9d88
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17619726 Change-Id: I7f717fa0bfdc6f18cf0b624c2ccc9d1b5ecdf5ef Ignore-AOSP-First: this is an automerge Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java6
-rw-r--r--services/core/java/com/android/server/am/DropboxRateLimiter.java49
-rw-r--r--services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java49
3 files changed, 82 insertions, 22 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b9a55f990ce5..c5a4ca4dc0e5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8713,7 +8713,9 @@ public class ActivityManagerService extends IActivityManager.Stub
if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
// Check if we should rate limit and abort early if needed.
- if (mDropboxRateLimiter.shouldRateLimit(eventType, processName)) return;
+ final DropboxRateLimiter.RateLimitResult rateLimitResult =
+ mDropboxRateLimiter.shouldRateLimit(eventType, processName);
+ if (rateLimitResult.shouldRateLimit()) return;
final StringBuilder sb = new StringBuilder(1024);
appendDropBoxProcessHeaders(process, processName, sb);
@@ -8762,6 +8764,8 @@ public class ActivityManagerService extends IActivityManager.Stub
millisSinceOldestPendingRead).append("\n");
}
}
+ sb.append("Dropped-Count: ").append(
+ rateLimitResult.droppedCountSinceRateLimitActivated()).append("\n");
sb.append("\n");
// Do the rest in a worker thread to avoid blocking the caller on I/O
diff --git a/services/core/java/com/android/server/am/DropboxRateLimiter.java b/services/core/java/com/android/server/am/DropboxRateLimiter.java
index c51702359a6b..672736df88f3 100644
--- a/services/core/java/com/android/server/am/DropboxRateLimiter.java
+++ b/services/core/java/com/android/server/am/DropboxRateLimiter.java
@@ -49,7 +49,7 @@ public class DropboxRateLimiter {
}
/** Determines whether dropbox entries of a specific tag and process should be rate limited. */
- public boolean shouldRateLimit(String eventType, String processName) {
+ public RateLimitResult shouldRateLimit(String eventType, String processName) {
// Rate-limit how often we're willing to do the heavy lifting to collect and record logs.
final long now = mClock.uptimeMillis();
synchronized (mErrorClusterRecords) {
@@ -60,17 +60,33 @@ public class DropboxRateLimiter {
if (errRecord == null) {
errRecord = new ErrorRecord(now, 1);
mErrorClusterRecords.put(errorKey(eventType, processName), errRecord);
- } else if (now - errRecord.getStartTime() > RATE_LIMIT_BUFFER_DURATION) {
+ return new RateLimitResult(false, 0);
+ }
+
+ if (now - errRecord.getStartTime() > RATE_LIMIT_BUFFER_DURATION) {
errRecord.setStartTime(now);
errRecord.setCount(1);
- } else {
- errRecord.incrementCount();
- if (errRecord.getCount() > RATE_LIMIT_ALLOWED_ENTRIES) return true;
+ return new RateLimitResult(false, recentlyDroppedCount(errRecord));
+ }
+
+ errRecord.incrementCount();
+ if (errRecord.getCount() > RATE_LIMIT_ALLOWED_ENTRIES) {
+ return new RateLimitResult(true, recentlyDroppedCount(errRecord));
}
}
- return false;
+ return new RateLimitResult(false, 0);
}
+ /**
+ * Returns the number of entries of a certain type and process that have recenlty been
+ * dropped. Resets every RATE_LIMIT_BUFFER_DURATION if events are still actively created or
+ * RATE_LIMIT_BUFFER_EXPIRY if not. */
+ private int recentlyDroppedCount(ErrorRecord errRecord) {
+ if (errRecord == null || errRecord.getCount() < RATE_LIMIT_ALLOWED_ENTRIES) return 0;
+ return errRecord.getCount() - RATE_LIMIT_ALLOWED_ENTRIES;
+ }
+
+
private void maybeRemoveExpiredRecords(long now) {
if (now - mLastMapCleanUp <= RATE_LIMIT_BUFFER_EXPIRY) return;
@@ -87,6 +103,27 @@ public class DropboxRateLimiter {
return eventType + processName;
}
+ /** Holds information on whether we should rate limit and how many events have been dropped. */
+ public class RateLimitResult {
+ boolean mShouldRateLimit;
+ int mDroppedCountSinceRateLimitActivated;
+
+ public RateLimitResult(boolean shouldRateLimit, int droppedCountSinceRateLimitActivated) {
+ mShouldRateLimit = shouldRateLimit;
+ mDroppedCountSinceRateLimitActivated = droppedCountSinceRateLimitActivated;
+ }
+
+ /** Whether to rate limit. */
+ public boolean shouldRateLimit() {
+ return mShouldRateLimit;
+ }
+
+ /** The number of dropped events since rate limit was activated. */
+ public int droppedCountSinceRateLimitActivated() {
+ return mDroppedCountSinceRateLimitActivated;
+ }
+ }
+
private class ErrorRecord {
long mStartTime;
int mCount;
diff --git a/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java b/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
index 00f4c3908f26..5c91b8b4717f 100644
--- a/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -43,34 +44,52 @@ public class DropboxRateLimiterTest {
@Test
public void testMultipleProcesses() {
// The first 5 entries should not be rate limited.
- assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
- assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
- assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
- assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
- assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
// Different processes and tags should not get rate limited either.
- assertFalse(mRateLimiter.shouldRateLimit("tag", "process2"));
- assertFalse(mRateLimiter.shouldRateLimit("tag2", "process"));
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process2").shouldRateLimit());
+ assertFalse(mRateLimiter.shouldRateLimit("tag2", "process").shouldRateLimit());
// The 6th entry of the same process should be rate limited.
- assertTrue(mRateLimiter.shouldRateLimit("tag", "process"));
+ assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
}
@Test
public void testBufferClearing() throws Exception {
// The first 5 entries should not be rate limited.
- assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
- assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
- assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
- assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
- assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
// The 6th entry of the same process should be rate limited.
- assertTrue(mRateLimiter.shouldRateLimit("tag", "process"));
+ assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
// After 11 seconds there should be nothing left in the buffer and the same type of entry
// should not get rate limited anymore.
mClock.setOffsetMillis(11000);
- assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+ }
+
+ @Test
+ public void testRecentlyDroppedCount() throws Exception {
+ assertEquals(0,
+ mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
+ assertEquals(0,
+ mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
+ assertEquals(0,
+ mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
+ assertEquals(0,
+ mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
+ assertEquals(0,
+ mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
+ assertEquals(1,
+ mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
+ assertEquals(2,
+ mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
}
private static class TestClock implements DropboxRateLimiter.Clock {