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