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

Commit 7a2a98bb authored by Olivier Gaillard's avatar Olivier Gaillard
Browse files

Store the runtime class instead of the class name.

This will be used by a follow up CL to call getTransactionCode lazily
instead of doing it during the binder call.

Test: unit tests
Change-Id: I11a997bb8a6268871daf4145a962886b43195c89
parent 55369290
Loading
Loading
Loading
Loading
+49 −51
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import com.android.internal.util.Preconditions;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -76,16 +77,17 @@ public class BinderCallsStats implements BinderInternal.Observer {

    @Override
    public CallSession callStarted(Binder binder, int code) {
        return callStarted(binder.getClass().getName(), code, binder.getTransactionName(code));
        return callStarted(binder.getClass(), code, binder.getTransactionName(code));
    }

    private CallSession callStarted(String className, int code, @Nullable String methodName) {
    private CallSession callStarted(Class<? extends Binder> binderClass, int code,
            @Nullable String methodName) {
        CallSession s = mCallSessionsPool.poll();
        if (s == null) {
            s = new CallSession();
        }

        s.className = className;
        s.binderClass = binderClass;
        s.transactionCode = code;
        s.methodName = methodName;
        s.exceptionThrown = false;
@@ -137,7 +139,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
                mUidEntries.put(callingUid, uidEntry);
            }
            uidEntry.callCount++;
            CallStat callStat = uidEntry.getOrCreate(s.className, s.transactionCode);
            CallStat callStat = uidEntry.getOrCreate(s.binderClass, s.transactionCode);
            callStat.callCount++;

            if (recordCall) {
@@ -183,6 +185,9 @@ public class BinderCallsStats implements BinderInternal.Observer {
        }
    }

    /**
     * This method is expensive to call.
     */
    public ArrayList<ExportedCallStat> getExportedCallStats() {
        // We do not collect all the data if detailed tracking is off.
        if (!mDetailedTracking) {
@@ -197,7 +202,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
                for (CallStat stat : entry.getCallStatsList()) {
                    ExportedCallStat exported = new ExportedCallStat();
                    exported.uid = entry.uid;
                    exported.className = stat.className;
                    exported.className = stat.binderClass.getName();
                    exported.methodName = stat.methodName == null
                            ? String.valueOf(stat.transactionCode) : stat.methodName;
                    exported.cpuTimeMicros = stat.cpuTimeMicros;
@@ -258,12 +263,12 @@ public class BinderCallsStats implements BinderInternal.Observer {
                + "latency_time_micros, max_latency_time_micros, exception_count, "
                + "max_request_size_bytes, max_reply_size_bytes, recorded_call_count, "
                + "call_count):");
        for (UidEntry uidEntry : topEntries) {
            for (CallStat e : uidEntry.getCallStatsList()) {
        for (ExportedCallStat e : sortByCpuDesc(getExportedCallStats())) {
            sb.setLength(0);
            sb.append("    ")
                        .append(uidToString(uidEntry.uid, appIdToPkgNameMap))
                        .append(',').append(e)
                    .append(uidToString(e.uid, appIdToPkgNameMap))
                    .append(',').append(e.className)
                    .append('#').append(e.methodName)
                    .append(',').append(e.cpuTimeMicros)
                    .append(',').append(e.maxCpuTimeMicros)
                    .append(',').append(e.latencyMicros)
@@ -275,7 +280,6 @@ public class BinderCallsStats implements BinderInternal.Observer {
                    .append(',').append(e.callCount);
            pw.println(sb);
        }
        }
        pw.println();
        pw.println("Per-UID Summary " + datasetSizeDesc
                + "(cpu_time, % of total cpu_time, recorded_call_count, call_count, package/uid):");
@@ -380,7 +384,7 @@ public class BinderCallsStats implements BinderInternal.Observer {

    @VisibleForTesting
    public static class CallStat {
        public String className;
        public Class<? extends Binder> binderClass;
        public int transactionCode;
        // Method name might be null when we cannot resolve the transaction code. For instance, if
        // the binder was not generated by AIDL.
@@ -405,23 +409,15 @@ public class BinderCallsStats implements BinderInternal.Observer {
        public long maxReplySizeBytes;
        public long exceptionCount;

        CallStat() {
        }

        CallStat(String className, int transactionCode) {
            this.className = className;
        CallStat(Class<? extends Binder> binderClass, int transactionCode) {
            this.binderClass = binderClass;
            this.transactionCode = transactionCode;
        }

        @Override
        public String toString() {
            return className + "#" + (methodName == null ? transactionCode : methodName);
        }
    }

    /** Key used to store CallStat object in a Map. */
    public static class CallStatKey {
        public String className;
        public Class<? extends Binder> binderClass;
        public int transactionCode;

        @Override
@@ -432,12 +428,12 @@ public class BinderCallsStats implements BinderInternal.Observer {

            CallStatKey key = (CallStatKey) o;
            return transactionCode == key.transactionCode
                    && (className.equals(key.className));
                    && (binderClass.equals(key.binderClass));
        }

        @Override
        public int hashCode() {
            int result = className.hashCode();
            int result = binderClass.hashCode();
            result = 31 * result + transactionCode;
            return result;
        }
@@ -465,16 +461,16 @@ public class BinderCallsStats implements BinderInternal.Observer {
        private Map<CallStatKey, CallStat> mCallStats = new ArrayMap<>();
        private CallStatKey mTempKey = new CallStatKey();

        CallStat getOrCreate(String className, int transactionCode) {
        CallStat getOrCreate(Class<? extends Binder> binderClass, int transactionCode) {
            // Use a global temporary key to avoid creating new objects for every lookup.
            mTempKey.className = className;
            mTempKey.binderClass = binderClass;
            mTempKey.transactionCode = transactionCode;
            CallStat mapCallStat = mCallStats.get(mTempKey);
            // Only create CallStat if it's a new entry, otherwise update existing instance
            if (mapCallStat == null) {
                mapCallStat = new CallStat(className, transactionCode);
                mapCallStat = new CallStat(binderClass, transactionCode);
                CallStatKey key = new CallStatKey();
                key.className = className;
                key.binderClass = binderClass;
                key.transactionCode = transactionCode;
                mCallStats.put(key, mapCallStat);
            }
@@ -484,17 +480,8 @@ public class BinderCallsStats implements BinderInternal.Observer {
        /**
         * Returns list of calls sorted by CPU time
         */
        public List<CallStat> getCallStatsList() {
            List<CallStat> callStats = new ArrayList<>(mCallStats.values());
            callStats.sort((o1, o2) -> {
                if (o1.cpuTimeMicros < o2.cpuTimeMicros) {
                    return 1;
                } else if (o1.cpuTimeMicros > o2.cpuTimeMicros) {
                    return -1;
                }
                return 0;
            });
            return callStats;
        public Collection<CallStat> getCallStatsList() {
            return mCallStats.values();
        }

        @Override
@@ -553,4 +540,15 @@ public class BinderCallsStats implements BinderInternal.Observer {
        return result;
    }

    private List<ExportedCallStat> sortByCpuDesc(List<ExportedCallStat> callStats) {
        callStats.sort((o1, o2) -> {
            if (o1.cpuTimeMicros < o2.cpuTimeMicros) {
                return 1;
            } else if (o1.cpuTimeMicros > o2.cpuTimeMicros) {
                return -1;
            }
            return 0;
        });
        return callStats;
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -75,7 +75,7 @@ public class BinderInternal {
     */
    public static class CallSession {
        // Binder interface descriptor.
        public String className;
        public Class<? extends Binder> binderClass;
        // Binder transaction code.
        public int transactionCode;
        // Binder transaction method name.
+29 −14
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import org.junit.runner.RunWith;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -62,11 +63,11 @@ public class BinderCallsStatsTest {
        assertEquals(1, uidEntries.size());
        BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID);
        Assert.assertNotNull(uidEntry);
        List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
        List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList());
        assertEquals(1, uidEntry.callCount);
        assertEquals(1, uidEntry.recordedCallCount);
        assertEquals(10, uidEntry.cpuTimeMicros);
        assertEquals(binder.getClass().getName(), callStatsList.get(0).className);
        assertEquals(binder.getClass(), callStatsList.get(0).binderClass);
        assertEquals(1, callStatsList.get(0).transactionCode);

        // CPU usage is sampled, should not be tracked here.
@@ -85,7 +86,7 @@ public class BinderCallsStatsTest {
        assertEquals(3, uidEntry.callCount);
        assertEquals(1, uidEntry.recordedCallCount);
        // Still sampled even for another API.
        callStatsList = uidEntry.getCallStatsList();
        callStatsList = new ArrayList(uidEntry.getCallStatsList());
        assertEquals(2, callStatsList.size());
    }

@@ -105,12 +106,12 @@ public class BinderCallsStatsTest {
        Assert.assertNotNull(uidEntry);
        assertEquals(1, uidEntry.callCount);
        assertEquals(10, uidEntry.cpuTimeMicros);
        assertEquals(1, uidEntry.getCallStatsList().size());
        assertEquals(1, new ArrayList(uidEntry.getCallStatsList()).size());

        List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
        List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList());
        assertEquals(1, callStatsList.get(0).callCount);
        assertEquals(10, callStatsList.get(0).cpuTimeMicros);
        assertEquals(binder.getClass().getName(), callStatsList.get(0).className);
        assertEquals(binder.getClass(), callStatsList.get(0).binderClass);
        assertEquals(1, callStatsList.get(0).transactionCode);

        callSession = bcs.callStarted(binder, 1);
@@ -120,7 +121,7 @@ public class BinderCallsStatsTest {
        uidEntry = bcs.getUidEntries().get(TEST_UID);
        assertEquals(2, uidEntry.callCount);
        assertEquals(30, uidEntry.cpuTimeMicros);
        callStatsList = uidEntry.getCallStatsList();
        callStatsList = new ArrayList(uidEntry.getCallStatsList());
        assertEquals(1, callStatsList.size());

        callSession = bcs.callStarted(binder, 2);
@@ -131,7 +132,7 @@ public class BinderCallsStatsTest {

        // This is the first transaction of a new type, so the real CPU time will be measured
        assertEquals(80, uidEntry.cpuTimeMicros);
        callStatsList = uidEntry.getCallStatsList();
        callStatsList = new ArrayList(uidEntry.getCallStatsList());
        assertEquals(2, callStatsList.size());
    }

@@ -182,7 +183,7 @@ public class BinderCallsStatsTest {
        assertEquals(3, uidEntry.callCount);
        assertEquals(60 /* 10 + 50 */, uidEntry.cpuTimeMicros);

        List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
        List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList());
        assertEquals(1, callStatsList.size());
        BinderCallsStats.CallStat callStats = callStatsList.get(0);
        assertEquals(3, callStats.callCount);
@@ -216,7 +217,7 @@ public class BinderCallsStatsTest {
        assertEquals(1, uidEntry.recordedCallCount);
        assertEquals(10, uidEntry.cpuTimeMicros);

        List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
        List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList());
        assertEquals(2, callStatsList.size());

        BinderCallsStats.CallStat callStats = callStatsList.get(0);
@@ -248,7 +249,7 @@ public class BinderCallsStatsTest {
        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);

        List<BinderCallsStats.CallStat> callStatsList =
                bcs.getUidEntries().get(TEST_UID).getCallStatsList();
                new ArrayList(bcs.getUidEntries().get(TEST_UID).getCallStatsList());
        assertEquals(1, callStatsList.get(0).transactionCode);
        assertEquals("resolved", callStatsList.get(0).methodName);
    }
@@ -263,7 +264,7 @@ public class BinderCallsStatsTest {
        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);

        List<BinderCallsStats.CallStat> callStatsList =
                bcs.getUidEntries().get(TEST_UID).getCallStatsList();
                new ArrayList(bcs.getUidEntries().get(TEST_UID).getCallStatsList());

        assertEquals(REQUEST_SIZE, callStatsList.get(0).maxRequestSizeBytes);
        assertEquals(REPLY_SIZE, callStatsList.get(0).maxReplySizeBytes);
@@ -283,7 +284,7 @@ public class BinderCallsStatsTest {
        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);

        List<BinderCallsStats.CallStat> callStatsList =
                bcs.getUidEntries().get(TEST_UID).getCallStatsList();
                new ArrayList(bcs.getUidEntries().get(TEST_UID).getCallStatsList());

        assertEquals(50, callStatsList.get(0).maxCpuTimeMicros);
    }
@@ -302,7 +303,7 @@ public class BinderCallsStatsTest {
        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);

        List<BinderCallsStats.CallStat> callStatsList =
                bcs.getUidEntries().get(TEST_UID).getCallStatsList();
                new ArrayList(bcs.getUidEntries().get(TEST_UID).getCallStatsList());

        assertEquals(5, callStatsList.get(0).maxLatencyMicros);
    }
@@ -388,6 +389,20 @@ public class BinderCallsStatsTest {
        assertEquals(0, stat.exceptionCount);
    }

    @Test
    public void testGetExportedStatsWithoutCalls() {
        TestBinderCallsStats bcs = new TestBinderCallsStats();
        Binder binder = new Binder();
        assertEquals(0, bcs.getExportedCallStats().size());
    }

    @Test
    public void testGetExportedExceptionsWithoutCalls() {
        TestBinderCallsStats bcs = new TestBinderCallsStats();
        Binder binder = new Binder();
        assertEquals(0, bcs.getExceptionCounts().size());
    }

    static class TestBinderCallsStats extends BinderCallsStats {
        int callingUid = TEST_UID;
        long time = 1234;