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