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