Track max CPU and latency of binder calls

Test: unit tested

Change-Id: I1429e8c34e9cb0572975fda3ec18e85d6caf3cad
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index fbb99e4..75d714f 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -122,25 +122,25 @@
                 mUidEntries.put(callingUid, uidEntry);
             }
 
+            CallStat callStat;
             if (mDetailedTracking) {
                 // Find CallStat entry and update its total time
-                CallStat callStat = uidEntry.getOrCreate(s.callStat);
-                callStat.callCount++;
-                callStat.cpuTimeMicros += duration;
-                callStat.latencyMicros += latencyDuration;
+                callStat = uidEntry.getOrCreate(s.callStat);
                 callStat.exceptionCount += s.exceptionThrown ? 1 : 0;
-                callStat.maxLatencyMicros = Math.max(callStat.maxLatencyMicros, latencyDuration);
                 callStat.maxRequestSizeBytes =
                         Math.max(callStat.maxRequestSizeBytes, parcelRequestSize);
                 callStat.maxReplySizeBytes =
                         Math.max(callStat.maxReplySizeBytes, parcelReplySize);
             } else {
                 // update sampled timings in the beginning of each interval
-                if (s.cpuTimeStarted >= 0) {
-                    s.sampledCallStat.cpuTimeMicros += duration;
-                    s.sampledCallStat.latencyMicros += latencyDuration;
-                }
-                s.sampledCallStat.callCount++;
+                callStat = s.sampledCallStat;
+            }
+            callStat.callCount++;
+            if (s.cpuTimeStarted >= 0) {
+                callStat.cpuTimeMicros += duration;
+                callStat.maxCpuTimeMicros = Math.max(callStat.maxCpuTimeMicros, duration);
+                callStat.latencyMicros += latencyDuration;
+                callStat.maxLatencyMicros = Math.max(callStat.maxLatencyMicros, latencyDuration);
             }
 
             uidEntry.cpuTimeMicros += duration;
@@ -189,7 +189,7 @@
         StringBuilder sb = new StringBuilder();
         if (mDetailedTracking) {
             pw.println("Per-UID raw data " + datasetSizeDesc
-                    + "(uid, call_desc, cpu_time_micros, latency_time_micros, "
+                    + "(uid, call_desc, cpu_time_micros, max_cpu_time_micros, latency_time_micros, "
                     + "max_latency_time_micros, exception_count, max_request_size_bytes, "
                     + "max_reply_size_bytes, call_count):");
             List<UidEntry> topEntries = verbose ? entries
@@ -200,6 +200,7 @@
                     sb.append("    ")
                             .append(uidEntry.uid).append(",").append(e)
                             .append(',').append(e.cpuTimeMicros)
+                            .append(',').append(e.maxCpuTimeMicros)
                             .append(',').append(e.latencyMicros)
                             .append(',').append(e.maxLatencyMicros)
                             .append(',').append(e.exceptionCount)
@@ -260,7 +261,7 @@
         return Binder.getCallingUid();
     }
 
-    private long getElapsedRealtimeMicro() {
+    protected long getElapsedRealtimeMicro() {
         return SystemClock.elapsedRealtimeNanos() / 1000;
     }
 
@@ -288,11 +289,13 @@
         public String className;
         public int msg;
         public long cpuTimeMicros;
+        public long maxCpuTimeMicros;
         public long latencyMicros;
         public long maxLatencyMicros;
+        public long callCount;
+        // The following fields are only computed if mDetailedTracking is set.
         public long maxRequestSizeBytes;
         public long maxReplySizeBytes;
-        public long callCount;
         public long exceptionCount;
 
         CallStat() {
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 b7fef13..18263ab 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -155,6 +155,42 @@
     }
 
     @Test
+    public void testMaxCpu() {
+        TestBinderCallsStats bcs = new TestBinderCallsStats(true);
+        Binder binder = new Binder();
+        BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
+        bcs.time += 50;
+        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+        callSession = bcs.callStarted(binder, 1);
+        bcs.time += 10;
+        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+        List<BinderCallsStats.CallStat> callStatsList =
+                bcs.getUidEntries().get(TEST_UID).getCallStatsList();
+
+        assertEquals(50, callStatsList.get(0).maxCpuTimeMicros);
+    }
+
+    @Test
+    public void testMaxLatency() {
+        TestBinderCallsStats bcs = new TestBinderCallsStats(true);
+        Binder binder = new Binder();
+        BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
+        bcs.elapsedTime += 5;
+        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+        callSession = bcs.callStarted(binder, 1);
+        bcs.elapsedTime += 1;
+        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+        List<BinderCallsStats.CallStat> callStatsList =
+                bcs.getUidEntries().get(TEST_UID).getCallStatsList();
+
+        assertEquals(5, callStatsList.get(0).maxLatencyMicros);
+    }
+
+    @Test
     public void testGetHighestValues() {
         List<Integer> list = Arrays.asList(1, 2, 3, 4);
         List<Integer> highestValues = BinderCallsStats
@@ -165,6 +201,7 @@
     static class TestBinderCallsStats extends BinderCallsStats {
         int callingUid = TEST_UID;
         long time = 1234;
+        long elapsedTime = 0;
 
         TestBinderCallsStats(boolean detailedTracking) {
             super(detailedTracking);
@@ -176,6 +213,11 @@
         }
 
         @Override
+        protected long getElapsedRealtimeMicro() {
+            return elapsedTime;
+        }
+
+        @Override
         protected int getCallingUid() {
             return callingUid;
         }