BatteryStats.java revision f1e484acb594a726fb57ad0ae4cfe902c7f35858
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.
19     */
20    public static final int WAKE_TYPE_PARTIAL = 0;
21
22    /**
23     * A constant indicating a full wake lock.
24     */
25    public static final int WAKE_TYPE_FULL = 1;
26
27    /**
28     * A constant indicating a window wake lock.
29     */
30    public static final int WAKE_TYPE_WINDOW = 2;
31
32    /**
33     * Include all of the data in the stats, including previously saved data.
34     */
35    public static final int STATS_TOTAL = 0;
36
37    /**
38     * Include only the last run in the stats.
39     */
40    public static final int STATS_LAST = 1;
41
42    /**
43     * Include only the current run in the stats.
44     */
45    public static final int STATS_CURRENT = 2;
46
47    /**
48     * Include only the run since the last time the device was unplugged in the stats.
49     */
50    public static final int STATS_UNPLUGGED = 3;
51
52    private final StringBuilder mFormatBuilder = new StringBuilder(8);
53    private final Formatter mFormatter = new Formatter(mFormatBuilder);
54
55    /**
56     * State for keeping track of timing information.
57     */
58    public static abstract class Timer {
59
60        /**
61         * Returns the count associated with this Timer for the
62         * selected type of statistics.
63         *
64         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
65         */
66        public abstract int getCount(int which);
67
68        /**
69         * Returns the total time in microseconds associated with this Timer for the
70         * selected type of statistics.
71         *
72         * @param now system uptime time in microseconds
73         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
74         * @return a time in microseconds
75         */
76        public abstract long getTotalTime(long now, int which);
77    }
78
79    /**
80     * The statistics associated with a particular uid.
81     */
82    public static abstract class Uid {
83
84        /**
85         * Returns a mapping containing wakelock statistics.
86         *
87         * @return a Map from Strings to Uid.Wakelock objects.
88         */
89        public abstract Map<String, ? extends Wakelock> getWakelockStats();
90
91        /**
92         * The statistics associated with a particular wake lock.
93         */
94        public static abstract class Wakelock {
95            public abstract Timer getWakeTime(int type);
96        }
97
98        /**
99         * Returns a mapping containing sensor statistics.
100         *
101         * @return a Map from Integer sensor ids to Uid.Sensor objects.
102         */
103        public abstract Map<Integer, ? extends Sensor> getSensorStats();
104
105        /**
106         * Returns a mapping containing process statistics.
107         *
108         * @return a Map from Strings to Uid.Proc objects.
109         */
110        public abstract Map<String, ? extends Proc> getProcessStats();
111
112        /**
113         * Returns a mapping containing package statistics.
114         *
115         * @return a Map from Strings to Uid.Pkg objects.
116         */
117        public abstract Map<String, ? extends Pkg> getPackageStats();
118
119        public static abstract class Sensor {
120            public abstract Timer getSensorTime();
121        }
122
123        /**
124         * The statistics associated with a particular process.
125         */
126        public static abstract class Proc {
127
128            /**
129             * Returns the total time (in 1/100 sec) spent executing in user code.
130             *
131             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
132             */
133            public abstract long getUserTime(int which);
134
135            /**
136             * Returns the total time (in 1/100 sec) spent executing in system code.
137             *
138             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
139             */
140            public abstract long getSystemTime(int which);
141
142            /**
143             * Returns the number of times the process has been started.
144             *
145             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
146             */
147            public abstract int getStarts(int which);
148        }
149
150        /**
151         * The statistics associated with a particular package.
152         */
153        public static abstract class Pkg {
154
155            /**
156             * Returns the number of times this package has done something that could wake up the
157             * device from sleep.
158             *
159             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
160             */
161            public abstract int getWakeups(int which);
162
163            /**
164             * Returns a mapping containing service statistics.
165             */
166            public abstract Map<String, ? extends Serv> getServiceStats();
167
168            /**
169             * The statistics associated with a particular service.
170             */
171            public abstract class Serv {
172
173                /**
174                 * Returns the amount of time spent started.
175                 *
176                 * @param now elapsed realtime in microseconds.
177                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
178                 * @return
179                 */
180                public abstract long getStartTime(long now, int which);
181
182                /**
183                 * Returns the total number of times startService() has been called.
184                 *
185                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
186                 */
187                public abstract int getStarts(int which);
188
189                /**
190                 * Returns the total number times the service has been launched.
191                 *
192                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
193                 */
194                public abstract int getLaunches(int which);
195            }
196        }
197    }
198
199    /**
200     * Returns the number of times the device has been started.
201     */
202    public abstract int getStartCount();
203
204    /**
205     * Returns a SparseArray containing the statistics for each uid.
206     */
207    public abstract SparseArray<? extends Uid> getUidStats();
208
209    /**
210     * Returns the current battery uptime in microseconds.
211     *
212     * @param curTime the amount of elapsed realtime in microseconds.
213     */
214    public abstract long getBatteryUptime(long curTime);
215
216    /**
217     * Returns the current battery realtime in microseconds.
218     *
219     * @param curTime the amount of elapsed realtime in microseconds.
220     */
221    public abstract long getBatteryRealtime(long curTime);
222
223    /**
224     * Returns the total, last, or current battery uptime in microseconds.
225     *
226     * @param curTime the elapsed realtime in microseconds.
227     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
228     */
229    public abstract long computeBatteryUptime(long curTime, int which);
230
231    /**
232     * Returns the total, last, or current battery realtime in microseconds.
233     *
234     * @param curTime the current elapsed realtime in microseconds.
235     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
236     */
237    public abstract long computeBatteryRealtime(long curTime, int which);
238
239    /**
240     * Returns the total, last, or current uptime in microseconds.
241     *
242     * @param curTime the current elapsed realtime in microseconds.
243     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
244     */
245    public abstract long computeUptime(long curTime, int which);
246
247    /**
248     * Returns the total, last, or current realtime in microseconds.
249     * *
250     * @param curTime the current elapsed realtime in microseconds.
251     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
252     */
253    public abstract long computeRealtime(long curTime, int which);
254
255    private final static void formatTime(StringBuilder out, long seconds) {
256        long days = seconds / (60 * 60 * 24);
257        if (days != 0) {
258            out.append(days);
259            out.append("d ");
260        }
261        long used = days * 60 * 60 * 24;
262
263        long hours = (seconds - used) / (60 * 60);
264        if (hours != 0 || used != 0) {
265            out.append(hours);
266            out.append("h ");
267        }
268        used += hours * 60 * 60;
269
270        long mins = (seconds-used) / 60;
271        if (mins != 0 || used != 0) {
272            out.append(mins);
273            out.append("m ");
274        }
275        used += mins * 60;
276
277        if (seconds != 0 || used != 0) {
278            out.append(seconds-used);
279            out.append("s ");
280        }
281    }
282
283    private final static String formatTime(long time) {
284        long sec = time / 100;
285        StringBuilder sb = new StringBuilder();
286        formatTime(sb, sec);
287        sb.append((time - (sec * 100)) * 10);
288        sb.append("ms ");
289        return sb.toString();
290    }
291
292    private final static String formatTimeMs(long time) {
293        long sec = time / 1000;
294        StringBuilder sb = new StringBuilder();
295        formatTime(sb, sec);
296        sb.append(time - (sec * 1000));
297        sb.append("ms ");
298        return sb.toString();
299    }
300
301    private final String formatRatioLocked(long num, long den) {
302        if (den == 0L) {
303            return "---%";
304        }
305        float perc = ((float)num) / ((float)den) * 100;
306        mFormatBuilder.setLength(0);
307        mFormatter.format("%.1f%%", perc);
308        return mFormatBuilder.toString();
309    }
310
311    /**
312     *
313     * @param sb a StringBuilder object.
314     * @param timer a Timer object contining the wakelock times.
315     * @param now the current time in microseconds.
316     * @param name the name of the wakelock.
317     * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
318     * @param linePrefix a String to be prepended to each line of output.
319     * @return the line prefix
320     */
321    private final String printWakeLock(StringBuilder sb, Timer timer, long now,
322        String name, int which, String linePrefix) {
323        if (timer != null) {
324            // Convert from microseconds to milliseconds with rounding
325            long totalTimeMillis = (timer.getTotalTime(now, which) + 500) / 1000;
326            int count = timer.getCount(which);
327            if (totalTimeMillis != 0) {
328                sb.append(linePrefix);
329                sb.append(formatTimeMs(totalTimeMillis));
330                sb.append(name);
331                sb.append(' ');
332                sb.append('(');
333                sb.append(count);
334                sb.append(" times)");
335                return ", ";
336            }
337        }
338        return linePrefix;
339    }
340
341    @SuppressWarnings("unused")
342    private final void dumpLocked(FileDescriptor fd, PrintWriter pw, String prefix, int which) {
343        long uSecTime = SystemClock.elapsedRealtime() * 1000;
344        final long uSecNow = getBatteryUptime(uSecTime);
345
346        StringBuilder sb = new StringBuilder(128);
347        if (which == STATS_TOTAL) {
348            pw.println(prefix + "Current and Historic Battery Usage Statistics:");
349            pw.println(prefix + "  System starts: " + getStartCount());
350        } else if (which == STATS_LAST) {
351            pw.println(prefix + "Last Battery Usage Statistics:");
352        } else {
353            pw.println(prefix + "Current Battery Usage Statistics:");
354        }
355        long batteryUptime = computeBatteryUptime(uSecNow, which);
356        long batteryRealtime = computeBatteryRealtime(getBatteryRealtime(uSecTime), which);
357        long elapsedRealtime = computeRealtime(uSecTime, which);
358        long uptime = computeUptime(SystemClock.uptimeMillis() * 1000, which);
359
360        pw.println(prefix
361                + "  On battery: " + formatTimeMs(batteryUptime / 1000) + "("
362                + formatRatioLocked(batteryUptime, batteryRealtime)
363                + ") uptime, "
364                + formatTimeMs(batteryRealtime / 1000) + "("
365                + formatRatioLocked(batteryRealtime, elapsedRealtime)
366                + ") realtime");
367        pw.println(prefix
368                + "  Total: "
369                + formatTimeMs(uptime / 1000)
370                + "uptime, "
371                + formatTimeMs(elapsedRealtime / 1000)
372                + "realtime");
373
374        pw.println(" ");
375
376        SparseArray<? extends Uid> uidStats = getUidStats();
377        final int NU = uidStats.size();
378        for (int iu=0; iu<NU; iu++) {
379            final int uid = uidStats.keyAt(iu);
380            Uid u = uidStats.valueAt(iu);
381            pw.println(prefix + "  #" + uid + ":");
382            boolean uidActivity = false;
383
384            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
385            if (wakelocks.size() > 0) {
386                for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
387                    : wakelocks.entrySet()) {
388                    Uid.Wakelock wl = ent.getValue();
389                    String linePrefix = ": ";
390                    sb.setLength(0);
391                    sb.append(prefix);
392                    sb.append("    Wake lock ");
393                    sb.append(ent.getKey());
394                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), uSecNow,
395                            "full", which, linePrefix);
396                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), uSecNow,
397                            "partial", which, linePrefix);
398                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), uSecNow,
399                            "window", which, linePrefix);
400                    if (linePrefix.equals(": ")) {
401                        sb.append(": (nothing executed)");
402                    }
403                    pw.println(sb.toString());
404                    uidActivity = true;
405                }
406            }
407
408            Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
409            if (sensors.size() > 0) {
410                for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
411                    : sensors.entrySet()) {
412                    Uid.Sensor se = ent.getValue();
413                    int sensorNumber = ent.getKey();
414                    sb.setLength(0);
415                    sb.append(prefix);
416                    sb.append("    Sensor ");
417                    sb.append(sensorNumber);
418
419                    Timer timer = se.getSensorTime();
420                    if (timer != null) {
421                        // Convert from microseconds to milliseconds with rounding
422                        long totalTime = (timer.getTotalTime(uSecNow, which) + 500) / 1000;
423                        int count = timer.getCount(which);
424                        if (totalTime != 0) {
425                            sb.append(": ");
426                            sb.append(formatTimeMs(totalTime));
427                            sb.append(' ');
428                            sb.append('(');
429                            sb.append(count);
430                            sb.append(" times)");
431                        }
432                    } else {
433                        sb.append(": (none used)");
434                    }
435
436                    pw.println(sb.toString());
437                    uidActivity = true;
438                }
439            }
440
441            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
442            if (processStats.size() > 0) {
443                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
444                    : processStats.entrySet()) {
445                    Uid.Proc ps = ent.getValue();
446                    long userTime;
447                    long systemTime;
448                    int starts;
449
450                    userTime = ps.getUserTime(which);
451                    systemTime = ps.getSystemTime(which);
452                    starts = ps.getStarts(which);
453
454                    if (userTime != 0 || systemTime != 0 || starts != 0) {
455                        pw.println(prefix + "    Proc " + ent.getKey() + ":");
456                        pw.println(prefix + "      CPU: " + formatTime(userTime) + "user + "
457                                + formatTime(systemTime) + "kernel");
458                        pw.println(prefix + "      " + starts + " process starts");
459                        uidActivity = true;
460                    }
461                }
462            }
463
464            Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
465            if (packageStats.size() > 0) {
466                for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
467                    : packageStats.entrySet()) {
468                    pw.println(prefix + "    Apk " + ent.getKey() + ":");
469                    boolean apkActivity = false;
470                    Uid.Pkg ps = ent.getValue();
471                    int wakeups = ps.getWakeups(which);
472                    if (wakeups != 0) {
473                        pw.println(prefix + "      " + wakeups + " wakeup alarms");
474                        apkActivity = true;
475                    }
476                    Map<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
477                    if (serviceStats.size() > 0) {
478                        for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
479                                : serviceStats.entrySet()) {
480                            BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
481                            long startTime = ss.getStartTime(uSecNow, which);
482                            int starts = ss.getStarts(which);
483                            int launches = ss.getLaunches(which);
484                            if (startTime != 0 || starts != 0 || launches != 0) {
485                                pw.println(prefix + "      Service " + sent.getKey() + ":");
486                                pw.println(prefix + "        Time spent started: "
487                                        + formatTimeMs(startTime / 1000));
488                                pw.println(prefix + "        Starts: " + starts
489                                        + ", launches: " + launches);
490                                apkActivity = true;
491                            }
492                        }
493                    }
494                    if (!apkActivity) {
495                        pw.println(prefix + "      (nothing executed)");
496                    }
497                    uidActivity = true;
498                }
499            }
500            if (!uidActivity) {
501                pw.println(prefix + "    (nothing executed)");
502            }
503        }
504    }
505
506    /**
507     * Dumps a human-readable summary of the battery statistics to the given PrintWriter.
508     *
509     * @param fd a FileDescriptor, currently unused.
510     * @param pw a PrintWriter to receive the dump output.
511     * @param args an array of Strings, currently unused.
512     */
513    @SuppressWarnings("unused")
514    public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
515        synchronized (this) {
516            dumpLocked(fd, pw, "", STATS_TOTAL);
517            pw.println("");
518            dumpLocked(fd, pw, "", STATS_LAST);
519            pw.println("");
520            dumpLocked(fd, pw, "", STATS_CURRENT);
521        }
522    }
523}
524