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>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user