diff options
3 files changed, 87 insertions, 42 deletions
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index 856712f48297..f5d768c4123f 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -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. @@ -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) { @@ -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; @@ -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++; } @@ -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; @@ -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, " @@ -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) @@ -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)); @@ -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; } @@ -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; @@ -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; @@ -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; @@ -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; @@ -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)); } @@ -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; } @@ -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; @@ -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 @@ -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; @@ -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; } } 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 364dcfd4f471..30309cf64e96 100644 --- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java @@ -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); @@ -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); @@ -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. @@ -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); @@ -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()); @@ -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 @@ -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); @@ -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); @@ -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); @@ -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); } @@ -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); } @@ -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); @@ -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); @@ -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); @@ -526,6 +528,22 @@ public class BinderCallsStatsTest { } @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(); Binder binder = new Binder(); @@ -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. @@ -575,6 +594,11 @@ public class BinderCallsStatsTest { protected int getCallingUid() { return callingUid; } + + @Override + protected int getWorkSourceUid() { + return workSourceUid; + } } } diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index f10fe5814d0b..5600749ee437 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -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); |