diff options
| author | 2022-04-25 19:55:20 +0000 | |
|---|---|---|
| committer | 2022-04-25 19:55:20 +0000 | |
| commit | ba8ea9baef208b13f422a1a7ba90dec75b93833d (patch) | |
| tree | 038953ec922d1e5a40c9a91f67e42ba4d8207123 | |
| parent | 6366b11d030260d34298617bb9381ce0257ab9b6 (diff) | |
| parent | 48ecaf9d882adfe7f7110f19287b7419edbf1f33 (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>
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 { |