Loading core/java/com/android/internal/os/BinderCallsStats.java +45 −24 Original line number Diff line number Diff line Loading @@ -140,6 +140,7 @@ public class BinderCallsStats implements BinderInternal.Observer { latencyDuration = 0; } final int callingUid = getCallingUid(); final int workSourceUid = getWorkSourceUid(); synchronized (mLock) { // This was already checked in #callStart but check again while synchronized. Loading @@ -147,7 +148,8 @@ public class BinderCallsStats implements BinderInternal.Observer { return; } final UidEntry uidEntry = getUidEntry(callingUid); final boolean isWorkSourceSet = workSourceUid >= 0; final UidEntry uidEntry = getUidEntry(isWorkSourceSet ? workSourceUid : callingUid); uidEntry.callCount++; if (recordCall) { Loading @@ -155,7 +157,8 @@ public class BinderCallsStats implements BinderInternal.Observer { uidEntry.recordedCallCount++; final CallStat callStat = uidEntry.getOrCreate( s.binderClass, s.transactionCode, mDeviceState.isScreenInteractive()); callingUid, s.binderClass, s.transactionCode, mDeviceState.isScreenInteractive()); callStat.callCount++; callStat.recordedCallCount++; callStat.cpuTimeMicros += duration; Loading @@ -174,7 +177,8 @@ public class BinderCallsStats implements BinderInternal.Observer { // Only record the total call count if we already track data for this key. // It helps to keep the memory usage down when sampling is enabled. final CallStat callStat = uidEntry.get( s.binderClass, s.transactionCode, mDeviceState.isScreenInteractive()); callingUid, s.binderClass, s.transactionCode, mDeviceState.isScreenInteractive()); if (callStat != null) { callStat.callCount++; } Loading Loading @@ -251,7 +255,8 @@ public class BinderCallsStats implements BinderInternal.Observer { final UidEntry entry = mUidEntries.valueAt(entryIdx); for (CallStat stat : entry.getCallStatsList()) { ExportedCallStat exported = new ExportedCallStat(); exported.uid = entry.uid; exported.workSourceUid = entry.workSourceUid; exported.callingUid = stat.callingUid; exported.className = stat.binderClass.getName(); exported.binderClass = stat.binderClass; exported.transactionCode = stat.transactionCode; Loading Loading @@ -338,10 +343,8 @@ public class BinderCallsStats implements BinderInternal.Observer { entries.sort(Comparator.<UidEntry>comparingDouble(value -> value.cpuTimeMicros).reversed()); final String datasetSizeDesc = verbose ? "" : "(top 90% by cpu time) "; final StringBuilder sb = new StringBuilder(); final List<UidEntry> topEntries = verbose ? entries : getHighestValues(entries, value -> value.cpuTimeMicros, 0.9); pw.println("Per-UID raw data " + datasetSizeDesc + "(package/uid, call_desc, screen_interactive, " + "(package/uid, worksource, call_desc, screen_interactive, " + "cpu_time_micros, max_cpu_time_micros, " + "latency_time_micros, max_latency_time_micros, exception_count, " + "max_request_size_bytes, max_reply_size_bytes, recorded_call_count, " Loading @@ -351,7 +354,9 @@ public class BinderCallsStats implements BinderInternal.Observer { for (ExportedCallStat e : exportedCallStats) { sb.setLength(0); sb.append(" ") .append(uidToString(e.uid, appIdToPkgNameMap)) .append(uidToString(e.callingUid, appIdToPkgNameMap)) .append(',') .append(uidToString(e.workSourceUid, appIdToPkgNameMap)) .append(',').append(e.className) .append('#').append(e.methodName) .append(',').append(e.screenInteractive) Loading @@ -372,7 +377,7 @@ public class BinderCallsStats implements BinderInternal.Observer { final List<UidEntry> summaryEntries = verbose ? entries : getHighestValues(entries, value -> value.cpuTimeMicros, 0.9); for (UidEntry entry : summaryEntries) { String uidStr = uidToString(entry.uid, appIdToPkgNameMap); String uidStr = uidToString(entry.workSourceUid, appIdToPkgNameMap); pw.println(String.format(" %10d %3.0f%% %8d %8d %s", entry.cpuTimeMicros, 100d * entry.cpuTimeMicros / totalCpuTime, entry.recordedCallCount, entry.callCount, uidStr)); Loading Loading @@ -415,6 +420,10 @@ public class BinderCallsStats implements BinderInternal.Observer { return Binder.getCallingUid(); } protected int getWorkSourceUid() { return Binder.getThreadWorkSource(); } protected long getElapsedRealtimeMicro() { return SystemClock.elapsedRealtimeNanos() / 1000; } Loading Loading @@ -462,7 +471,8 @@ public class BinderCallsStats implements BinderInternal.Observer { * Aggregated data by uid/class/method to be sent through WestWorld. */ public static class ExportedCallStat { public int uid; public int callingUid; public int workSourceUid; public String className; public String methodName; public boolean screenInteractive; Loading @@ -483,10 +493,12 @@ public class BinderCallsStats implements BinderInternal.Observer { @VisibleForTesting public static class CallStat { public Class<? extends Binder> binderClass; public int transactionCode; // The UID who executed the transaction (i.e. Binder#getCallingUid). public final int callingUid; public final Class<? extends Binder> binderClass; public final int transactionCode; // True if the screen was interactive when the call ended. public boolean screenInteractive; public final boolean screenInteractive; // Number of calls for which we collected data for. We do not record data for all the calls // when sampling is on. public long recordedCallCount; Loading @@ -508,8 +520,9 @@ public class BinderCallsStats implements BinderInternal.Observer { public long maxReplySizeBytes; public long exceptionCount; CallStat(Class<? extends Binder> binderClass, int transactionCode, CallStat(int callingUid, Class<? extends Binder> binderClass, int transactionCode, boolean screenInteractive) { this.callingUid = callingUid; this.binderClass = binderClass; this.transactionCode = transactionCode; this.screenInteractive = screenInteractive; Loading @@ -518,6 +531,7 @@ public class BinderCallsStats implements BinderInternal.Observer { /** Key used to store CallStat object in a Map. */ public static class CallStatKey { public int callingUid; public Class<? extends Binder> binderClass; public int transactionCode; private boolean screenInteractive; Loading @@ -529,7 +543,8 @@ public class BinderCallsStats implements BinderInternal.Observer { } final CallStatKey key = (CallStatKey) o; return transactionCode == key.transactionCode return callingUid == key.callingUid && transactionCode == key.transactionCode && screenInteractive == key.screenInteractive && (binderClass.equals(key.binderClass)); } Loading @@ -538,6 +553,7 @@ public class BinderCallsStats implements BinderInternal.Observer { public int hashCode() { int result = binderClass.hashCode(); result = 31 * result + transactionCode; result = 31 * result + callingUid; result = 31 * result + (screenInteractive ? 1231 : 1237); return result; } Loading @@ -546,7 +562,9 @@ public class BinderCallsStats implements BinderInternal.Observer { @VisibleForTesting public static class UidEntry { int uid; // The UID who is responsible for the binder transaction. If the bluetooth process execute a // transaction on behalf of app foo, the workSourceUid will be the uid of app foo. public int workSourceUid; // Number of calls for which we collected data for. We do not record data for all the calls // when sampling is on. public long recordedCallCount; Loading @@ -558,7 +576,7 @@ public class BinderCallsStats implements BinderInternal.Observer { public long cpuTimeMicros; UidEntry(int uid) { this.uid = uid; this.workSourceUid = uid; } // Aggregate time spent per each call name: call_desc -> cpu_time_micros Loading @@ -566,22 +584,25 @@ public class BinderCallsStats implements BinderInternal.Observer { private CallStatKey mTempKey = new CallStatKey(); @Nullable CallStat get(Class<? extends Binder> binderClass, int transactionCode, CallStat get(int callingUid, Class<? extends Binder> binderClass, int transactionCode, boolean screenInteractive) { // Use a global temporary key to avoid creating new objects for every lookup. mTempKey.callingUid = callingUid; mTempKey.binderClass = binderClass; mTempKey.transactionCode = transactionCode; mTempKey.screenInteractive = screenInteractive; return mCallStats.get(mTempKey); } CallStat getOrCreate(Class<? extends Binder> binderClass, int transactionCode, boolean screenInteractive) { CallStat mapCallStat = get(binderClass, transactionCode, screenInteractive); CallStat getOrCreate(int callingUid, Class<? extends Binder> binderClass, int transactionCode, boolean screenInteractive) { CallStat mapCallStat = get(callingUid, binderClass, transactionCode, screenInteractive); // Only create CallStat if it's a new entry, otherwise update existing instance if (mapCallStat == null) { mapCallStat = new CallStat(binderClass, transactionCode, screenInteractive); mapCallStat = new CallStat(callingUid, binderClass, transactionCode, screenInteractive); CallStatKey key = new CallStatKey(); key.callingUid = callingUid; key.binderClass = binderClass; key.transactionCode = transactionCode; key.screenInteractive = screenInteractive; Loading Loading @@ -613,12 +634,12 @@ public class BinderCallsStats implements BinderInternal.Observer { } UidEntry uidEntry = (UidEntry) o; return uid == uidEntry.uid; return workSourceUid == uidEntry.workSourceUid; } @Override public int hashCode() { return uid; return workSourceUid; } } Loading core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +41 −17 Original line number Diff line number Diff line Loading @@ -43,7 +43,8 @@ import java.util.Random; @RunWith(AndroidJUnit4.class) @Presubmit public class BinderCallsStatsTest { private static final int TEST_UID = 1; private static final int WORKSOURCE_UID = 1; private static final int CALLING_UID = 2; private static final int REQUEST_SIZE = 2; private static final int REPLY_SIZE = 3; private final CachedDeviceState mDeviceState = new CachedDeviceState(false, true); Loading @@ -61,7 +62,7 @@ public class BinderCallsStatsTest { SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); assertEquals(1, uidEntries.size()); BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID); BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); Assert.assertNotNull(uidEntry); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); assertEquals(1, uidEntry.callCount); Loading @@ -82,7 +83,7 @@ public class BinderCallsStatsTest { callSession = bcs.callStarted(binder, 2); bcs.time += 50; bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); uidEntry = bcs.getUidEntries().get(TEST_UID); uidEntry = bcs.getUidEntries().get(WORKSOURCE_UID); assertEquals(3, uidEntry.callCount); assertEquals(1, uidEntry.recordedCallCount); // Still sampled even for another API. Loading @@ -102,7 +103,7 @@ public class BinderCallsStatsTest { SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); assertEquals(1, uidEntries.size()); BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID); BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); Assert.assertNotNull(uidEntry); assertEquals(1, uidEntry.callCount); assertEquals(10, uidEntry.cpuTimeMicros); Loading @@ -118,7 +119,7 @@ public class BinderCallsStatsTest { bcs.time += 20; bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); uidEntry = bcs.getUidEntries().get(TEST_UID); uidEntry = bcs.getUidEntries().get(WORKSOURCE_UID); assertEquals(2, uidEntry.callCount); assertEquals(30, uidEntry.cpuTimeMicros); callStatsList = new ArrayList(uidEntry.getCallStatsList()); Loading @@ -127,7 +128,7 @@ public class BinderCallsStatsTest { callSession = bcs.callStarted(binder, 2); bcs.time += 50; bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); uidEntry = bcs.getUidEntries().get(TEST_UID); uidEntry = bcs.getUidEntries().get(WORKSOURCE_UID); assertEquals(3, uidEntry.callCount); // This is the first transaction of a new type, so the real CPU time will be measured Loading Loading @@ -178,7 +179,7 @@ public class BinderCallsStatsTest { SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); assertEquals(1, uidEntries.size()); BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID); BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); Assert.assertNotNull(uidEntry); assertEquals(3, uidEntry.callCount); assertEquals(60 /* 10 + 50 */, uidEntry.cpuTimeMicros); Loading Loading @@ -212,7 +213,7 @@ public class BinderCallsStatsTest { SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); assertEquals(1, uidEntries.size()); BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID); BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); assertEquals(2, uidEntry.callCount); assertEquals(1, uidEntry.recordedCallCount); assertEquals(10, uidEntry.cpuTimeMicros); Loading Loading @@ -309,7 +310,7 @@ public class BinderCallsStatsTest { bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(bcs.getUidEntries().get(TEST_UID).getCallStatsList()); new ArrayList(bcs.getUidEntries().get(WORKSOURCE_UID).getCallStatsList()); assertEquals(REQUEST_SIZE, callStatsList.get(0).maxRequestSizeBytes); assertEquals(REPLY_SIZE, callStatsList.get(0).maxReplySizeBytes); Loading @@ -329,7 +330,7 @@ public class BinderCallsStatsTest { bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(bcs.getUidEntries().get(TEST_UID).getCallStatsList()); new ArrayList(bcs.getUidEntries().get(WORKSOURCE_UID).getCallStatsList()); assertEquals(50, callStatsList.get(0).maxCpuTimeMicros); } Loading @@ -348,7 +349,7 @@ public class BinderCallsStatsTest { bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(bcs.getUidEntries().get(TEST_UID).getCallStatsList()); new ArrayList(bcs.getUidEntries().get(WORKSOURCE_UID).getCallStatsList()); assertEquals(5, callStatsList.get(0).maxLatencyMicros); } Loading Loading @@ -424,7 +425,7 @@ public class BinderCallsStatsTest { SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); assertEquals(1, uidEntries.size()); BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID); BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); Assert.assertNotNull(uidEntry); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); assertEquals(false, callStatsList.get(0).screenInteractive); Loading @@ -441,7 +442,7 @@ public class BinderCallsStatsTest { SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); assertEquals(1, uidEntries.size()); BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID); BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); Assert.assertNotNull(uidEntry); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); assertEquals(true, callStatsList.get(0).screenInteractive); Loading Loading @@ -510,7 +511,8 @@ public class BinderCallsStatsTest { assertEquals(1, bcs.getExportedCallStats().size()); BinderCallsStats.ExportedCallStat stat = bcs.getExportedCallStats().get(0); assertEquals(TEST_UID, stat.uid); assertEquals(WORKSOURCE_UID, stat.workSourceUid); assertEquals(CALLING_UID, stat.callingUid); assertEquals("android.os.Binder", stat.className); assertEquals("1", stat.methodName); assertEquals(true, stat.screenInteractive); Loading @@ -525,6 +527,22 @@ public class BinderCallsStatsTest { assertEquals(0, stat.exceptionCount); } @Test public void testCallingUidUsedWhenWorkSourceNotSet() { TestBinderCallsStats bcs = new TestBinderCallsStats(); bcs.setDetailedTracking(true); bcs.workSourceUid = -1; Binder binder = new Binder(); CallSession callSession = bcs.callStarted(binder, 1); bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); assertEquals(1, bcs.getExportedCallStats().size()); BinderCallsStats.ExportedCallStat stat = bcs.getExportedCallStats().get(0); assertEquals(CALLING_UID, stat.workSourceUid); assertEquals(CALLING_UID, stat.callingUid); } @Test public void testGetExportedStatsWithoutCalls() { TestBinderCallsStats bcs = new TestBinderCallsStats(); Loading @@ -540,9 +558,10 @@ public class BinderCallsStatsTest { } class TestBinderCallsStats extends BinderCallsStats { int callingUid = TEST_UID; long time = 1234; long elapsedTime = 0; public int callingUid = CALLING_UID; public int workSourceUid = WORKSOURCE_UID; public long time = 1234; public long elapsedTime = 0; TestBinderCallsStats() { // Make random generator not random. Loading Loading @@ -575,6 +594,11 @@ public class BinderCallsStatsTest { protected int getCallingUid() { return callingUid; } @Override protected int getWorkSourceUid() { return workSourceUid; } } } services/core/java/com/android/server/stats/StatsCompanionService.java +1 −1 Original line number Diff line number Diff line Loading @@ -1034,7 +1034,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { binderStats.reset(); for (ExportedCallStat callStat : callStats) { StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); e.writeInt(callStat.uid); e.writeInt(callStat.workSourceUid); e.writeString(callStat.className); e.writeString(callStat.methodName); e.writeLong(callStat.callCount); Loading Loading
core/java/com/android/internal/os/BinderCallsStats.java +45 −24 Original line number Diff line number Diff line Loading @@ -140,6 +140,7 @@ public class BinderCallsStats implements BinderInternal.Observer { latencyDuration = 0; } final int callingUid = getCallingUid(); final int workSourceUid = getWorkSourceUid(); synchronized (mLock) { // This was already checked in #callStart but check again while synchronized. Loading @@ -147,7 +148,8 @@ public class BinderCallsStats implements BinderInternal.Observer { return; } final UidEntry uidEntry = getUidEntry(callingUid); final boolean isWorkSourceSet = workSourceUid >= 0; final UidEntry uidEntry = getUidEntry(isWorkSourceSet ? workSourceUid : callingUid); uidEntry.callCount++; if (recordCall) { Loading @@ -155,7 +157,8 @@ public class BinderCallsStats implements BinderInternal.Observer { uidEntry.recordedCallCount++; final CallStat callStat = uidEntry.getOrCreate( s.binderClass, s.transactionCode, mDeviceState.isScreenInteractive()); callingUid, s.binderClass, s.transactionCode, mDeviceState.isScreenInteractive()); callStat.callCount++; callStat.recordedCallCount++; callStat.cpuTimeMicros += duration; Loading @@ -174,7 +177,8 @@ public class BinderCallsStats implements BinderInternal.Observer { // Only record the total call count if we already track data for this key. // It helps to keep the memory usage down when sampling is enabled. final CallStat callStat = uidEntry.get( s.binderClass, s.transactionCode, mDeviceState.isScreenInteractive()); callingUid, s.binderClass, s.transactionCode, mDeviceState.isScreenInteractive()); if (callStat != null) { callStat.callCount++; } Loading Loading @@ -251,7 +255,8 @@ public class BinderCallsStats implements BinderInternal.Observer { final UidEntry entry = mUidEntries.valueAt(entryIdx); for (CallStat stat : entry.getCallStatsList()) { ExportedCallStat exported = new ExportedCallStat(); exported.uid = entry.uid; exported.workSourceUid = entry.workSourceUid; exported.callingUid = stat.callingUid; exported.className = stat.binderClass.getName(); exported.binderClass = stat.binderClass; exported.transactionCode = stat.transactionCode; Loading Loading @@ -338,10 +343,8 @@ public class BinderCallsStats implements BinderInternal.Observer { entries.sort(Comparator.<UidEntry>comparingDouble(value -> value.cpuTimeMicros).reversed()); final String datasetSizeDesc = verbose ? "" : "(top 90% by cpu time) "; final StringBuilder sb = new StringBuilder(); final List<UidEntry> topEntries = verbose ? entries : getHighestValues(entries, value -> value.cpuTimeMicros, 0.9); pw.println("Per-UID raw data " + datasetSizeDesc + "(package/uid, call_desc, screen_interactive, " + "(package/uid, worksource, call_desc, screen_interactive, " + "cpu_time_micros, max_cpu_time_micros, " + "latency_time_micros, max_latency_time_micros, exception_count, " + "max_request_size_bytes, max_reply_size_bytes, recorded_call_count, " Loading @@ -351,7 +354,9 @@ public class BinderCallsStats implements BinderInternal.Observer { for (ExportedCallStat e : exportedCallStats) { sb.setLength(0); sb.append(" ") .append(uidToString(e.uid, appIdToPkgNameMap)) .append(uidToString(e.callingUid, appIdToPkgNameMap)) .append(',') .append(uidToString(e.workSourceUid, appIdToPkgNameMap)) .append(',').append(e.className) .append('#').append(e.methodName) .append(',').append(e.screenInteractive) Loading @@ -372,7 +377,7 @@ public class BinderCallsStats implements BinderInternal.Observer { final List<UidEntry> summaryEntries = verbose ? entries : getHighestValues(entries, value -> value.cpuTimeMicros, 0.9); for (UidEntry entry : summaryEntries) { String uidStr = uidToString(entry.uid, appIdToPkgNameMap); String uidStr = uidToString(entry.workSourceUid, appIdToPkgNameMap); pw.println(String.format(" %10d %3.0f%% %8d %8d %s", entry.cpuTimeMicros, 100d * entry.cpuTimeMicros / totalCpuTime, entry.recordedCallCount, entry.callCount, uidStr)); Loading Loading @@ -415,6 +420,10 @@ public class BinderCallsStats implements BinderInternal.Observer { return Binder.getCallingUid(); } protected int getWorkSourceUid() { return Binder.getThreadWorkSource(); } protected long getElapsedRealtimeMicro() { return SystemClock.elapsedRealtimeNanos() / 1000; } Loading Loading @@ -462,7 +471,8 @@ public class BinderCallsStats implements BinderInternal.Observer { * Aggregated data by uid/class/method to be sent through WestWorld. */ public static class ExportedCallStat { public int uid; public int callingUid; public int workSourceUid; public String className; public String methodName; public boolean screenInteractive; Loading @@ -483,10 +493,12 @@ public class BinderCallsStats implements BinderInternal.Observer { @VisibleForTesting public static class CallStat { public Class<? extends Binder> binderClass; public int transactionCode; // The UID who executed the transaction (i.e. Binder#getCallingUid). public final int callingUid; public final Class<? extends Binder> binderClass; public final int transactionCode; // True if the screen was interactive when the call ended. public boolean screenInteractive; public final boolean screenInteractive; // Number of calls for which we collected data for. We do not record data for all the calls // when sampling is on. public long recordedCallCount; Loading @@ -508,8 +520,9 @@ public class BinderCallsStats implements BinderInternal.Observer { public long maxReplySizeBytes; public long exceptionCount; CallStat(Class<? extends Binder> binderClass, int transactionCode, CallStat(int callingUid, Class<? extends Binder> binderClass, int transactionCode, boolean screenInteractive) { this.callingUid = callingUid; this.binderClass = binderClass; this.transactionCode = transactionCode; this.screenInteractive = screenInteractive; Loading @@ -518,6 +531,7 @@ public class BinderCallsStats implements BinderInternal.Observer { /** Key used to store CallStat object in a Map. */ public static class CallStatKey { public int callingUid; public Class<? extends Binder> binderClass; public int transactionCode; private boolean screenInteractive; Loading @@ -529,7 +543,8 @@ public class BinderCallsStats implements BinderInternal.Observer { } final CallStatKey key = (CallStatKey) o; return transactionCode == key.transactionCode return callingUid == key.callingUid && transactionCode == key.transactionCode && screenInteractive == key.screenInteractive && (binderClass.equals(key.binderClass)); } Loading @@ -538,6 +553,7 @@ public class BinderCallsStats implements BinderInternal.Observer { public int hashCode() { int result = binderClass.hashCode(); result = 31 * result + transactionCode; result = 31 * result + callingUid; result = 31 * result + (screenInteractive ? 1231 : 1237); return result; } Loading @@ -546,7 +562,9 @@ public class BinderCallsStats implements BinderInternal.Observer { @VisibleForTesting public static class UidEntry { int uid; // The UID who is responsible for the binder transaction. If the bluetooth process execute a // transaction on behalf of app foo, the workSourceUid will be the uid of app foo. public int workSourceUid; // Number of calls for which we collected data for. We do not record data for all the calls // when sampling is on. public long recordedCallCount; Loading @@ -558,7 +576,7 @@ public class BinderCallsStats implements BinderInternal.Observer { public long cpuTimeMicros; UidEntry(int uid) { this.uid = uid; this.workSourceUid = uid; } // Aggregate time spent per each call name: call_desc -> cpu_time_micros Loading @@ -566,22 +584,25 @@ public class BinderCallsStats implements BinderInternal.Observer { private CallStatKey mTempKey = new CallStatKey(); @Nullable CallStat get(Class<? extends Binder> binderClass, int transactionCode, CallStat get(int callingUid, Class<? extends Binder> binderClass, int transactionCode, boolean screenInteractive) { // Use a global temporary key to avoid creating new objects for every lookup. mTempKey.callingUid = callingUid; mTempKey.binderClass = binderClass; mTempKey.transactionCode = transactionCode; mTempKey.screenInteractive = screenInteractive; return mCallStats.get(mTempKey); } CallStat getOrCreate(Class<? extends Binder> binderClass, int transactionCode, boolean screenInteractive) { CallStat mapCallStat = get(binderClass, transactionCode, screenInteractive); CallStat getOrCreate(int callingUid, Class<? extends Binder> binderClass, int transactionCode, boolean screenInteractive) { CallStat mapCallStat = get(callingUid, binderClass, transactionCode, screenInteractive); // Only create CallStat if it's a new entry, otherwise update existing instance if (mapCallStat == null) { mapCallStat = new CallStat(binderClass, transactionCode, screenInteractive); mapCallStat = new CallStat(callingUid, binderClass, transactionCode, screenInteractive); CallStatKey key = new CallStatKey(); key.callingUid = callingUid; key.binderClass = binderClass; key.transactionCode = transactionCode; key.screenInteractive = screenInteractive; Loading Loading @@ -613,12 +634,12 @@ public class BinderCallsStats implements BinderInternal.Observer { } UidEntry uidEntry = (UidEntry) o; return uid == uidEntry.uid; return workSourceUid == uidEntry.workSourceUid; } @Override public int hashCode() { return uid; return workSourceUid; } } Loading
core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +41 −17 Original line number Diff line number Diff line Loading @@ -43,7 +43,8 @@ import java.util.Random; @RunWith(AndroidJUnit4.class) @Presubmit public class BinderCallsStatsTest { private static final int TEST_UID = 1; private static final int WORKSOURCE_UID = 1; private static final int CALLING_UID = 2; private static final int REQUEST_SIZE = 2; private static final int REPLY_SIZE = 3; private final CachedDeviceState mDeviceState = new CachedDeviceState(false, true); Loading @@ -61,7 +62,7 @@ public class BinderCallsStatsTest { SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); assertEquals(1, uidEntries.size()); BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID); BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); Assert.assertNotNull(uidEntry); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); assertEquals(1, uidEntry.callCount); Loading @@ -82,7 +83,7 @@ public class BinderCallsStatsTest { callSession = bcs.callStarted(binder, 2); bcs.time += 50; bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); uidEntry = bcs.getUidEntries().get(TEST_UID); uidEntry = bcs.getUidEntries().get(WORKSOURCE_UID); assertEquals(3, uidEntry.callCount); assertEquals(1, uidEntry.recordedCallCount); // Still sampled even for another API. Loading @@ -102,7 +103,7 @@ public class BinderCallsStatsTest { SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); assertEquals(1, uidEntries.size()); BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID); BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); Assert.assertNotNull(uidEntry); assertEquals(1, uidEntry.callCount); assertEquals(10, uidEntry.cpuTimeMicros); Loading @@ -118,7 +119,7 @@ public class BinderCallsStatsTest { bcs.time += 20; bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); uidEntry = bcs.getUidEntries().get(TEST_UID); uidEntry = bcs.getUidEntries().get(WORKSOURCE_UID); assertEquals(2, uidEntry.callCount); assertEquals(30, uidEntry.cpuTimeMicros); callStatsList = new ArrayList(uidEntry.getCallStatsList()); Loading @@ -127,7 +128,7 @@ public class BinderCallsStatsTest { callSession = bcs.callStarted(binder, 2); bcs.time += 50; bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); uidEntry = bcs.getUidEntries().get(TEST_UID); uidEntry = bcs.getUidEntries().get(WORKSOURCE_UID); assertEquals(3, uidEntry.callCount); // This is the first transaction of a new type, so the real CPU time will be measured Loading Loading @@ -178,7 +179,7 @@ public class BinderCallsStatsTest { SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); assertEquals(1, uidEntries.size()); BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID); BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); Assert.assertNotNull(uidEntry); assertEquals(3, uidEntry.callCount); assertEquals(60 /* 10 + 50 */, uidEntry.cpuTimeMicros); Loading Loading @@ -212,7 +213,7 @@ public class BinderCallsStatsTest { SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); assertEquals(1, uidEntries.size()); BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID); BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); assertEquals(2, uidEntry.callCount); assertEquals(1, uidEntry.recordedCallCount); assertEquals(10, uidEntry.cpuTimeMicros); Loading Loading @@ -309,7 +310,7 @@ public class BinderCallsStatsTest { bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(bcs.getUidEntries().get(TEST_UID).getCallStatsList()); new ArrayList(bcs.getUidEntries().get(WORKSOURCE_UID).getCallStatsList()); assertEquals(REQUEST_SIZE, callStatsList.get(0).maxRequestSizeBytes); assertEquals(REPLY_SIZE, callStatsList.get(0).maxReplySizeBytes); Loading @@ -329,7 +330,7 @@ public class BinderCallsStatsTest { bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(bcs.getUidEntries().get(TEST_UID).getCallStatsList()); new ArrayList(bcs.getUidEntries().get(WORKSOURCE_UID).getCallStatsList()); assertEquals(50, callStatsList.get(0).maxCpuTimeMicros); } Loading @@ -348,7 +349,7 @@ public class BinderCallsStatsTest { bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(bcs.getUidEntries().get(TEST_UID).getCallStatsList()); new ArrayList(bcs.getUidEntries().get(WORKSOURCE_UID).getCallStatsList()); assertEquals(5, callStatsList.get(0).maxLatencyMicros); } Loading Loading @@ -424,7 +425,7 @@ public class BinderCallsStatsTest { SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); assertEquals(1, uidEntries.size()); BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID); BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); Assert.assertNotNull(uidEntry); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); assertEquals(false, callStatsList.get(0).screenInteractive); Loading @@ -441,7 +442,7 @@ public class BinderCallsStatsTest { SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); assertEquals(1, uidEntries.size()); BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID); BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); Assert.assertNotNull(uidEntry); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); assertEquals(true, callStatsList.get(0).screenInteractive); Loading Loading @@ -510,7 +511,8 @@ public class BinderCallsStatsTest { assertEquals(1, bcs.getExportedCallStats().size()); BinderCallsStats.ExportedCallStat stat = bcs.getExportedCallStats().get(0); assertEquals(TEST_UID, stat.uid); assertEquals(WORKSOURCE_UID, stat.workSourceUid); assertEquals(CALLING_UID, stat.callingUid); assertEquals("android.os.Binder", stat.className); assertEquals("1", stat.methodName); assertEquals(true, stat.screenInteractive); Loading @@ -525,6 +527,22 @@ public class BinderCallsStatsTest { assertEquals(0, stat.exceptionCount); } @Test public void testCallingUidUsedWhenWorkSourceNotSet() { TestBinderCallsStats bcs = new TestBinderCallsStats(); bcs.setDetailedTracking(true); bcs.workSourceUid = -1; Binder binder = new Binder(); CallSession callSession = bcs.callStarted(binder, 1); bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); assertEquals(1, bcs.getExportedCallStats().size()); BinderCallsStats.ExportedCallStat stat = bcs.getExportedCallStats().get(0); assertEquals(CALLING_UID, stat.workSourceUid); assertEquals(CALLING_UID, stat.callingUid); } @Test public void testGetExportedStatsWithoutCalls() { TestBinderCallsStats bcs = new TestBinderCallsStats(); Loading @@ -540,9 +558,10 @@ public class BinderCallsStatsTest { } class TestBinderCallsStats extends BinderCallsStats { int callingUid = TEST_UID; long time = 1234; long elapsedTime = 0; public int callingUid = CALLING_UID; public int workSourceUid = WORKSOURCE_UID; public long time = 1234; public long elapsedTime = 0; TestBinderCallsStats() { // Make random generator not random. Loading Loading @@ -575,6 +594,11 @@ public class BinderCallsStatsTest { protected int getCallingUid() { return callingUid; } @Override protected int getWorkSourceUid() { return workSourceUid; } } }
services/core/java/com/android/server/stats/StatsCompanionService.java +1 −1 Original line number Diff line number Diff line Loading @@ -1034,7 +1034,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { binderStats.reset(); for (ExportedCallStat callStat : callStats) { StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); e.writeInt(callStat.uid); e.writeInt(callStat.workSourceUid); e.writeString(callStat.className); e.writeString(callStat.methodName); e.writeLong(callStat.callCount); Loading