BatteryStats.java revision 076357b8567458d4b6dfdcf839ef751634cd2bfb
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    /**
20     * A constant indicating a partial wake lock timer.
21     */
22    public static final int WAKE_TYPE_PARTIAL = 0;
23
24    /**
25     * A constant indicating a full wake lock timer.
26     */
27    public static final int WAKE_TYPE_FULL = 1;
28
29    /**
30     * A constant indicating a window wake lock timer.
31     */
32    public static final int WAKE_TYPE_WINDOW = 2;
33
34    /**
35     * A constant indicating a sensor timer.
36     *
37     * {@hide}
38     */
39    public static final int SENSOR = 3;
40
41    /**
42     * Include all of the data in the stats, including previously saved data.
43     */
44    public static final int STATS_TOTAL = 0;
45
46    /**
47     * Include only the last run in the stats.
48     */
49    public static final int STATS_LAST = 1;
50
51    /**
52     * Include only the current run in the stats.
53     */
54    public static final int STATS_CURRENT = 2;
55
56    /**
57     * Include only the run since the last time the device was unplugged in the stats.
58     */
59    public static final int STATS_UNPLUGGED = 3;
60
61    /**
62     * Bump the version on this if the checkin format changes.
63     */
64    private static final int BATTERY_STATS_CHECKIN_VERSION = 1;
65
66    // TODO: Update this list if you add/change any stats above.
67    private static final String[] STAT_NAMES = { "total", "last", "current", "unplugged" };
68
69    private static final String APK_DATA = "apk";
70    private static final String PROCESS_DATA = "process";
71    private static final String SENSOR_DATA = "sensor";
72    private static final String WAKELOCK_DATA = "wakelock";
73    private static final String NETWORK_DATA = "network";
74    private static final String BATTERY_DATA = "battery";
75
76    private final StringBuilder mFormatBuilder = new StringBuilder(8);
77    private final Formatter mFormatter = new Formatter(mFormatBuilder);
78
79    /**
80     * State for keeping track of timing information.
81     */
82    public static abstract class Timer {
83
84        /**
85         * Returns the count associated with this Timer for the
86         * selected type of statistics.
87         *
88         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
89         */
90        public abstract int getCount(int which);
91
92        /**
93         * Returns the total time in microseconds associated with this Timer for the
94         * selected type of statistics.
95         *
96         * @param now system uptime time in microseconds
97         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
98         * @return a time in microseconds
99         */
100        public abstract long getTotalTime(long now, int which);
101
102        /**
103         * Temporary for debugging.
104         */
105        public abstract void logState();
106    }
107
108    /**
109     * The statistics associated with a particular uid.
110     */
111    public static abstract class Uid {
112
113        /**
114         * Returns a mapping containing wakelock statistics.
115         *
116         * @return a Map from Strings to Uid.Wakelock objects.
117         */
118        public abstract Map<String, ? extends Wakelock> getWakelockStats();
119
120        /**
121         * The statistics associated with a particular wake lock.
122         */
123        public static abstract class Wakelock {
124            public abstract Timer getWakeTime(int type);
125        }
126
127        /**
128         * Returns a mapping containing sensor statistics.
129         *
130         * @return a Map from Integer sensor ids to Uid.Sensor objects.
131         */
132        public abstract Map<Integer, ? extends Sensor> getSensorStats();
133
134        /**
135         * Returns a mapping containing process statistics.
136         *
137         * @return a Map from Strings to Uid.Proc objects.
138         */
139        public abstract Map<String, ? extends Proc> getProcessStats();
140
141        /**
142         * Returns a mapping containing package statistics.
143         *
144         * @return a Map from Strings to Uid.Pkg objects.
145         */
146        public abstract Map<String, ? extends Pkg> getPackageStats();
147
148        /**
149         * {@hide}
150         */
151        public abstract int getUid();
152
153        /**
154         * {@hide}
155         */
156        public abstract long getTcpBytesReceived(int which);
157
158        /**
159         * {@hide}
160         */
161        public abstract long getTcpBytesSent(int which);
162
163        public static abstract class Sensor {
164            // Magic sensor number for the GPS.
165            public static final int GPS = -10000;
166
167            public abstract int getHandle();
168
169            public abstract Timer getSensorTime();
170        }
171
172        /**
173         * The statistics associated with a particular process.
174         */
175        public static abstract class Proc {
176
177            /**
178             * Returns the total time (in 1/100 sec) spent executing in user code.
179             *
180             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
181             */
182            public abstract long getUserTime(int which);
183
184            /**
185             * Returns the total time (in 1/100 sec) spent executing in system code.
186             *
187             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
188             */
189            public abstract long getSystemTime(int which);
190
191            /**
192             * Returns the number of times the process has been started.
193             *
194             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
195             */
196            public abstract int getStarts(int which);
197        }
198
199        /**
200         * The statistics associated with a particular package.
201         */
202        public static abstract class Pkg {
203
204            /**
205             * Returns the number of times this package has done something that could wake up the
206             * device from sleep.
207             *
208             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
209             */
210            public abstract int getWakeups(int which);
211
212            /**
213             * Returns a mapping containing service statistics.
214             */
215            public abstract Map<String, ? extends Serv> getServiceStats();
216
217            /**
218             * The statistics associated with a particular service.
219             */
220            public abstract class Serv {
221
222                /**
223                 * Returns the amount of time spent started.
224                 *
225                 * @param now elapsed realtime in microseconds.
226                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
227                 * @return
228                 */
229                public abstract long getStartTime(long now, int which);
230
231                /**
232                 * Returns the total number of times startService() has been called.
233                 *
234                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
235                 */
236                public abstract int getStarts(int which);
237
238                /**
239                 * Returns the total number times the service has been launched.
240                 *
241                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
242                 */
243                public abstract int getLaunches(int which);
244            }
245        }
246    }
247
248    /**
249     * Returns the number of times the device has been started.
250     */
251    public abstract int getStartCount();
252
253    /**
254     * Returns the time in milliseconds that the screen has been on while the device was
255     * running on battery.
256     *
257     * {@hide}
258     */
259    public abstract long getBatteryScreenOnTime();
260
261    /**
262     * Returns the time in milliseconds that the screen has been on while the device was
263     * plugged in.
264     *
265     * {@hide}
266     */
267    public abstract long getPluggedScreenOnTime();
268
269    /**
270     * Return whether we are currently running on battery.
271     */
272    public abstract boolean getIsOnBattery();
273
274    /**
275     * Returns a SparseArray containing the statistics for each uid.
276     */
277    public abstract SparseArray<? extends Uid> getUidStats();
278
279    /**
280     * Returns the current battery uptime in microseconds.
281     *
282     * @param curTime the amount of elapsed realtime in microseconds.
283     */
284    public abstract long getBatteryUptime(long curTime);
285
286    /**
287     * Returns the current battery realtime in microseconds.
288     *
289     * @param curTime the amount of elapsed realtime in microseconds.
290     */
291    public abstract long getBatteryRealtime(long curTime);
292
293    /**
294     * Returns the total, last, or current battery uptime in microseconds.
295     *
296     * @param curTime the elapsed realtime in microseconds.
297     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
298     */
299    public abstract long computeBatteryUptime(long curTime, int which);
300
301    /**
302     * Returns the total, last, or current battery realtime in microseconds.
303     *
304     * @param curTime the current elapsed realtime in microseconds.
305     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
306     */
307    public abstract long computeBatteryRealtime(long curTime, int which);
308
309    /**
310     * Returns the total, last, or current uptime in microseconds.
311     *
312     * @param curTime the current elapsed realtime in microseconds.
313     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
314     */
315    public abstract long computeUptime(long curTime, int which);
316
317    /**
318     * Returns the total, last, or current realtime in microseconds.
319     * *
320     * @param curTime the current elapsed realtime in microseconds.
321     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
322     */
323    public abstract long computeRealtime(long curTime, int which);
324
325    private final static void formatTime(StringBuilder out, long seconds) {
326        long days = seconds / (60 * 60 * 24);
327        if (days != 0) {
328            out.append(days);
329            out.append("d ");
330        }
331        long used = days * 60 * 60 * 24;
332
333        long hours = (seconds - used) / (60 * 60);
334        if (hours != 0 || used != 0) {
335            out.append(hours);
336            out.append("h ");
337        }
338        used += hours * 60 * 60;
339
340        long mins = (seconds-used) / 60;
341        if (mins != 0 || used != 0) {
342            out.append(mins);
343            out.append("m ");
344        }
345        used += mins * 60;
346
347        if (seconds != 0 || used != 0) {
348            out.append(seconds-used);
349            out.append("s ");
350        }
351    }
352
353    private final static String formatTime(long time) {
354        long sec = time / 100;
355        StringBuilder sb = new StringBuilder();
356        formatTime(sb, sec);
357        sb.append((time - (sec * 100)) * 10);
358        sb.append("ms ");
359        return sb.toString();
360    }
361
362    private final static String formatTimeMs(long time) {
363        long sec = time / 1000;
364        StringBuilder sb = new StringBuilder();
365        formatTime(sb, sec);
366        sb.append(time - (sec * 1000));
367        sb.append("ms ");
368        return sb.toString();
369    }
370
371    private final String formatRatioLocked(long num, long den) {
372        if (den == 0L) {
373            return "---%";
374        }
375        float perc = ((float)num) / ((float)den) * 100;
376        mFormatBuilder.setLength(0);
377        mFormatter.format("%.1f%%", perc);
378        return mFormatBuilder.toString();
379    }
380
381    /**
382     *
383     * @param sb a StringBuilder object.
384     * @param timer a Timer object contining the wakelock times.
385     * @param now the current time in microseconds.
386     * @param name the name of the wakelock.
387     * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
388     * @param linePrefix a String to be prepended to each line of output.
389     * @return the line prefix
390     */
391    private static final String printWakeLock(StringBuilder sb, Timer timer, long now,
392        String name, int which, String linePrefix) {
393
394        if (timer != null) {
395            // Convert from microseconds to milliseconds with rounding
396            long totalTimeMicros = timer.getTotalTime(now, which);
397            long totalTimeMillis = (totalTimeMicros + 500) / 1000;
398
399            int count = timer.getCount(which);
400            if (totalTimeMillis != 0) {
401                sb.append(linePrefix);
402                sb.append(formatTimeMs(totalTimeMillis));
403                sb.append(name);
404                sb.append(' ');
405                sb.append('(');
406                sb.append(count);
407                sb.append(" times)");
408                return ", ";
409            }
410        }
411        return linePrefix;
412    }
413
414    /**
415     * Checkin version of wakelock printer. Prints simple comma-separated list.
416     *
417     * @param sb a StringBuilder object.
418     * @param timer a Timer object contining the wakelock times.
419     * @param now the current time in microseconds.
420     * @param name the name of the wakelock.
421     * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
422     * @param linePrefix a String to be prepended to each line of output.
423     * @return the line prefix
424     */
425    private static final String printWakeLockCheckin(StringBuilder sb, Timer timer, long now,
426        String name, int which, String linePrefix) {
427        long totalTimeMicros = 0;
428        int count = 0;
429        if (timer != null) {
430            totalTimeMicros = timer.getTotalTime(now, which);
431            count = timer.getCount(which);
432        }
433        sb.append(linePrefix);
434        sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding
435        sb.append(',');
436        sb.append(name);
437        sb.append(',');
438        sb.append(count);
439        return ",";
440    }
441
442    /**
443     * Dump a comma-separated line of values for terse checkin mode.
444     *
445     * @param pw the PageWriter to dump log to
446     * @param category category of data (e.g. "total", "last", "unplugged", "current" )
447     * @param type type of data (e.g. "wakelock", "sensor", "process", "apk" ,  "process", "network")
448     * @param args type-dependent data arguments
449     */
450    private static final void dumpLine(PrintWriter pw, int uid, String category, String type,
451           Object... args ) {
452        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
453        pw.print(uid); pw.print(',');
454        pw.print(category); pw.print(',');
455        pw.print(type);
456
457        for (Object arg : args) {
458            pw.print(',');
459            pw.print(arg);
460        }
461        pw.print('\n');
462    }
463
464    /**
465     * Checkin server version of dump to produce more compact, computer-readable log.
466     *
467     * NOTE: all times are expressed in 'ms'.
468     * @param fd
469     * @param pw
470     * @param which
471     */
472    private final void dumpCheckinLocked(PrintWriter pw, int which) {
473        long uSecTime = SystemClock.elapsedRealtime() * 1000;
474        final long uSecNow = getBatteryUptime(uSecTime);
475
476        StringBuilder sb = new StringBuilder(128);
477        long batteryUptime = computeBatteryUptime(uSecNow, which);
478        long batteryRealtime = computeBatteryRealtime(getBatteryRealtime(uSecTime), which);
479        long elapsedRealtime = computeRealtime(uSecTime, which);
480        long uptime = computeUptime(SystemClock.uptimeMillis() * 1000, which);
481
482        String category = STAT_NAMES[which];
483
484        // Dump "battery" stat
485        dumpLine(pw, 0 /* uid */, category, BATTERY_DATA,
486                which == STATS_TOTAL ? getStartCount() : "N/A",
487                batteryUptime / 1000,
488                formatRatioLocked(batteryUptime, elapsedRealtime),
489                batteryRealtime / 1000,
490                formatRatioLocked(batteryRealtime, elapsedRealtime),
491                uptime / 1000,
492                elapsedRealtime / 1000);
493
494        SparseArray<? extends Uid> uidStats = getUidStats();
495        final int NU = uidStats.size();
496        for (int iu = 0; iu < NU; iu++) {
497            final int uid = uidStats.keyAt(iu);
498            Uid u = uidStats.valueAt(iu);
499            // Dump Network stats per uid, if any
500            long rx = u.getTcpBytesReceived(which);
501            long tx = u.getTcpBytesSent(which);
502            if (rx > 0 || tx > 0) dumpLine(pw, uid, category, NETWORK_DATA, rx, tx);
503
504            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
505            if (wakelocks.size() > 0) {
506                for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
507                        : wakelocks.entrySet()) {
508                    Uid.Wakelock wl = ent.getValue();
509                    String linePrefix = "";
510                    sb.setLength(0);
511                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), uSecNow,
512                            "full", which, linePrefix);
513                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), uSecNow,
514                            "partial", which, linePrefix);
515                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), uSecNow,
516                            "window", which, linePrefix);
517
518                    // Only log if we had at lease one wakelock...
519                    if (sb.length() > 0) {
520                       dumpLine(pw, uid, category, WAKELOCK_DATA, ent.getKey(), sb.toString());
521                    }
522                }
523            }
524
525            Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
526            if (sensors.size() > 0)  {
527                for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
528                        : sensors.entrySet()) {
529                    Uid.Sensor se = ent.getValue();
530                    int sensorNumber = ent.getKey();
531                    Timer timer = se.getSensorTime();
532                    if (timer != null) {
533                        // Convert from microseconds to milliseconds with rounding
534                        long totalTime = (timer.getTotalTime(uSecNow, which) + 500) / 1000;
535                        int count = timer.getCount(which);
536                        if (totalTime != 0) {
537                            dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count);
538                        }
539                    }
540                }
541            }
542
543            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
544            if (processStats.size() > 0) {
545                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
546                        : processStats.entrySet()) {
547                    Uid.Proc ps = ent.getValue();
548
549                    long userTime = ps.getUserTime(which);
550                    long systemTime = ps.getSystemTime(which);
551                    int starts = ps.getStarts(which);
552
553                    if (userTime != 0 || systemTime != 0 || starts != 0) {
554                        dumpLine(pw, uid, category, PROCESS_DATA,
555                                ent.getKey(), // proc
556                                userTime * 10, // cpu time in ms
557                                systemTime * 10, // user time in ms
558                                starts); // process starts
559                    }
560                }
561            }
562
563            Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
564            if (packageStats.size() > 0) {
565                for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
566                        : packageStats.entrySet()) {
567
568                    Uid.Pkg ps = ent.getValue();
569                    int wakeups = ps.getWakeups(which);
570                    Map<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
571                    for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
572                            : serviceStats.entrySet()) {
573                        BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
574                        long startTime = ss.getStartTime(uSecNow, which);
575                        int starts = ss.getStarts(which);
576                        int launches = ss.getLaunches(which);
577                        if (startTime != 0 || starts != 0 || launches != 0) {
578                            dumpLine(pw, uid, category, APK_DATA,
579                                    wakeups, // wakeup alarms
580                                    ent.getKey(), // Apk
581                                    sent.getKey(), // service
582                                    startTime / 1000, // time spent started, in ms
583                                    starts,
584                                    launches);
585                        }
586                    }
587                }
588            }
589        }
590    }
591
592    @SuppressWarnings("unused")
593    private final void dumpLocked(Printer pw, String prefix, int which) {
594        long uSecTime = SystemClock.elapsedRealtime() * 1000;
595        final long uSecNow = getBatteryUptime(uSecTime);
596
597        StringBuilder sb = new StringBuilder(128);
598        long batteryUptime = computeBatteryUptime(uSecNow, which);
599        long batteryRealtime = computeBatteryRealtime(getBatteryRealtime(uSecTime), which);
600        long elapsedRealtime = computeRealtime(uSecTime, which);
601        long uptime = computeUptime(SystemClock.uptimeMillis() * 1000, which);
602
603        pw.println(prefix
604                + "  Time on battery: " + formatTimeMs(batteryUptime / 1000) + "("
605                + formatRatioLocked(batteryUptime, elapsedRealtime)
606                + ") uptime, "
607                + formatTimeMs(batteryRealtime / 1000) + "("
608                + formatRatioLocked(batteryRealtime, elapsedRealtime)
609                + ") realtime");
610        pw.println(prefix
611                + "  Total: "
612                + formatTimeMs(uptime / 1000)
613                + "uptime, "
614                + formatTimeMs(elapsedRealtime / 1000)
615                + "realtime");
616
617        pw.println(" ");
618
619        SparseArray<? extends Uid> uidStats = getUidStats();
620        final int NU = uidStats.size();
621        for (int iu=0; iu<NU; iu++) {
622            final int uid = uidStats.keyAt(iu);
623            Uid u = uidStats.valueAt(iu);
624            pw.println(prefix + "  #" + uid + ":");
625            boolean uidActivity = false;
626
627            long tcpReceived = u.getTcpBytesReceived(which);
628            long tcpSent = u.getTcpBytesSent(which);
629            if (tcpReceived != 0 || tcpSent != 0) {
630                pw.println(prefix + "    Network: " + tcpReceived + " bytes received, "
631                        + tcpSent + " bytes sent");
632            }
633
634            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
635            if (wakelocks.size() > 0) {
636                for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
637                    : wakelocks.entrySet()) {
638                    Uid.Wakelock wl = ent.getValue();
639                    String linePrefix = ": ";
640                    sb.setLength(0);
641                    sb.append(prefix);
642                    sb.append("    Wake lock ");
643                    sb.append(ent.getKey());
644                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), uSecNow,
645                            "full", which, linePrefix);
646                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), uSecNow,
647                            "partial", which, linePrefix);
648                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), uSecNow,
649                            "window", which, linePrefix);
650                    if (!linePrefix.equals(": ")) {
651                        sb.append(" realtime");
652                    } else {
653                        sb.append(": (nothing executed)");
654                    }
655                    pw.println(sb.toString());
656                    uidActivity = true;
657                }
658            }
659
660            Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
661            if (sensors.size() > 0) {
662                for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
663                    : sensors.entrySet()) {
664                    Uid.Sensor se = ent.getValue();
665                    int sensorNumber = ent.getKey();
666                    sb.setLength(0);
667                    sb.append(prefix);
668                    sb.append("    Sensor ");
669                    int handle = se.getHandle();
670                    if (handle == Uid.Sensor.GPS) {
671                        sb.append("GPS");
672                    } else {
673                        sb.append(handle);
674                    }
675                    sb.append(": ");
676
677                    Timer timer = se.getSensorTime();
678                    if (timer != null) {
679                        // Convert from microseconds to milliseconds with rounding
680                        long totalTime = (timer.getTotalTime(uSecNow, which) + 500) / 1000;
681                        int count = timer.getCount(which);
682                        //timer.logState();
683                        if (totalTime != 0) {
684                            sb.append(formatTimeMs(totalTime));
685                            sb.append("realtime (");
686                            sb.append(count);
687                            sb.append(" times)");
688                        } else {
689                            sb.append("(not used)");
690                        }
691                    } else {
692                        sb.append("(not used)");
693                    }
694
695                    pw.println(sb.toString());
696                    uidActivity = true;
697                }
698            }
699
700            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
701            if (processStats.size() > 0) {
702                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
703                    : processStats.entrySet()) {
704                    Uid.Proc ps = ent.getValue();
705                    long userTime;
706                    long systemTime;
707                    int starts;
708
709                    userTime = ps.getUserTime(which);
710                    systemTime = ps.getSystemTime(which);
711                    starts = ps.getStarts(which);
712
713                    if (userTime != 0 || systemTime != 0 || starts != 0) {
714                        pw.println(prefix + "    Proc " + ent.getKey() + ":");
715                        pw.println(prefix + "      CPU: " + formatTime(userTime) + "user + "
716                                + formatTime(systemTime) + "kernel");
717                        pw.println(prefix + "      " + starts + " process starts");
718                        uidActivity = true;
719                    }
720                }
721            }
722
723            Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
724            if (packageStats.size() > 0) {
725                for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
726                    : packageStats.entrySet()) {
727                    pw.println(prefix + "    Apk " + ent.getKey() + ":");
728                    boolean apkActivity = false;
729                    Uid.Pkg ps = ent.getValue();
730                    int wakeups = ps.getWakeups(which);
731                    if (wakeups != 0) {
732                        pw.println(prefix + "      " + wakeups + " wakeup alarms");
733                        apkActivity = true;
734                    }
735                    Map<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
736                    if (serviceStats.size() > 0) {
737                        for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
738                                : serviceStats.entrySet()) {
739                            BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
740                            long startTime = ss.getStartTime(uSecNow, which);
741                            int starts = ss.getStarts(which);
742                            int launches = ss.getLaunches(which);
743                            if (startTime != 0 || starts != 0 || launches != 0) {
744                                pw.println(prefix + "      Service " + sent.getKey() + ":");
745                                pw.println(prefix + "        Created for: "
746                                        + formatTimeMs(startTime / 1000)
747                                        + " uptime");
748                                pw.println(prefix + "        Starts: " + starts
749                                        + ", launches: " + launches);
750                                apkActivity = true;
751                            }
752                        }
753                    }
754                    if (!apkActivity) {
755                        pw.println(prefix + "      (nothing executed)");
756                    }
757                    uidActivity = true;
758                }
759            }
760            if (!uidActivity) {
761                pw.println(prefix + "    (nothing executed)");
762            }
763        }
764    }
765
766    /**
767     * Dumps a human-readable summary of the battery statistics to the given PrintWriter.
768     *
769     * @param pw a Printer to receive the dump output.
770     */
771    @SuppressWarnings("unused")
772    public void dumpLocked(Printer pw) {
773        pw.println("Total Statistics (Current and Historic):");
774        pw.println("  System starts: " + getStartCount()
775                + ", currently on battery: " + getIsOnBattery());
776        dumpLocked(pw, "", STATS_TOTAL);
777        pw.println("");
778        pw.println("Last Run Statistics (Previous run of system):");
779        dumpLocked(pw, "", STATS_LAST);
780        pw.println("");
781        pw.println("Current Battery Statistics (Currently running system):");
782        dumpLocked(pw, "", STATS_CURRENT);
783        pw.println("");
784        pw.println("Unplugged Statistics (Since last unplugged from power):");
785        dumpLocked(pw, "", STATS_UNPLUGGED);
786    }
787
788    @SuppressWarnings("unused")
789    public void dumpCheckinLocked(PrintWriter pw, String[] args) {
790        dumpCheckinLocked(pw, STATS_TOTAL);
791        dumpCheckinLocked(pw, STATS_LAST);
792        dumpCheckinLocked(pw, STATS_UNPLUGGED);
793        dumpCheckinLocked(pw, STATS_CURRENT);
794    }
795}
796