Add time spent by uid per cpu frequency to batterystats.

Currently we have total user and system cpu time spent by the uid
in the batterystats. This change will add times spent by the uid
at each different cpu frequency to the batterystats dump which will
help in better understanding the battery usage.

Bug: 34133340
Test: manual
Change-Id: I567dc75875eb58543c0e71572d0b440e87dbb4b9
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b5fd116..3eea72d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -203,6 +203,8 @@
     private static final String APK_DATA = "apk";
     private static final String PROCESS_DATA = "pr";
     private static final String CPU_DATA = "cpu";
+    private static final String GLOBAL_CPU_FREQ_DATA = "gcf";
+    private static final String CPU_TIMES_AT_FREQ_DATA = "ctf";
     private static final String SENSOR_DATA = "sr";
     private static final String VIBRATOR_DATA = "vib";
     private static final String FOREGROUND_DATA = "fg";
@@ -265,6 +267,13 @@
     private final Formatter mFormatter = new Formatter(mFormatBuilder);
 
     /**
+     * Indicates times spent by the uid at each cpu frequency in all process states.
+     *
+     * Other types might include times spent in foreground, background etc.
+     */
+    private final String UID_TIMES_TYPE_ALL = "A";
+
+    /**
      * State for keeping track of counting information.
      */
     public static abstract class Counter {
@@ -303,6 +312,24 @@
     }
 
     /**
+     * State for keeping track of array of long counting information.
+     */
+    public static abstract class LongCounterArray {
+        /**
+         * Returns the counts associated with this Counter for the
+         * selected type of statistics.
+         *
+         * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
+         */
+        public abstract long[] getCountsLocked(int which);
+
+        /**
+         * Temporary for debugging.
+         */
+        public abstract void logState(Printer pw, String prefix);
+    }
+
+    /**
      * Container class that aggregates counters for transmit, receive, and idle state of a
      * radio controller.
      */
@@ -523,6 +550,9 @@
         public abstract Timer getBluetoothScanBackgroundTimer();
         public abstract Counter getBluetoothScanResultCounter();
 
+        public abstract long[] getCpuFreqTimes(int which);
+        public abstract long[] getScreenOffCpuFreqTimes(int which);
+
         // Note: the following times are disjoint.  They can be added together to find the
         // total time a uid has had any processes running at all.
 
@@ -1077,6 +1107,8 @@
 
     public abstract long getNextMaxDailyDeadline();
 
+    public abstract long[] getCpuFreqs();
+
     public final static class HistoryTag {
         public String string;
         public int uid;
@@ -3274,6 +3306,15 @@
             }
         }
 
+        final long[] cpuFreqs = getCpuFreqs();
+        if (cpuFreqs != null) {
+            sb.setLength(0);
+            for (int i = 0; i < cpuFreqs.length; ++i) {
+                sb.append((i == 0 ? "" : ",") + cpuFreqs[i]);
+            }
+            dumpLine(pw, 0 /* uid */, category, GLOBAL_CPU_FREQ_DATA, sb.toString());
+        }
+
         for (int iu = 0; iu < NU; iu++) {
             final int uid = uidStats.keyAt(iu);
             if (reqUid >= 0 && uid != reqUid) {
@@ -3506,6 +3547,27 @@
                         0 /* old cpu power, keep for compatibility */);
             }
 
+            final long[] cpuFreqTimeMs = u.getCpuFreqTimes(which);
+            // If total cpuFreqTimes is null, then we don't need to check for screenOffCpuFreqTimes.
+            if (cpuFreqTimeMs != null) {
+                sb.setLength(0);
+                for (int i = 0; i < cpuFreqTimeMs.length; ++i) {
+                    sb.append((i == 0 ? "" : ",") + cpuFreqTimeMs[i]);
+                }
+                final long[] screenOffCpuFreqTimeMs = u.getScreenOffCpuFreqTimes(which);
+                if (screenOffCpuFreqTimeMs != null) {
+                    for (int i = 0; i < screenOffCpuFreqTimeMs.length; ++i) {
+                        sb.append("," + screenOffCpuFreqTimeMs[i]);
+                    }
+                } else {
+                    for (int i = 0; i < cpuFreqTimeMs.length; ++i) {
+                        sb.append(",0");
+                    }
+                }
+                dumpLine(pw, uid, category, CPU_TIMES_AT_FREQ_DATA, UID_TIMES_TYPE_ALL,
+                        cpuFreqTimeMs.length, sb.toString());
+            }
+
             final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
                     = u.getProcessStats();
             for (int ipr=processStats.size()-1; ipr>=0; ipr--) {
@@ -4373,6 +4435,16 @@
             pw.println(sb.toString());
         }
 
+        final long[] cpuFreqs = getCpuFreqs();
+        if (cpuFreqs != null) {
+            sb.setLength(0);
+            sb.append("CPU freqs:");
+            for (int i = 0; i < cpuFreqs.length; ++i) {
+                sb.append(" " + cpuFreqs[i]);
+            }
+            pw.println(sb.toString());
+        }
+
         for (int iu=0; iu<NU; iu++) {
             final int uid = uidStats.keyAt(iu);
             if (reqUid >= 0 && uid != reqUid && uid != Process.SYSTEM_UID) {
@@ -4835,6 +4907,25 @@
                 pw.println(sb.toString());
             }
 
+            final long[] cpuFreqTimes = u.getCpuFreqTimes(which);
+            if (cpuFreqTimes != null) {
+                sb.setLength(0);
+                sb.append("    Total cpu time per freq:");
+                for (int i = 0; i < cpuFreqTimes.length; ++i) {
+                    sb.append(" " + cpuFreqTimes[i]);
+                }
+                pw.println(sb.toString());
+            }
+            final long[] screenOffCpuFreqTimes = u.getScreenOffCpuFreqTimes(which);
+            if (screenOffCpuFreqTimes != null) {
+                sb.setLength(0);
+                sb.append("    Total screen-off cpu time per freq:");
+                for (int i = 0; i < screenOffCpuFreqTimes.length; ++i) {
+                    sb.append(" " + screenOffCpuFreqTimes[i]);
+                }
+                pw.println(sb.toString());
+            }
+
             final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
                     = u.getProcessStats();
             for (int ipr=processStats.size()-1; ipr>=0; ipr--) {