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;
|
if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
|
||||||
|
|
||||||
// Check if we should rate limit and abort early if needed.
|
// 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);
|
final StringBuilder sb = new StringBuilder(1024);
|
||||||
appendDropBoxProcessHeaders(process, processName, sb);
|
appendDropBoxProcessHeaders(process, processName, sb);
|
||||||
@@ -8762,6 +8764,8 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
millisSinceOldestPendingRead).append("\n");
|
millisSinceOldestPendingRead).append("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sb.append("Dropped-Count: ").append(
|
||||||
|
rateLimitResult.droppedCountSinceRateLimitActivated()).append("\n");
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
|
|
||||||
// Do the rest in a worker thread to avoid blocking the caller on I/O
|
// 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. */
|
/** 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.
|
// Rate-limit how often we're willing to do the heavy lifting to collect and record logs.
|
||||||
final long now = mClock.uptimeMillis();
|
final long now = mClock.uptimeMillis();
|
||||||
synchronized (mErrorClusterRecords) {
|
synchronized (mErrorClusterRecords) {
|
||||||
@@ -60,17 +60,33 @@ public class DropboxRateLimiter {
|
|||||||
if (errRecord == null) {
|
if (errRecord == null) {
|
||||||
errRecord = new ErrorRecord(now, 1);
|
errRecord = new ErrorRecord(now, 1);
|
||||||
mErrorClusterRecords.put(errorKey(eventType, processName), errRecord);
|
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.setStartTime(now);
|
||||||
errRecord.setCount(1);
|
errRecord.setCount(1);
|
||||||
} else {
|
return new RateLimitResult(false, recentlyDroppedCount(errRecord));
|
||||||
|
}
|
||||||
|
|
||||||
errRecord.incrementCount();
|
errRecord.incrementCount();
|
||||||
if (errRecord.getCount() > RATE_LIMIT_ALLOWED_ENTRIES) return true;
|
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) {
|
private void maybeRemoveExpiredRecords(long now) {
|
||||||
if (now - mLastMapCleanUp <= RATE_LIMIT_BUFFER_EXPIRY) return;
|
if (now - mLastMapCleanUp <= RATE_LIMIT_BUFFER_EXPIRY) return;
|
||||||
|
|
||||||
@@ -87,6 +103,27 @@ public class DropboxRateLimiter {
|
|||||||
return eventType + processName;
|
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 {
|
private class ErrorRecord {
|
||||||
long mStartTime;
|
long mStartTime;
|
||||||
int mCount;
|
int mCount;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.server.am;
|
package com.android.server.am;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
@@ -43,34 +44,52 @@ public class DropboxRateLimiterTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testMultipleProcesses() {
|
public void testMultipleProcesses() {
|
||||||
// The first 5 entries should not be rate limited.
|
// The first 5 entries should not be rate limited.
|
||||||
assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
|
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
|
||||||
assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
|
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
|
||||||
assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
|
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
|
||||||
assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
|
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
|
||||||
assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
|
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
|
||||||
// Different processes and tags should not get rate limited either.
|
// Different processes and tags should not get rate limited either.
|
||||||
assertFalse(mRateLimiter.shouldRateLimit("tag", "process2"));
|
assertFalse(mRateLimiter.shouldRateLimit("tag", "process2").shouldRateLimit());
|
||||||
assertFalse(mRateLimiter.shouldRateLimit("tag2", "process"));
|
assertFalse(mRateLimiter.shouldRateLimit("tag2", "process").shouldRateLimit());
|
||||||
// The 6th entry of the same process should be rate limited.
|
// The 6th entry of the same process should be rate limited.
|
||||||
assertTrue(mRateLimiter.shouldRateLimit("tag", "process"));
|
assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBufferClearing() throws Exception {
|
public void testBufferClearing() throws Exception {
|
||||||
// The first 5 entries should not be rate limited.
|
// The first 5 entries should not be rate limited.
|
||||||
assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
|
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
|
||||||
assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
|
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
|
||||||
assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
|
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
|
||||||
assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
|
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
|
||||||
assertFalse(mRateLimiter.shouldRateLimit("tag", "process"));
|
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
|
||||||
// The 6th entry of the same process should be rate limited.
|
// 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
|
// After 11 seconds there should be nothing left in the buffer and the same type of entry
|
||||||
// should not get rate limited anymore.
|
// should not get rate limited anymore.
|
||||||
mClock.setOffsetMillis(11000);
|
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 {
|
private static class TestClock implements DropboxRateLimiter.Clock {
|
||||||
|
|||||||
Reference in New Issue
Block a user