Merge "Adds an overflow mechanism for binder calls."
This commit is contained in:
committed by
Android (Google) Code Review
commit
45e52a4069
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user