summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/os/BinderCallsStats.java69
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java58
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java2
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);