BatteryStats.java revision 2a15f38ec2072141de086720a8e914c51056a69d
1package android.os;
2
3import java.io.PrintWriter;
4import java.util.Formatter;
5import java.util.Map;
6
7import android.util.Log;
8import android.util.Printer;
9import android.util.SparseArray;
10
11/**
12 * A class providing access to battery usage statistics, including information on
13 * wakelocks, processes, packages, and services.  All times are represented in microseconds
14 * except where indicated otherwise.
15 * @hide
16 */
17public abstract class BatteryStats implements Parcelable {
18
19    private static final boolean LOCAL_LOGV = false;
20
21    /**
22     * A constant indicating a partial wake lock timer.
23     */
24    public static final int WAKE_TYPE_PARTIAL = 0;
25
26    /**
27     * A constant indicating a full wake lock timer.
28     */
29    public static final int WAKE_TYPE_FULL = 1;
30
31    /**
32     * A constant indicating a window wake lock timer.
33     */
34    public static final int WAKE_TYPE_WINDOW = 2;
35
36    /**
37     * A constant indicating a sensor timer.
38     *
39     * {@hide}
40     */
41    public static final int SENSOR = 3;
42
43    /**
44     * A constant indicating a full wifi lock timer
45     *
46     * {@hide}
47     */
48    public static final int FULL_WIFI_LOCK = 4;
49
50    /**
51     * A constant indicating a scan wifi lock timer
52     *
53     * {@hide}
54     */
55    public static final int SCAN_WIFI_LOCK = 5;
56
57    /**
58     * Include all of the data in the stats, including previously saved data.
59     */
60    public static final int STATS_TOTAL = 0;
61
62    /**
63     * Include only the last run in the stats.
64     */
65    public static final int STATS_LAST = 1;
66
67    /**
68     * Include only the current run in the stats.
69     */
70    public static final int STATS_CURRENT = 2;
71
72    /**
73     * Include only the run since the last time the device was unplugged in the stats.
74     */
75    public static final int STATS_UNPLUGGED = 3;
76
77    /**
78     * Bump the version on this if the checkin format changes.
79     */
80    private static final int BATTERY_STATS_CHECKIN_VERSION = 1;
81
82    // TODO: Update this list if you add/change any stats above.
83    private static final String[] STAT_NAMES = { "total", "last", "current", "unplugged" };
84
85    private static final String APK_DATA = "apk";
86    private static final String PROCESS_DATA = "process";
87    private static final String SENSOR_DATA = "sensor";
88    private static final String WAKELOCK_DATA = "wakelock";
89    private static final String NETWORK_DATA = "network";
90    private static final String BATTERY_DATA = "battery";
91    private static final String WIFI_LOCK_DATA = "wifilock";
92    private static final String MISC_DATA = "misc";
93    private static final String SIGNAL_STRENGTH_DATA = "signal";
94    private static final String DATA_CONNECTION_DATA = "dataconn";
95
96    private final StringBuilder mFormatBuilder = new StringBuilder(8);
97    private final Formatter mFormatter = new Formatter(mFormatBuilder);
98
99    /**
100     * State for keeping track of timing information.
101     */
102    public static abstract class Timer {
103
104        /**
105         * Returns the count associated with this Timer for the
106         * selected type of statistics.
107         *
108         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
109         */
110        public abstract int getCount(int which);
111
112        /**
113         * Returns the total time in microseconds associated with this Timer for the
114         * selected type of statistics.
115         *
116         * @param batteryRealtime system realtime on  battery in microseconds
117         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
118         * @return a time in microseconds
119         */
120        public abstract long getTotalTime(long batteryRealtime, int which);
121
122        /**
123         * Temporary for debugging.
124         */
125        public abstract void logState(Printer pw, String prefix);
126    }
127
128    /**
129     * The statistics associated with a particular uid.
130     */
131    public static abstract class Uid {
132
133        /**
134         * Returns a mapping containing wakelock statistics.
135         *
136         * @return a Map from Strings to Uid.Wakelock objects.
137         */
138        public abstract Map<String, ? extends Wakelock> getWakelockStats();
139
140        /**
141         * The statistics associated with a particular wake lock.
142         */
143        public static abstract class Wakelock {
144            public abstract Timer getWakeTime(int type);
145        }
146
147        /**
148         * Returns a mapping containing sensor statistics.
149         *
150         * @return a Map from Integer sensor ids to Uid.Sensor objects.
151         */
152        public abstract Map<Integer, ? extends Sensor> getSensorStats();
153
154        /**
155         * Returns a mapping containing process statistics.
156         *
157         * @return a Map from Strings to Uid.Proc objects.
158         */
159        public abstract Map<String, ? extends Proc> getProcessStats();
160
161        /**
162         * Returns a mapping containing package statistics.
163         *
164         * @return a Map from Strings to Uid.Pkg objects.
165         */
166        public abstract Map<String, ? extends Pkg> getPackageStats();
167
168        /**
169         * {@hide}
170         */
171        public abstract int getUid();
172
173        /**
174         * {@hide}
175         */
176        public abstract long getTcpBytesReceived(int which);
177
178        /**
179         * {@hide}
180         */
181        public abstract long getTcpBytesSent(int which);
182
183        public abstract void noteFullWifiLockAcquiredLocked();
184        public abstract void noteFullWifiLockReleasedLocked();
185        public abstract void noteScanWifiLockAcquiredLocked();
186        public abstract void noteScanWifiLockReleasedLocked();
187        public abstract long getFullWifiLockTime(long batteryRealtime, int which);
188        public abstract long getScanWifiLockTime(long batteryRealtime, int which);
189
190        public static abstract class Sensor {
191            // Magic sensor number for the GPS.
192            public static final int GPS = -10000;
193
194            public abstract int getHandle();
195
196            public abstract Timer getSensorTime();
197        }
198
199        /**
200         * The statistics associated with a particular process.
201         */
202        public static abstract class Proc {
203
204            /**
205             * Returns the total time (in 1/100 sec) spent executing in user code.
206             *
207             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
208             */
209            public abstract long getUserTime(int which);
210
211            /**
212             * Returns the total time (in 1/100 sec) spent executing in system code.
213             *
214             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
215             */
216            public abstract long getSystemTime(int which);
217
218            /**
219             * Returns the number of times the process has been started.
220             *
221             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
222             */
223            public abstract int getStarts(int which);
224        }
225
226        /**
227         * The statistics associated with a particular package.
228         */
229        public static abstract class Pkg {
230
231            /**
232             * Returns the number of times this package has done something that could wake up the
233             * device from sleep.
234             *
235             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
236             */
237            public abstract int getWakeups(int which);
238
239            /**
240             * Returns a mapping containing service statistics.
241             */
242            public abstract Map<String, ? extends Serv> getServiceStats();
243
244            /**
245             * The statistics associated with a particular service.
246             */
247            public abstract class Serv {
248
249                /**
250                 * Returns the amount of time spent started.
251                 *
252                 * @param batteryUptime elapsed uptime on battery in microseconds.
253                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
254                 * @return
255                 */
256                public abstract long getStartTime(long batteryUptime, int which);
257
258                /**
259                 * Returns the total number of times startService() has been called.
260                 *
261                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
262                 */
263                public abstract int getStarts(int which);
264
265                /**
266                 * Returns the total number times the service has been launched.
267                 *
268                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
269                 */
270                public abstract int getLaunches(int which);
271            }
272        }
273    }
274
275    /**
276     * Returns the number of times the device has been started.
277     */
278    public abstract int getStartCount();
279
280    /**
281     * Returns the time in milliseconds that the screen has been on while the device was
282     * running on battery.
283     *
284     * {@hide}
285     */
286    public abstract long getScreenOnTime(long batteryRealtime, int which);
287
288    /**
289     * Returns the time in milliseconds that the phone has been on while the device was
290     * running on battery.
291     *
292     * {@hide}
293     */
294    public abstract long getPhoneOnTime(long batteryRealtime, int which);
295
296    public static final int SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
297    public static final int SIGNAL_STRENGTH_POOR = 1;
298    public static final int SIGNAL_STRENGTH_MODERATE = 2;
299    public static final int SIGNAL_STRENGTH_GOOD = 3;
300    public static final int SIGNAL_STRENGTH_GREAT = 4;
301
302    static final String[] SIGNAL_STRENGTH_NAMES = {
303        "none", "poor", "moderate", "good", "great"
304    };
305
306    public static final int NUM_SIGNAL_STRENGTH_BINS = 5;
307
308    /**
309     * Returns the time in milliseconds that the phone has been running with
310     * the given signal strength.
311     *
312     * {@hide}
313     */
314    public abstract long getPhoneSignalStrengthTime(int strengthBin,
315            long batteryRealtime, int which);
316
317    public static final int DATA_CONNECTION_NONE = 0;
318    public static final int DATA_CONNECTION_GPRS = 1;
319    public static final int DATA_CONNECTION_EDGE = 2;
320    public static final int DATA_CONNECTION_UMTS = 3;
321    public static final int DATA_CONNECTION_OTHER = 4;
322
323    static final String[] DATA_CONNECTION_NAMES = {
324        "none", "gprs", "edge", "umts", "other"
325    };
326
327    public static final int NUM_DATA_CONNECTION_TYPES = 5;
328
329    /**
330     * Returns the time in milliseconds that the phone has been running with
331     * the given data connection.
332     *
333     * {@hide}
334     */
335    public abstract long getPhoneDataConnectionTime(int dataType,
336            long batteryRealtime, int which);
337
338    /**
339     * Returns the time in milliseconds that wifi has been on while the device was
340     * running on battery.
341     *
342     * {@hide}
343     */
344    public abstract long getWifiOnTime(long batteryRealtime, int which);
345
346    /**
347     * Returns the time in milliseconds that wifi has been on and the driver has
348     * been in the running state while the device was running on battery.
349     *
350     * {@hide}
351     */
352    public abstract long getWifiRunningTime(long batteryRealtime, int which);
353
354    /**
355     * Returns the time in milliseconds that bluetooth has been on while the device was
356     * running on battery.
357     *
358     * {@hide}
359     */
360    public abstract long getBluetoothOnTime(long batteryRealtime, int which);
361
362    /**
363     * Return whether we are currently running on battery.
364     */
365    public abstract boolean getIsOnBattery();
366
367    /**
368     * Returns a SparseArray containing the statistics for each uid.
369     */
370    public abstract SparseArray<? extends Uid> getUidStats();
371
372    /**
373     * Returns the current battery uptime in microseconds.
374     *
375     * @param curTime the amount of elapsed realtime in microseconds.
376     */
377    public abstract long getBatteryUptime(long curTime);
378
379    /**
380     * Returns the current battery realtime in microseconds.
381     *
382     * @param curTime the amount of elapsed realtime in microseconds.
383     */
384    public abstract long getBatteryRealtime(long curTime);
385
386    /**
387     * Returns the battery percentage level at the last time the device was unplugged from power,
388     * or the last time it was booted while unplugged.
389     */
390    public abstract int getUnpluggedStartLevel();
391
392    /**
393     * Returns the battery percentage level at the last time the device was plugged into power.
394     */
395    public abstract int getPluggedStartLevel();
396
397    /**
398     * Returns the total, last, or current battery uptime in microseconds.
399     *
400     * @param curTime the elapsed realtime in microseconds.
401     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
402     */
403    public abstract long computeBatteryUptime(long curTime, int which);
404
405    /**
406     * Returns the total, last, or current battery realtime in microseconds.
407     *
408     * @param curTime the current elapsed realtime in microseconds.
409     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
410     */
411    public abstract long computeBatteryRealtime(long curTime, int which);
412
413    /**
414     * Returns the total, last, or current uptime in microseconds.
415     *
416     * @param curTime the current elapsed realtime in microseconds.
417     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
418     */
419    public abstract long computeUptime(long curTime, int which);
420
421    /**
422     * Returns the total, last, or current realtime in microseconds.
423     * *
424     * @param curTime the current elapsed realtime in microseconds.
425     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
426     */
427    public abstract long computeRealtime(long curTime, int which);
428
429    private final static void formatTime(StringBuilder out, long seconds) {
430        long days = seconds / (60 * 60 * 24);
431        if (days != 0) {
432            out.append(days);
433            out.append("d ");
434        }
435        long used = days * 60 * 60 * 24;
436
437        long hours = (seconds - used) / (60 * 60);
438        if (hours != 0 || used != 0) {
439            out.append(hours);
440            out.append("h ");
441        }
442        used += hours * 60 * 60;
443
444        long mins = (seconds-used) / 60;
445        if (mins != 0 || used != 0) {
446            out.append(mins);
447            out.append("m ");
448        }
449        used += mins * 60;
450
451        if (seconds != 0 || used != 0) {
452            out.append(seconds-used);
453            out.append("s ");
454        }
455    }
456
457    private final static String formatTime(long time) {
458        long sec = time / 100;
459        StringBuilder sb = new StringBuilder();
460        formatTime(sb, sec);
461        sb.append((time - (sec * 100)) * 10);
462        sb.append("ms ");
463        return sb.toString();
464    }
465
466    private final static String formatTimeMs(long time) {
467        long sec = time / 1000;
468        StringBuilder sb = new StringBuilder();
469        formatTime(sb, sec);
470        sb.append(time - (sec * 1000));
471        sb.append("ms ");
472        return sb.toString();
473    }
474
475    private final String formatRatioLocked(long num, long den) {
476        if (den == 0L) {
477            return "---%";
478        }
479        float perc = ((float)num) / ((float)den) * 100;
480        mFormatBuilder.setLength(0);
481        mFormatter.format("%.1f%%", perc);
482        return mFormatBuilder.toString();
483    }
484
485    /**
486     *
487     * @param sb a StringBuilder object.
488     * @param timer a Timer object contining the wakelock times.
489     * @param batteryRealtime the current on-battery time in microseconds.
490     * @param name the name of the wakelock.
491     * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
492     * @param linePrefix a String to be prepended to each line of output.
493     * @return the line prefix
494     */
495    private static final String printWakeLock(StringBuilder sb, Timer timer,
496            long batteryRealtime, String name, int which, String linePrefix) {
497
498        if (timer != null) {
499            // Convert from microseconds to milliseconds with rounding
500            long totalTimeMicros = timer.getTotalTime(batteryRealtime, which);
501            long totalTimeMillis = (totalTimeMicros + 500) / 1000;
502
503            int count = timer.getCount(which);
504            if (totalTimeMillis != 0) {
505                sb.append(linePrefix);
506                sb.append(formatTimeMs(totalTimeMillis));
507                sb.append(name);
508                sb.append(' ');
509                sb.append('(');
510                sb.append(count);
511                sb.append(" times)");
512                return ", ";
513            }
514        }
515        return linePrefix;
516    }
517
518    /**
519     * Checkin version of wakelock printer. Prints simple comma-separated list.
520     *
521     * @param sb a StringBuilder object.
522     * @param timer a Timer object contining the wakelock times.
523     * @param now the current time in microseconds.
524     * @param name the name of the wakelock.
525     * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
526     * @param linePrefix a String to be prepended to each line of output.
527     * @return the line prefix
528     */
529    private static final String printWakeLockCheckin(StringBuilder sb, Timer timer, long now,
530        String name, int which, String linePrefix) {
531        long totalTimeMicros = 0;
532        int count = 0;
533        if (timer != null) {
534            totalTimeMicros = timer.getTotalTime(now, which);
535            count = timer.getCount(which);
536        }
537        sb.append(linePrefix);
538        sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding
539        sb.append(',');
540        sb.append(name);
541        sb.append(',');
542        sb.append(count);
543        return ",";
544    }
545
546    /**
547     * Dump a comma-separated line of values for terse checkin mode.
548     *
549     * @param pw the PageWriter to dump log to
550     * @param category category of data (e.g. "total", "last", "unplugged", "current" )
551     * @param type type of data (e.g. "wakelock", "sensor", "process", "apk" ,  "process", "network")
552     * @param args type-dependent data arguments
553     */
554    private static final void dumpLine(PrintWriter pw, int uid, String category, String type,
555           Object... args ) {
556        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
557        pw.print(uid); pw.print(',');
558        pw.print(category); pw.print(',');
559        pw.print(type);
560
561        for (Object arg : args) {
562            pw.print(',');
563            pw.print(arg);
564        }
565        pw.print('\n');
566    }
567
568    /**
569     * Checkin server version of dump to produce more compact, computer-readable log.
570     *
571     * NOTE: all times are expressed in 'ms'.
572     * @param fd
573     * @param pw
574     * @param which
575     */
576    private final void dumpCheckinLocked(PrintWriter pw, int which) {
577        final long rawUptime = SystemClock.uptimeMillis() * 1000;
578        final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
579        final long batteryUptime = getBatteryUptime(rawUptime);
580        final long batteryRealtime = getBatteryRealtime(rawRealtime);
581        final long whichBatteryUptime = computeBatteryUptime(rawUptime, which);
582        final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which);
583        final long totalRealtime = computeRealtime(rawRealtime, which);
584        final long totalUptime = computeUptime(rawUptime, which);
585        final long screenOnTime = getScreenOnTime(batteryRealtime, which);
586        final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
587        final long wifiOnTime = getWifiOnTime(batteryRealtime, which);
588        final long wifiRunningTime = getWifiRunningTime(batteryRealtime, which);
589        final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which);
590
591        StringBuilder sb = new StringBuilder(128);
592
593        String category = STAT_NAMES[which];
594
595        // Dump "battery" stat
596        dumpLine(pw, 0 /* uid */, category, BATTERY_DATA,
597                which == STATS_TOTAL ? getStartCount() : "N/A",
598                whichBatteryUptime / 1000, whichBatteryRealtime / 1000,
599                totalUptime / 1000, totalRealtime / 1000);
600
601        // Dump misc stats
602        dumpLine(pw, 0 /* uid */, category, MISC_DATA,
603                screenOnTime / 1000, phoneOnTime / 1000, wifiOnTime / 1000,
604                wifiRunningTime / 1000, bluetoothOnTime / 1000);
605
606        // Dump signal strength stats
607        Object[] args = new Object[NUM_SIGNAL_STRENGTH_BINS];
608        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
609            args[i] = getPhoneSignalStrengthTime(i, batteryRealtime, which) / 1000;
610        }
611        dumpLine(pw, 0 /* uid */, category, SIGNAL_STRENGTH_DATA, args);
612
613        // Dump network type stats
614        args = new Object[NUM_DATA_CONNECTION_TYPES];
615        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
616            args[i] = getPhoneDataConnectionTime(i, batteryRealtime, which) / 1000;
617        }
618        dumpLine(pw, 0 /* uid */, category, DATA_CONNECTION_DATA, args);
619
620        if (which == STATS_UNPLUGGED) {
621            dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, getUnpluggedStartLevel(),
622                    getPluggedStartLevel());
623        }
624
625        SparseArray<? extends Uid> uidStats = getUidStats();
626        final int NU = uidStats.size();
627        for (int iu = 0; iu < NU; iu++) {
628            final int uid = uidStats.keyAt(iu);
629            Uid u = uidStats.valueAt(iu);
630            // Dump Network stats per uid, if any
631            long rx = u.getTcpBytesReceived(which);
632            long tx = u.getTcpBytesSent(which);
633            long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
634            long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which);
635
636            if (rx > 0 || tx > 0) dumpLine(pw, uid, category, NETWORK_DATA, rx, tx);
637
638            if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0) {
639                dumpLine(pw, uid, category, WIFI_LOCK_DATA,
640                        fullWifiLockOnTime, scanWifiLockOnTime);
641            }
642
643            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
644            if (wakelocks.size() > 0) {
645                for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
646                        : wakelocks.entrySet()) {
647                    Uid.Wakelock wl = ent.getValue();
648                    String linePrefix = "";
649                    sb.setLength(0);
650                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime,
651                            "full", which, linePrefix);
652                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime,
653                            "partial", which, linePrefix);
654                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime,
655                            "window", which, linePrefix);
656
657                    // Only log if we had at lease one wakelock...
658                    if (sb.length() > 0) {
659                       dumpLine(pw, uid, category, WAKELOCK_DATA, ent.getKey(), sb.toString());
660                    }
661                }
662            }
663
664            Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
665            if (sensors.size() > 0)  {
666                for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
667                        : sensors.entrySet()) {
668                    Uid.Sensor se = ent.getValue();
669                    int sensorNumber = ent.getKey();
670                    Timer timer = se.getSensorTime();
671                    if (timer != null) {
672                        // Convert from microseconds to milliseconds with rounding
673                        long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000;
674                        int count = timer.getCount(which);
675                        if (totalTime != 0) {
676                            dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count);
677                        }
678                    }
679                }
680            }
681
682            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
683            if (processStats.size() > 0) {
684                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
685                        : processStats.entrySet()) {
686                    Uid.Proc ps = ent.getValue();
687
688                    long userTime = ps.getUserTime(which);
689                    long systemTime = ps.getSystemTime(which);
690                    int starts = ps.getStarts(which);
691
692                    if (userTime != 0 || systemTime != 0 || starts != 0) {
693                        dumpLine(pw, uid, category, PROCESS_DATA,
694                                ent.getKey(), // proc
695                                userTime * 10, // cpu time in ms
696                                systemTime * 10, // user time in ms
697                                starts); // process starts
698                    }
699                }
700            }
701
702            Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
703            if (packageStats.size() > 0) {
704                for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
705                        : packageStats.entrySet()) {
706
707                    Uid.Pkg ps = ent.getValue();
708                    int wakeups = ps.getWakeups(which);
709                    Map<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
710                    for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
711                            : serviceStats.entrySet()) {
712                        BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
713                        long startTime = ss.getStartTime(batteryUptime, which);
714                        int starts = ss.getStarts(which);
715                        int launches = ss.getLaunches(which);
716                        if (startTime != 0 || starts != 0 || launches != 0) {
717                            dumpLine(pw, uid, category, APK_DATA,
718                                    wakeups, // wakeup alarms
719                                    ent.getKey(), // Apk
720                                    sent.getKey(), // service
721                                    startTime / 1000, // time spent started, in ms
722                                    starts,
723                                    launches);
724                        }
725                    }
726                }
727            }
728        }
729    }
730
731    @SuppressWarnings("unused")
732    private final void dumpLocked(Printer pw, String prefix, int which) {
733        final long rawUptime = SystemClock.uptimeMillis() * 1000;
734        final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
735        final long batteryUptime = getBatteryUptime(rawUptime);
736        final long batteryRealtime = getBatteryRealtime(rawRealtime);
737
738        final long whichBatteryUptime = computeBatteryUptime(rawUptime, which);
739        final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which);
740        final long totalRealtime = computeRealtime(rawRealtime, which);
741        final long totalUptime = computeUptime(rawUptime, which);
742
743        StringBuilder sb = new StringBuilder(128);
744
745        pw.println(prefix
746                + "  Time on battery: " + formatTimeMs(whichBatteryUptime / 1000)
747                + "(" + formatRatioLocked(whichBatteryUptime, totalRealtime)
748                + ") uptime, "
749                + formatTimeMs(whichBatteryRealtime / 1000) + "("
750                + formatRatioLocked(whichBatteryRealtime, totalRealtime)
751                + ") realtime");
752        pw.println(prefix
753                + "  Total: "
754                + formatTimeMs(totalUptime / 1000)
755                + "uptime, "
756                + formatTimeMs(totalRealtime / 1000)
757                + "realtime");
758
759        final long screenOnTime = getScreenOnTime(batteryRealtime, which);
760        final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
761        final long wifiRunningTime = getWifiRunningTime(batteryRealtime, which);
762        final long wifiOnTime = getWifiOnTime(batteryRealtime, which);
763        final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which);
764        pw.println(prefix
765                + "  Screen on: " + formatTimeMs(screenOnTime / 1000)
766                + "(" + formatRatioLocked(screenOnTime, whichBatteryRealtime)
767                + "), Phone on: " + formatTimeMs(phoneOnTime / 1000)
768                + "(" + formatRatioLocked(phoneOnTime, whichBatteryRealtime));
769        pw.println(prefix
770                + "  Wifi on: " + formatTimeMs(wifiOnTime / 1000)
771                + "(" + formatRatioLocked(wifiOnTime, whichBatteryRealtime)
772                + "), Wifi running: " + formatTimeMs(wifiRunningTime / 1000)
773                + "(" + formatRatioLocked(wifiRunningTime, whichBatteryRealtime)
774                + "), Bluetooth on: " + formatTimeMs(bluetoothOnTime / 1000)
775                + "(" + formatRatioLocked(bluetoothOnTime, whichBatteryRealtime)+ ")");
776
777        sb.setLength(0);
778        sb.append("  Signal strengths: ");
779        boolean didOne = false;
780        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
781            final long time = getPhoneSignalStrengthTime(i, batteryRealtime, which);
782            if (time == 0) {
783                continue;
784            }
785            if (didOne) sb.append(", ");
786            didOne = true;
787            sb.append(SIGNAL_STRENGTH_NAMES[i]);
788            sb.append(" ");
789            sb.append(formatTimeMs(time/1000));
790            sb.append("(");
791            sb.append(formatRatioLocked(time, whichBatteryRealtime));
792            sb.append(")");
793        }
794        if (!didOne) sb.append("No activity");
795        pw.println(sb.toString());
796
797        sb.setLength(0);
798        sb.append("  Data types: ");
799        didOne = false;
800        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
801            final long time = getPhoneDataConnectionTime(i, batteryRealtime, which);
802            if (time == 0) {
803                continue;
804            }
805            if (didOne) sb.append(", ");
806            didOne = true;
807            sb.append(DATA_CONNECTION_NAMES[i]);
808            sb.append(" ");
809            sb.append(formatTimeMs(time/1000));
810            sb.append("(");
811            sb.append(formatRatioLocked(time, whichBatteryRealtime));
812            sb.append(")");
813        }
814        if (!didOne) sb.append("No activity");
815        pw.println(sb.toString());
816
817        pw.println(" ");
818
819        if (which == STATS_UNPLUGGED) {
820            if (getIsOnBattery()) {
821                pw.println(prefix + "  Device is currently unplugged");
822                pw.println(prefix + "    Discharge cycle start level: " +
823                        getUnpluggedStartLevel());
824            } else {
825                pw.println(prefix + "  Device is currently plugged into power");
826                pw.println(prefix + "    Last discharge cycle start level: " +
827                        getUnpluggedStartLevel());
828                pw.println(prefix + "    Last discharge cycle end level: " +
829                        getPluggedStartLevel());
830            }
831        }
832
833        pw.println(" ");
834
835        SparseArray<? extends Uid> uidStats = getUidStats();
836        final int NU = uidStats.size();
837        for (int iu=0; iu<NU; iu++) {
838            final int uid = uidStats.keyAt(iu);
839            Uid u = uidStats.valueAt(iu);
840            pw.println(prefix + "  #" + uid + ":");
841            boolean uidActivity = false;
842
843            long tcpReceived = u.getTcpBytesReceived(which);
844            long tcpSent = u.getTcpBytesSent(which);
845            long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
846            long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which);
847
848            if (tcpReceived != 0 || tcpSent != 0) {
849                pw.println(prefix + "    Network: " + tcpReceived + " bytes received, "
850                        + tcpSent + " bytes sent");
851            }
852            if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0) {
853                pw.println(prefix + "    Full Wifi Lock Time: "
854                        + formatTimeMs(fullWifiLockOnTime / 1000)
855                        + "(" + formatRatioLocked(fullWifiLockOnTime,
856                                whichBatteryRealtime)+ ")");
857                pw.println(prefix + "    Scan Wifi Lock Time: "
858                        + formatTimeMs(scanWifiLockOnTime / 1000)
859                        + "(" + formatRatioLocked(scanWifiLockOnTime,
860                                whichBatteryRealtime)+ ")");
861            }
862
863            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
864            if (wakelocks.size() > 0) {
865                for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
866                    : wakelocks.entrySet()) {
867                    Uid.Wakelock wl = ent.getValue();
868                    String linePrefix = ": ";
869                    sb.setLength(0);
870                    sb.append(prefix);
871                    sb.append("    Wake lock ");
872                    sb.append(ent.getKey());
873                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime,
874                            "full", which, linePrefix);
875                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime,
876                            "partial", which, linePrefix);
877                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime,
878                            "window", which, linePrefix);
879                    if (!linePrefix.equals(": ")) {
880                        sb.append(" realtime");
881                    } else {
882                        sb.append(": (nothing executed)");
883                    }
884                    pw.println(sb.toString());
885                    uidActivity = true;
886                }
887            }
888
889            Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
890            if (sensors.size() > 0) {
891                for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
892                    : sensors.entrySet()) {
893                    Uid.Sensor se = ent.getValue();
894                    int sensorNumber = ent.getKey();
895                    sb.setLength(0);
896                    sb.append(prefix);
897                    sb.append("    Sensor ");
898                    int handle = se.getHandle();
899                    if (handle == Uid.Sensor.GPS) {
900                        sb.append("GPS");
901                    } else {
902                        sb.append(handle);
903                    }
904                    sb.append(": ");
905
906                    Timer timer = se.getSensorTime();
907                    if (timer != null) {
908                        // Convert from microseconds to milliseconds with rounding
909                        long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000;
910                        int count = timer.getCount(which);
911                        //timer.logState();
912                        if (totalTime != 0) {
913                            sb.append(formatTimeMs(totalTime));
914                            sb.append("realtime (");
915                            sb.append(count);
916                            sb.append(" times)");
917                        } else {
918                            sb.append("(not used)");
919                        }
920                    } else {
921                        sb.append("(not used)");
922                    }
923
924                    pw.println(sb.toString());
925                    uidActivity = true;
926                }
927            }
928
929            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
930            if (processStats.size() > 0) {
931                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
932                    : processStats.entrySet()) {
933                    Uid.Proc ps = ent.getValue();
934                    long userTime;
935                    long systemTime;
936                    int starts;
937
938                    userTime = ps.getUserTime(which);
939                    systemTime = ps.getSystemTime(which);
940                    starts = ps.getStarts(which);
941
942                    if (userTime != 0 || systemTime != 0 || starts != 0) {
943                        pw.println(prefix + "    Proc " + ent.getKey() + ":");
944                        pw.println(prefix + "      CPU: " + formatTime(userTime) + "user + "
945                                + formatTime(systemTime) + "kernel");
946                        pw.println(prefix + "      " + starts + " process starts");
947                        uidActivity = true;
948                    }
949                }
950            }
951
952            Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
953            if (packageStats.size() > 0) {
954                for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
955                    : packageStats.entrySet()) {
956                    pw.println(prefix + "    Apk " + ent.getKey() + ":");
957                    boolean apkActivity = false;
958                    Uid.Pkg ps = ent.getValue();
959                    int wakeups = ps.getWakeups(which);
960                    if (wakeups != 0) {
961                        pw.println(prefix + "      " + wakeups + " wakeup alarms");
962                        apkActivity = true;
963                    }
964                    Map<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
965                    if (serviceStats.size() > 0) {
966                        for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
967                                : serviceStats.entrySet()) {
968                            BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
969                            long startTime = ss.getStartTime(batteryUptime, which);
970                            int starts = ss.getStarts(which);
971                            int launches = ss.getLaunches(which);
972                            if (startTime != 0 || starts != 0 || launches != 0) {
973                                pw.println(prefix + "      Service " + sent.getKey() + ":");
974                                pw.println(prefix + "        Created for: "
975                                        + formatTimeMs(startTime / 1000)
976                                        + " uptime");
977                                pw.println(prefix + "        Starts: " + starts
978                                        + ", launches: " + launches);
979                                apkActivity = true;
980                            }
981                        }
982                    }
983                    if (!apkActivity) {
984                        pw.println(prefix + "      (nothing executed)");
985                    }
986                    uidActivity = true;
987                }
988            }
989            if (!uidActivity) {
990                pw.println(prefix + "    (nothing executed)");
991            }
992        }
993    }
994
995    /**
996     * Dumps a human-readable summary of the battery statistics to the given PrintWriter.
997     *
998     * @param pw a Printer to receive the dump output.
999     */
1000    @SuppressWarnings("unused")
1001    public void dumpLocked(Printer pw) {
1002        pw.println("Total Statistics (Current and Historic):");
1003        pw.println("  System starts: " + getStartCount()
1004                + ", currently on battery: " + getIsOnBattery());
1005        dumpLocked(pw, "", STATS_TOTAL);
1006        pw.println("");
1007        pw.println("Last Run Statistics (Previous run of system):");
1008        dumpLocked(pw, "", STATS_LAST);
1009        pw.println("");
1010        pw.println("Current Battery Statistics (Currently running system):");
1011        dumpLocked(pw, "", STATS_CURRENT);
1012        pw.println("");
1013        pw.println("Unplugged Statistics (Since last unplugged from power):");
1014        dumpLocked(pw, "", STATS_UNPLUGGED);
1015    }
1016
1017    @SuppressWarnings("unused")
1018    public void dumpCheckinLocked(PrintWriter pw, String[] args) {
1019        boolean isUnpluggedOnly = false;
1020
1021        for (String arg : args) {
1022            if ("-u".equals(arg)) {
1023                if (LOCAL_LOGV) Log.v("BatteryStats", "Dumping unplugged data");
1024                isUnpluggedOnly = true;
1025            }
1026        }
1027
1028        if (isUnpluggedOnly) {
1029            dumpCheckinLocked(pw, STATS_UNPLUGGED);
1030        }
1031        else {
1032            dumpCheckinLocked(pw, STATS_TOTAL);
1033            dumpCheckinLocked(pw, STATS_LAST);
1034            dumpCheckinLocked(pw, STATS_UNPLUGGED);
1035            dumpCheckinLocked(pw, STATS_CURRENT);
1036        }
1037    }
1038
1039}
1040