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

Commit 00bfb1b9 authored by Olivier Gaillard's avatar Olivier Gaillard
Browse files

Collects binder call stats data through WestWorld.

We require binder calls detailed tracking to be enabled to collect the
stats (in addition to enabling it in WestWorld).

Test: unit test + manual

adb shell cmd stats pull-source 10022
Pull from 10022: { 1531240941000000000 25807560798 (10022)0x10000->0[I]
0x20000->com.android.server.StorageManagerService$3[S]
0x30000->onVolumePathChanged[S] 0x40000->1[L] 0x50000->0[L]
0x60000->18490[L] 0x70000->18490[L] 0x80000->2611[L] 0x90000->2611[L]
0xa0000->0[L]  } ...

Change-Id: I07cad5d8678426cdac45872cda028ea7a85d7d81
parent 89b325a9
Loading
Loading
Loading
Loading
+38 −1
Original line number Diff line number Diff line
@@ -126,7 +126,7 @@ message Atom {
    }

    // Pulled events will start at field 10000.
    // Next: 10022
    // Next: 10023
    oneof pulled {
        WifiBytesTransfer wifi_bytes_transfer = 10000;
        WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -150,6 +150,7 @@ message Atom {
        RemainingBatteryCapacity remaining_battery_capacity = 10019;
        FullBatteryCapacity full_battery_capacity = 10020;
        Temperature temperature = 10021;
        BinderCalls binder_calls = 10022;
    }

    // DO NOT USE field numbers above 100,000 in AOSP. Field numbers above
@@ -1975,3 +1976,39 @@ message Temperature {
    // Temperature in tenths of a degree C.
    optional int32 temperature_dC = 3;
}

/**
 * Pulls the statistics of calls to Binder.
 *
 * Binder stats are cumulative from boot unless somebody reset the data using
 * > adb shell dumpsys binder_calls_stats --reset
 */
message BinderCalls {
   // TODO(gaillard): figure out if binder call stats includes data from isolated uids, if a uid
   // gets recycled and we have isolated uids, we might attribute the data incorrectly.
   // TODO(gaillard): there is a high dimensions cardinality, figure out if we should drop the less
   // commonly used APIs.
   optional int32 uid = 1 [(is_uid) = true];
   // Fully qualified class name of the API call.
   optional string service_class_name = 2;
   // Method name of the API call. It can also be a transaction code if we cannot resolve it to a
   // name. See Binder#getTransactionName.
   optional string service_method_name = 3;
   // Total number of API calls.
   optional int64 call_count = 4;
   // Number of exceptions thrown by the API.
   optional int64 exception_count = 5;
   // Total latency of all API calls.
   // Average can be computed using total_latency_micros / call_count.
   optional int64 total_latency_micros = 6;
   // Maximum latency of one API call.
   optional int64 max_latency_micros = 7;
   // Total CPU usage of all API calls.
   optional int64 total_cpu_micros = 8;
   // Maximum CPU usage of one API call.
   optional int64 max_cpu_micros = 9;
   // Maximum parcel reply size of one API call.
   optional int64 max_reply_size_bytes = 10;
   // Maximum parcel request size of one API call.
   optional int64 max_request_size_bytes = 11;
}
+8 −1
Original line number Diff line number Diff line
@@ -171,7 +171,14 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
          1 * NS_PER_SEC,
          new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
        // temperature
        {android::util::TEMPERATURE, {{}, {}, 1, new ResourceThermalManagerPuller()}}};
        {android::util::TEMPERATURE, {{}, {}, 1, new ResourceThermalManagerPuller()}},
        // binder_calls
        {android::util::BINDER_CALLS,
         {{4, 5, 6, 8},
          {2, 3, 7, 9, 10, 11},
          1 * NS_PER_SEC,
          new StatsCompanionServicePuller(android::util::BINDER_CALLS)}}
        };

StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
}
+1 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ const int FIELD_ID_UID_MAP_DROPPED_CHANGES = 3;
const int FIELD_ID_UID_MAP_DELETED_APPS = 4;

