summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/os/BinderCallsStats.java49
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java56
-rw-r--r--services/core/java/com/android/server/BinderCallsStatsService.java4
3 files changed, 106 insertions, 3 deletions
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 34e8ed406200..875d7c9ee7a6 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -52,17 +52,23 @@ public class BinderCallsStats implements BinderInternal.Observer {
public static final boolean ENABLED_DEFAULT = false;
public static final boolean DETAILED_TRACKING_DEFAULT = true;
public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 100;
+ public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 5000;
+
+ private static class OverflowBinder extends Binder {}
private static final String TAG = "BinderCallsStats";
private static final int CALL_SESSIONS_POOL_SIZE = 100;
private static final int MAX_EXCEPTION_COUNT_SIZE = 50;
private static final String EXCEPTION_COUNT_OVERFLOW_NAME = "overflow";
+ private static final Class<? extends Binder> OVERFLOW_BINDER = OverflowBinder.class;
+ private static final int OVERFLOW_TRANSACTION_CODE = -1;
// Whether to collect all the data: cpu + exceptions + reply/request sizes.
private boolean mDetailedTracking = DETAILED_TRACKING_DEFAULT;
// Sampling period to control how often to track CPU usage. 1 means all calls, 100 means ~1 out
// of 100 requests.
private int mPeriodicSamplingInterval = PERIODIC_SAMPLING_INTERVAL_DEFAULT;
+ private int mMaxBinderCallStatsCount = MAX_BINDER_CALL_STATS_COUNT_DEFAULT;
@GuardedBy("mLock")
private final SparseArray<UidEntry> mUidEntries = new SparseArray<>();
@GuardedBy("mLock")
@@ -71,6 +77,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
private final Object mLock = new Object();
private final Random mRandom;
private long mStartTime = System.currentTimeMillis();
+ private long mCallStatsCount = 0;
private CachedDeviceState.Readonly mDeviceState;
@@ -158,7 +165,13 @@ public class BinderCallsStats implements BinderInternal.Observer {
final CallStat callStat = uidEntry.getOrCreate(
callingUid, s.binderClass, s.transactionCode,
- mDeviceState.isScreenInteractive());
+ mDeviceState.isScreenInteractive(),
+ mCallStatsCount >= mMaxBinderCallStatsCount);
+ final boolean isNewCallStat = callStat.callCount == 0;
+ if (isNewCallStat) {
+ mCallStatsCount++;
+ }
+
callStat.callCount++;
callStat.recordedCallCount++;
callStat.cpuTimeMicros += duration;
@@ -444,6 +457,24 @@ public class BinderCallsStats implements BinderInternal.Observer {
}
}
+ /**
+ * Sets the maximum number of items to track.
+ */
+ public void setMaxBinderCallStats(int maxKeys) {
+ if (maxKeys <= 0) {
+ Slog.w(TAG, "Ignored invalid max value (value must be positive): "
+ + maxKeys);
+ return;
+ }
+
+ synchronized (mLock) {
+ if (maxKeys != mMaxBinderCallStatsCount) {
+ mMaxBinderCallStatsCount = maxKeys;
+ reset();
+ }
+ }
+ }
+
public void setSamplingInterval(int samplingInterval) {
if (samplingInterval <= 0) {
Slog.w(TAG, "Ignored invalid sampling interval (value must be positive): "
@@ -461,6 +492,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
public void reset() {
synchronized (mLock) {
+ mCallStatsCount = 0;
mUidEntries.clear();
mExceptionCounts.clear();
mStartTime = System.currentTimeMillis();
@@ -595,10 +627,21 @@ public class BinderCallsStats implements BinderInternal.Observer {
}
CallStat getOrCreate(int callingUid, Class<? extends Binder> binderClass,
- int transactionCode, boolean screenInteractive) {
+ int transactionCode, boolean screenInteractive, boolean maxCallStatsReached) {
CallStat mapCallStat = get(callingUid, binderClass, transactionCode, screenInteractive);
- // Only create CallStat if it's a new entry, otherwise update existing instance
+ // Only create CallStat if it's a new entry, otherwise update existing instance.
if (mapCallStat == null) {
+ if (maxCallStatsReached) {
+ mapCallStat = get(callingUid, OVERFLOW_BINDER, OVERFLOW_TRANSACTION_CODE,
+ screenInteractive);
+ if (mapCallStat != null) {
+ return mapCallStat;
+ }
+
+ binderClass = OVERFLOW_BINDER;
+ transactionCode = OVERFLOW_TRANSACTION_CODE;
+ }
+
mapCallStat = new CallStat(callingUid, binderClass, transactionCode,
screenInteractive);
CallStatKey key = new CallStatKey();
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index 30309cf64e96..8691e73f82fb 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -557,6 +557,62 @@ public class BinderCallsStatsTest {
assertEquals(0, bcs.getExceptionCounts().size());
}
+ @Test
+ public void testOverflow_sameEntry() {
+ TestBinderCallsStats bcs = new TestBinderCallsStats();
+ bcs.setDetailedTracking(true);
+ bcs.setSamplingInterval(1);
+ bcs.setMaxBinderCallStats(2);
+
+ Binder binder = new Binder();
+ CallSession callSession = bcs.callStarted(binder, 1);
+ bcs.time += 10;
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+ callSession = bcs.callStarted(binder, 1);
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+ callSession = bcs.callStarted(binder, 1);
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+ BinderCallsStats.UidEntry uidEntry = bcs.getUidEntries().get(WORKSOURCE_UID);
+ List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList());
+ assertEquals(1, callStatsList.size());
+ BinderCallsStats.CallStat callStats = callStatsList.get(0);
+ assertEquals(3, callStats.callCount);
+ }
+
+ @Test
+ public void testOverflow_overflowEntry() {
+ TestBinderCallsStats bcs = new TestBinderCallsStats();
+ bcs.setDetailedTracking(true);
+ bcs.setSamplingInterval(1);
+ bcs.setMaxBinderCallStats(1);
+
+ Binder binder = new Binder();
+ CallSession callSession = bcs.callStarted(binder, 1);
+ bcs.time += 10;
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+ callSession = bcs.callStarted(binder, 2);
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+ List<BinderCallsStats.ExportedCallStat> callStatsList = bcs.getExportedCallStats();
+ assertEquals(2, callStatsList.size());
+ BinderCallsStats.ExportedCallStat callStats = callStatsList.get(0);
+ assertEquals(1, callStats.callCount);
+ assertEquals("1", callStats.methodName);
+ assertEquals("android.os.Binder", callStats.className);
+ assertEquals(CALLING_UID, callStats.callingUid);
+
+ callStats = callStatsList.get(1);
+ assertEquals(1, callStats.callCount);
+ assertEquals("-1", callStats.methodName);
+ assertEquals("com.android.internal.os.BinderCallsStats$OverflowBinder",
+ callStats.className);
+ assertEquals(CALLING_UID, callStats.callingUid);
+ }
+
class TestBinderCallsStats extends BinderCallsStats {
public int callingUid = CALLING_UID;
public int workSourceUid = WORKSOURCE_UID;
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index dd960751ab21..98203213e996 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -56,6 +56,7 @@ public class BinderCallsStatsService extends Binder {
private static final String SETTINGS_DETAILED_TRACKING_KEY = "detailed_tracking";
private static final String SETTINGS_UPLOAD_DATA_KEY = "upload_data";
private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
+ private static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count";
private boolean mEnabled;
private final Uri mUri = Settings.Global.getUriFor(Settings.Global.BINDER_CALLS_STATS);
@@ -97,6 +98,9 @@ public class BinderCallsStatsService extends Binder {
mBinderCallsStats.setSamplingInterval(mParser.getInt(
SETTINGS_SAMPLING_INTERVAL_KEY,
BinderCallsStats.PERIODIC_SAMPLING_INTERVAL_DEFAULT));
+ mBinderCallsStats.setSamplingInterval(mParser.getInt(
+ SETTINGS_MAX_CALL_STATS_KEY,
+ BinderCallsStats.MAX_BINDER_CALL_STATS_COUNT_DEFAULT));
final boolean enabled =