BatteryStats.java revision f013e1afd1e68af5e3b868c26a653bbfb39538f8
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 micropeconds.
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        float perc = ((float)num) / ((float)den) * 100;
303        mFormatBuilder.setLength(0);
304        mFormatter.format("%.1f%%", perc);
305        return mFormatBuilder.toString();
306    }
307
308    /**
309     *
310     * @param sb a StringBuilder object.
311     * @param timer a Timer object contining the wakelock times.
312     * @param now the current time in microseconds.
313     * @param name the name of the wakelock.
314     * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
315     * @param linePrefix a String to be prepended to each line of output.
316     * @return the line prefix
317     */
318    private final String printWakeLock(StringBuilder sb, Timer timer, long now,
319        String name, int which, String linePrefix) {
320        if (timer != null) {
321            // Convert from microseconds to milliseconds with rounding
322            long totalTimeMillis = (timer.getTotalTime(now, which) + 500) / 1000;
323            int count = timer.getCount(which);
324            if (totalTimeMillis != 0) {
325                sb.append(linePrefix);
326                sb.append(formatTimeMs(totalTimeMillis));
327                sb.append(name);
328                sb.append(' ');
329                sb.append('(');
330                sb.append(count);
331                sb.append(" times)");
332                return ", ";
333            }
334        }
335        return linePrefix;
336    }
337
338    @SuppressWarnings("unused")
339    private final void dumpLocked(FileDescriptor fd, PrintWriter pw, String prefix, int which) {
340        long uSecTime = SystemClock.elapsedRealtime() * 1000;
341        final long uSecNow = getBatteryUptime(uSecTime);
342
343        StringBuilder sb = new StringBuilder(128);
344        if (which == STATS_TOTAL) {
345            pw.println(prefix + "Current and Historic Battery Usage Statistics:");
346            pw.println(prefix + "  System starts: " + getStartCount());
347        } else if (which == STATS_LAST) {
348            pw.println(prefix + "Last Battery Usage Statistics:");
349        } else {
350            pw.println(prefix + "Current Battery Usage Statistics:");
351        }
352        long batteryUptime = computeBatteryUptime(uSecNow, which);
353        long batteryRealtime = computeBatteryRealtime(getBatteryRealtime(uSecTime), which);
354        long elapsedRealtime = computeRealtime(uSecTime, which);
355        pw.println(prefix
356                + "  On battery: " + formatTimeMs(batteryUptime) + "("
357                + formatRatioLocked(batteryUptime, batteryRealtime)
358                + ") uptime, "
359                + formatTimeMs(batteryRealtime) + "("
360                + formatRatioLocked(batteryRealtime, elapsedRealtime)
361                + ") realtime");
362        pw.println(prefix
363                + "  Total: "
364                + formatTimeMs(computeUptime(SystemClock.uptimeMillis() * 1000, which))
365                + "uptime, "
366                + formatTimeMs(elapsedRealtime)
367                + "realtime");
368
369        pw.println(" ");
370
371        SparseArray<? extends Uid> uidStats = getUidStats();
372        final int NU = uidStats.size();
373        for (int iu=0; iu<NU; iu++) {
374            final int uid = uidStats.keyAt(iu);
375            Uid u = uidStats.valueAt(iu);
376            pw.println(prefix + "  #" + uid + ":");
377            boolean uidActivity = false;
378
379            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
380            if (wakelocks.size() > 0) {
381                for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
382                    : wakelocks.entrySet()) {
383                    Uid.Wakelock wl = ent.getValue();
384                    String linePrefix = ": ";
385                    sb.setLength(0);
386                    sb.append(prefix);
387                    sb.append("    Wake lock ");
388                    sb.append(ent.getKey());
389                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), uSecNow,
390                            "full", which, linePrefix);
391                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), uSecNow,
392                            "partial", which, linePrefix);
393                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), uSecNow,
394                            "window", which, linePrefix);
395                    if (linePrefix.equals(": ")) {
396                        sb.append(": (nothing executed)");
397                    }
398                    pw.println(sb.toString());
399                    uidActivity = true;
400                }
401            }
402
403            Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
404            if (sensors.size() > 0) {
405                for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
406                    : sensors.entrySet()) {
407                    Uid.Sensor se = ent.getValue();
408                    int sensorNumber = ent.getKey();
409                    sb.setLength(0);
410                    sb.append(prefix);
411                    sb.append("    Sensor ");
412                    sb.append(sensorNumber);
413
414                    Timer timer = se.getSensorTime();
415                    if (timer != null) {
416                        // Convert from microseconds to milliseconds with rounding
417                        long totalTime = (timer.getTotalTime(uSecNow, which) + 500) / 1000;
418                        int count = timer.getCount(which);
419                        if (totalTime != 0) {
420                            sb.append(": ");
421                            sb.append(formatTimeMs(totalTime));
422                            sb.append(' ');
423                            sb.append('(');
424                            sb.append(count);
425                            sb.append(" times)");
426                        }
427                    } else {
428                        sb.append(": (none used)");
429                    }
430
431                    pw.println(sb.toString());
432                    uidActivity = true;
433                }
434            }
435
436            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
437            if (processStats.size() > 0) {
438                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
439                    : processStats.entrySet()) {
440                    Uid.Proc ps = ent.getValue();
441                    long userTime;
442                    long systemTime;
443                    int starts;
444
445                    userTime = ps.getUserTime(which);
446                    systemTime = ps.getSystemTime(which);
447                    starts = ps.getStarts(which);
448
449                    if (userTime != 0 || systemTime != 0 || starts != 0) {
450                        pw.println(prefix + "    Proc " + ent.getKey() + ":");
451                        pw.println(prefix + "      CPU: " + formatTime(userTime) + "user + "
452                                + formatTime(systemTime) + "kernel");
453                        pw.println(prefix + "      " + starts + " process starts");
454                        uidActivity = true;
455                    }
456                }
457            }
458
459            Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
460            if (packageStats.size() > 0) {
461                for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
462                    : packageStats.entrySet()) {
463                    pw.println(prefix + "    Apk " + ent.getKey() + ":");
464                    boolean apkActivity = false;
465                    Uid.Pkg ps = ent.getValue();
466                    int wakeups = ps.getWakeups(which);
467                    if (wakeups != 0) {
468                        pw.println(prefix + "      " + wakeups + " wakeup alarms");
469                        apkActivity = true;
470                    }
471                    Map<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
472                    if (serviceStats.size() > 0) {
473                        for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
474                                : serviceStats.entrySet()) {
475                            BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
476                            long startTime = ss.getStartTime(uSecNow, which);
477                            int starts = ss.getStarts(which);
478                            int launches = ss.getLaunches(which);
479                            if (startTime != 0 || starts != 0 || launches != 0) {
480                                pw.println(prefix + "      Service " + sent.getKey() + ":");
481                                pw.println(prefix + "        Time spent started: "
482                                        + formatTimeMs(startTime));
483                                pw.println(prefix + "        Starts: " + starts
484                                        + ", launches: " + launches);
485                                apkActivity = true;
486                            }
487                        }
488                    }
489                    if (!apkActivity) {
490                        pw.println(prefix + "      (nothing executed)");
491                    }
492                    uidActivity = true;
493                }
494            }
495            if (!uidActivity) {
496                pw.println(prefix + "    (nothing executed)");
497            }
498        }
499    }
500
501    /**
502     * Dumps a human-readable summary of the battery statistics to the given PrintWriter.
503     *
504     * @param fd a FileDescriptor, currently unused.
505     * @param pw a PrintWriter to receive the dump output.
506     * @param args an array of Strings, currently unused.
507     */
508    @SuppressWarnings("unused")
509    public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
510        synchronized (this) {
511            dumpLocked(fd, pw, "", STATS_TOTAL);
512            pw.println("");
513            dumpLocked(fd, pw, "", STATS_LAST);
514            pw.println("");
515            dumpLocked(fd, pw, "", STATS_CURRENT);
516        }
517    }
518}
519