Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e93685d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Update BinderCallsStats to use the worksource."

parents 4807b6b2 88de48f7
Loading
Loading
Loading
Loading
+45 −24
Original line number Diff line number Diff line
@@ -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;
        }
    }

+41 −17
Original line number Diff line number Diff line
@@ -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);
@@ -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();
@@ -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;
        }
    }

}
+1 −1
Original line number Diff line number Diff line
@@ -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);