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