blob: ed7c3663ce285ccbb48e9a8525d18254bb605e1c [file] [log] [blame]
package android.os;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Formatter;
import java.util.Map;
import android.util.SparseArray;
/**
* A class providing access to battery usage statistics, including information on
* wakelocks, processes, packages, and services. All times are represented in microseconds
* except where indicated otherwise.
*/
public abstract class BatteryStats {
/**
* A constant indicating a partial wake lock.
*/
public static final int WAKE_TYPE_PARTIAL = 0;
/**
* A constant indicating a full wake lock.
*/
public static final int WAKE_TYPE_FULL = 1;
/**
* A constant indicating a window wake lock.
*/
public static final int WAKE_TYPE_WINDOW = 2;
/**
* Include all of the data in the stats, including previously saved data.
*/
public static final int STATS_TOTAL = 0;
/**
* Include only the last run in the stats.
*/
public static final int STATS_LAST = 1;
/**
* Include only the current run in the stats.
*/
public static final int STATS_CURRENT = 2;
/**
* Include only the run since the last time the device was unplugged in the stats.
*/
public static final int STATS_UNPLUGGED = 3;
private final StringBuilder mFormatBuilder = new StringBuilder(8);
private final Formatter mFormatter = new Formatter(mFormatBuilder);
/**
* State for keeping track of timing information.
*/
public static abstract class Timer {
/**
* Returns the count associated with this Timer for the
* selected type of statistics.
*
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
*/
public abstract int getCount(int which);
/**
* Returns the total time in microseconds associated with this Timer for the
* selected type of statistics.
*
* @param now system uptime time in microseconds
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
* @return a time in microseconds
*/
public abstract long getTotalTime(long now, int which);
}
/**
* The statistics associated with a particular uid.
*/
public static abstract class Uid {
/**
* Returns a mapping containing wakelock statistics.
*
* @return a Map from Strings to Uid.Wakelock objects.
*/
public abstract Map<String, ? extends Wakelock> getWakelockStats();
/**
* The statistics associated with a particular wake lock.
*/
public static abstract class Wakelock {
public abstract Timer getWakeTime(int type);
}
/**
* Returns a mapping containing sensor statistics.
*
* @return a Map from Integer sensor ids to Uid.Sensor objects.
*/
public abstract Map<Integer, ? extends Sensor> getSensorStats();
/**
* Returns a mapping containing process statistics.
*
* @return a Map from Strings to Uid.Proc objects.
*/
public abstract Map<String, ? extends Proc> getProcessStats();
/**
* Returns a mapping containing package statistics.
*
* @return a Map from Strings to Uid.Pkg objects.
*/
public abstract Map<String, ? extends Pkg> getPackageStats();
public static abstract class Sensor {
public abstract Timer getSensorTime();
}
/**
* The statistics associated with a particular process.
*/
public static abstract class Proc {
/**
* Returns the total time (in 1/100 sec) spent executing in user code.
*
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
*/
public abstract long getUserTime(int which);
/**
* Returns the total time (in 1/100 sec) spent executing in system code.
*
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
*/
public abstract long getSystemTime(int which);
/**
* Returns the number of times the process has been started.
*
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
*/
public abstract int getStarts(int which);
}
/**
* The statistics associated with a particular package.
*/
public static abstract class Pkg {
/**
* Returns the number of times this package has done something that could wake up the
* device from sleep.
*
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
*/
public abstract int getWakeups(int which);
/**
* Returns a mapping containing service statistics.
*/
public abstract Map<String, ? extends Serv> getServiceStats();
/**
* The statistics associated with a particular service.
*/
public abstract class Serv {
/**
* Returns the amount of time spent started.
*
* @param now elapsed realtime in microseconds.
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
* @return
*/
public abstract long getStartTime(long now, int which);
/**
* Returns the total number of times startService() has been called.
*
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
*/
public abstract int getStarts(int which);
/**
* Returns the total number times the service has been launched.
*
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
*/
public abstract int getLaunches(int which);
}
}
}
/**
* Returns the number of times the device has been started.
*/
public abstract int getStartCount();
/**
* Returns a SparseArray containing the statistics for each uid.
*/
public abstract SparseArray<? extends Uid> getUidStats();
/**
* Returns the current battery uptime in microseconds.
*
* @param curTime the amount of elapsed realtime in microseconds.
*/
public abstract long getBatteryUptime(long curTime);
/**
* Returns the current battery realtime in microseconds.
*
* @param curTime the amount of elapsed realtime in microseconds.
*/
public abstract long getBatteryRealtime(long curTime);
/**
* Returns the total, last, or current battery uptime in microseconds.
*
* @param curTime the elapsed realtime in microseconds.
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
*/
public abstract long computeBatteryUptime(long curTime, int which);
/**
* Returns the total, last, or current battery realtime in microseconds.
*
* @param curTime the current elapsed realtime in microseconds.
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
*/
public abstract long computeBatteryRealtime(long curTime, int which);
/**
* Returns the total, last, or current uptime in microseconds.
*
* @param curTime the current elapsed realtime in microseconds.
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
*/
public abstract long computeUptime(long curTime, int which);
/**
* Returns the total, last, or current realtime in microseconds.
* *
* @param curTime the current elapsed realtime in microseconds.
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
*/
public abstract long computeRealtime(long curTime, int which);
private final static void formatTime(StringBuilder out, long seconds) {
long days = seconds / (60 * 60 * 24);
if (days != 0) {
out.append(days);
out.append("d ");
}
long used = days * 60 * 60 * 24;
long hours = (seconds - used) / (60 * 60);
if (hours != 0 || used != 0) {
out.append(hours);
out.append("h ");
}
used += hours * 60 * 60;
long mins = (seconds-used) / 60;
if (mins != 0 || used != 0) {
out.append(mins);
out.append("m ");
}
used += mins * 60;
if (seconds != 0 || used != 0) {
out.append(seconds-used);
out.append("s ");
}
}
private final static String formatTime(long time) {
long sec = time / 100;
StringBuilder sb = new StringBuilder();
formatTime(sb, sec);
sb.append((time - (sec * 100)) * 10);
sb.append("ms ");
return sb.toString();
}
private final static String formatTimeMs(long time) {
long sec = time / 1000;
StringBuilder sb = new StringBuilder();
formatTime(sb, sec);
sb.append(time - (sec * 1000));
sb.append("ms ");
return sb.toString();
}
private final String formatRatioLocked(long num, long den) {
if (den == 0L) {
return "---%";
}
float perc = ((float)num) / ((float)den) * 100;
mFormatBuilder.setLength(0);
mFormatter.format("%.1f%%", perc);
return mFormatBuilder.toString();
}
/**
*
* @param sb a StringBuilder object.
* @param timer a Timer object contining the wakelock times.
* @param now the current time in microseconds.
* @param name the name of the wakelock.
* @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
* @param linePrefix a String to be prepended to each line of output.
* @return the line prefix
*/
private final String printWakeLock(StringBuilder sb, Timer timer, long now,
String name, int which, String linePrefix) {
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
long totalTimeMillis = (timer.getTotalTime(now, which) + 500) / 1000;
int count = timer.getCount(which);
if (totalTimeMillis != 0) {
sb.append(linePrefix);
sb.append(formatTimeMs(totalTimeMillis));
sb.append(name);
sb.append(' ');
sb.append('(');
sb.append(count);
sb.append(" times)");
return ", ";
}
}
return linePrefix;
}
@SuppressWarnings("unused")
private final void dumpLocked(FileDescriptor fd, PrintWriter pw, String prefix, int which) {
long uSecTime = SystemClock.elapsedRealtime() * 1000;
final long uSecNow = getBatteryUptime(uSecTime);
StringBuilder sb = new StringBuilder(128);
if (which == STATS_TOTAL) {
pw.println(prefix + "Current and Historic Battery Usage Statistics:");
pw.println(prefix + " System starts: " + getStartCount());
} else if (which == STATS_LAST) {
pw.println(prefix + "Last Battery Usage Statistics:");
} else {
pw.println(prefix + "Current Battery Usage Statistics:");
}
long batteryUptime = computeBatteryUptime(uSecNow, which);
long batteryRealtime = computeBatteryRealtime(getBatteryRealtime(uSecTime), which);
long elapsedRealtime = computeRealtime(uSecTime, which);
long uptime = computeUptime(SystemClock.uptimeMillis() * 1000, which);
pw.println(prefix
+ " On battery: " + formatTimeMs(batteryUptime / 1000) + "("
+ formatRatioLocked(batteryUptime, batteryRealtime)
+ ") uptime, "
+ formatTimeMs(batteryRealtime / 1000) + "("
+ formatRatioLocked(batteryRealtime, elapsedRealtime)
+ ") realtime");
pw.println(prefix
+ " Total: "
+ formatTimeMs(uptime / 1000)
+ "uptime, "
+ formatTimeMs(elapsedRealtime / 1000)
+ "realtime");
pw.println(" ");
SparseArray<? extends Uid> uidStats = getUidStats();
final int NU = uidStats.size();
for (int iu=0; iu<NU; iu++) {
final int uid = uidStats.keyAt(iu);
Uid u = uidStats.valueAt(iu);
pw.println(prefix + " #" + uid + ":");
boolean uidActivity = false;
Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
if (wakelocks.size() > 0) {
for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
: wakelocks.entrySet()) {
Uid.Wakelock wl = ent.getValue();
String linePrefix = ": ";
sb.setLength(0);
sb.append(prefix);
sb.append(" Wake lock ");
sb.append(ent.getKey());
linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), uSecNow,
"full", which, linePrefix);
linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), uSecNow,
"partial", which, linePrefix);
linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), uSecNow,
"window", which, linePrefix);
if (linePrefix.equals(": ")) {
sb.append(": (nothing executed)");
}
pw.println(sb.toString());
uidActivity = true;
}
}
Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
if (sensors.size() > 0) {
for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
: sensors.entrySet()) {
Uid.Sensor se = ent.getValue();
int sensorNumber = ent.getKey();
sb.setLength(0);
sb.append(prefix);
sb.append(" Sensor ");
sb.append(sensorNumber);
Timer timer = se.getSensorTime();
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
long totalTime = (timer.getTotalTime(uSecNow, which) + 500) / 1000;
int count = timer.getCount(which);
if (totalTime != 0) {
sb.append(": ");
sb.append(formatTimeMs(totalTime));
sb.append(' ');
sb.append('(');
sb.append(count);
sb.append(" times)");
}
} else {
sb.append(": (none used)");
}
pw.println(sb.toString());
uidActivity = true;
}
}
Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
if (processStats.size() > 0) {
for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
: processStats.entrySet()) {
Uid.Proc ps = ent.getValue();
long userTime;
long systemTime;
int starts;
userTime = ps.getUserTime(which);
systemTime = ps.getSystemTime(which);
starts = ps.getStarts(which);
if (userTime != 0 || systemTime != 0 || starts != 0) {
pw.println(prefix + " Proc " + ent.getKey() + ":");
pw.println(prefix + " CPU: " + formatTime(userTime) + "user + "
+ formatTime(systemTime) + "kernel");
pw.println(prefix + " " + starts + " process starts");
uidActivity = true;
}
}
}
Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
if (packageStats.size() > 0) {
for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
: packageStats.entrySet()) {
pw.println(prefix + " Apk " + ent.getKey() + ":");
boolean apkActivity = false;
Uid.Pkg ps = ent.getValue();
int wakeups = ps.getWakeups(which);
if (wakeups != 0) {
pw.println(prefix + " " + wakeups + " wakeup alarms");
apkActivity = true;
}
Map<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
if (serviceStats.size() > 0) {
for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
: serviceStats.entrySet()) {
BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
long startTime = ss.getStartTime(uSecNow, which);
int starts = ss.getStarts(which);
int launches = ss.getLaunches(which);
if (startTime != 0 || starts != 0 || launches != 0) {
pw.println(prefix + " Service " + sent.getKey() + ":");
pw.println(prefix + " Time spent started: "
+ formatTimeMs(startTime / 1000));
pw.println(prefix + " Starts: " + starts
+ ", launches: " + launches);
apkActivity = true;
}
}
}
if (!apkActivity) {
pw.println(prefix + " (nothing executed)");
}
uidActivity = true;
}
}
if (!uidActivity) {
pw.println(prefix + " (nothing executed)");
}
}
}
/**
* Dumps a human-readable summary of the battery statistics to the given PrintWriter.
*
* @param fd a FileDescriptor, currently unused.
* @param pw a PrintWriter to receive the dump output.
* @param args an array of Strings, currently unused.
*/
@SuppressWarnings("unused")
public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (this) {
dumpLocked(fd, pw, "", STATS_TOTAL);
pw.println("");
dumpLocked(fd, pw, "", STATS_LAST);
pw.println("");
dumpLocked(fd, pw, "", STATS_CURRENT);
}
}
}