Loading core/java/com/android/internal/os/BinderCallsStats.java +46 −3 Original line number Diff line number Diff line Loading @@ -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") Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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): " Loading @@ -461,6 +492,7 @@ public class BinderCallsStats implements BinderInternal.Observer { public void reset() { synchronized (mLock) { mCallStatsCount = 0; mUidEntries.clear(); mExceptionCounts.clear(); mStartTime = System.currentTimeMillis(); Loading Loading @@ -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(); Loading core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +56 −0 Original line number Diff line number Diff line Loading @@ -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; Loading services/core/java/com/android/server/BinderCallsStatsService.java +4 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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 = Loading Loading
core/java/com/android/internal/os/BinderCallsStats.java +46 −3 Original line number Diff line number Diff line Loading @@ -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") Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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): " Loading @@ -461,6 +492,7 @@ public class BinderCallsStats implements BinderInternal.Observer { public void reset() { synchronized (mLock) { mCallStatsCount = 0; mUidEntries.clear(); mExceptionCounts.clear(); mStartTime = System.currentTimeMillis(); Loading Loading @@ -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(); Loading
core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +56 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
services/core/java/com/android/server/BinderCallsStatsService.java +4 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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 = Loading