const std::map<int, std::pair<size_t, size_t>> StatsdStats::kAtomDimensionKeySizeLimitMap = {
        {android::util::BINDER_CALLS, {6000, 10000}},
        {android::util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
};

+51 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;
@@ -212,6 +213,39 @@ public class BinderCallsStats {
        }
    }

    public ArrayList<ExportedCallStat> getExportedCallStats() {
        // We do not collect all the data if detailed tracking is off.
        if (!mDetailedTracking) {
          return new ArrayList<ExportedCallStat>();
        }

        ArrayList<ExportedCallStat> resultCallStats = new ArrayList<>();
        synchronized (mLock) {
            int uidEntriesSize = mUidEntries.size();
            for (int entryIdx = 0; entryIdx < uidEntriesSize; entryIdx++){
                UidEntry entry = mUidEntries.valueAt(entryIdx);
                for (CallStat stat : entry.getCallStatsList()) {
                    ExportedCallStat exported = new ExportedCallStat();
                    exported.uid = entry.uid;
                    exported.className = stat.className;
                    exported.methodName = stat.methodName == null
                        ? String.valueOf(stat.msg) : stat.methodName;
                    exported.cpuTimeMicros = stat.cpuTimeMicros;
                    exported.maxCpuTimeMicros = stat.maxCpuTimeMicros;
                    exported.latencyMicros = stat.latencyMicros;
                    exported.maxLatencyMicros = stat.maxLatencyMicros;
                    exported.callCount = stat.callCount;
                    exported.maxRequestSizeBytes = stat.maxRequestSizeBytes;
                    exported.maxReplySizeBytes = stat.maxReplySizeBytes;
                    exported.exceptionCount = stat.exceptionCount;
                    resultCallStats.add(exported);
                }
            }
        }

        return resultCallStats;
    }

    public void dump(PrintWriter pw, Map<Integer,String> appIdToPkgNameMap, boolean verbose) {
        synchronized (mLock) {
            dumpLocked(pw, appIdToPkgNameMap, verbose);
@@ -372,6 +406,23 @@ public class BinderCallsStats {
        }
    }

    /**
     * Aggregated data by uid/class/method to be sent through WestWorld.
     */
    public static class ExportedCallStat {
        public int uid;
        public String className;
        public String methodName;
        public long cpuTimeMicros;
        public long maxCpuTimeMicros;
        public long latencyMicros;
        public long maxLatencyMicros;
        public long callCount;
        public long maxRequestSizeBytes;
        public long maxReplySizeBytes;
        public long exceptionCount;
    }

    @VisibleForTesting
    public static class CallStat {
        public String className;
+36 −0
Original line number Diff line number Diff line
@@ -343,6 +343,42 @@ public class BinderCallsStatsTest {
        bcs.dump(pw, new HashMap<>(), true);
    }

    @Test
    public void testGetExportedStatsWhenDetailedTrackingDisabled() {
        TestBinderCallsStats bcs = new TestBinderCallsStats();
        bcs.setDetailedTracking(false);
        Binder binder = new Binder();
        BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);

        assertEquals(0, bcs.getExportedCallStats().size());
    }

    @Test
    public void testGetExportedStatsWhenDetailedTrackingEnabled() {
        TestBinderCallsStats bcs = new TestBinderCallsStats();
        bcs.setDetailedTracking(true);
        Binder binder = new Binder();
        BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
        bcs.time += 10;
        bcs.elapsedTime += 20;
        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);

        assertEquals(1, bcs.getExportedCallStats().size());
        BinderCallsStats.ExportedCallStat stat = bcs.getExportedCallStats().get(0);
        assertEquals(TEST_UID, stat.uid);
        assertEquals("android.os.Binder", stat.className);
        assertEquals("1", stat.methodName);
        assertEquals(10, stat.cpuTimeMicros);
        assertEquals(10, stat.maxCpuTimeMicros);
        assertEquals(20, stat.latencyMicros);
        assertEquals(20, stat.maxLatencyMicros);
        assertEquals(1, stat.callCount);
        assertEquals(REQUEST_SIZE, stat.maxRequestSizeBytes);
        assertEquals(REPLY_SIZE, stat.maxReplySizeBytes);
        assertEquals(0, stat.exceptionCount);
    }

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