BatteryStats.java revision 99d0452ddc0a0435030a462bda9f4d57b58bad9a
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.os; 18 19import java.io.PrintWriter; 20import java.util.Formatter; 21import java.util.Map; 22 23import android.util.Log; 24import android.util.Printer; 25import android.util.SparseArray; 26import android.util.TimeUtils; 27 28/** 29 * A class providing access to battery usage statistics, including information on 30 * wakelocks, processes, packages, and services. All times are represented in microseconds 31 * except where indicated otherwise. 32 * @hide 33 */ 34public abstract class BatteryStats implements Parcelable { 35 36 private static final boolean LOCAL_LOGV = false; 37 38 /** 39 * A constant indicating a partial wake lock timer. 40 */ 41 public static final int WAKE_TYPE_PARTIAL = 0; 42 43 /** 44 * A constant indicating a full wake lock timer. 45 */ 46 public static final int WAKE_TYPE_FULL = 1; 47 48 /** 49 * A constant indicating a window wake lock timer. 50 */ 51 public static final int WAKE_TYPE_WINDOW = 2; 52 53 /** 54 * A constant indicating a sensor timer. 55 */ 56 public static final int SENSOR = 3; 57 58 /** 59 * A constant indicating a a wifi turn on timer 60 */ 61 public static final int WIFI_TURNED_ON = 4; 62 63 /** 64 * A constant indicating a full wifi lock timer 65 */ 66 public static final int FULL_WIFI_LOCK = 5; 67 68 /** 69 * A constant indicating a scan wifi lock timer 70 */ 71 public static final int SCAN_WIFI_LOCK = 6; 72 73 /** 74 * A constant indicating a wifi multicast timer 75 */ 76 public static final int WIFI_MULTICAST_ENABLED = 7; 77 78 /** 79 * A constant indicating an audio turn on timer 80 */ 81 public static final int AUDIO_TURNED_ON = 7; 82 83 /** 84 * A constant indicating a video turn on timer 85 */ 86 public static final int VIDEO_TURNED_ON = 8; 87 88 /** 89 * Include all of the data in the stats, including previously saved data. 90 */ 91 public static final int STATS_SINCE_CHARGED = 0; 92 93 /** 94 * Include only the last run in the stats. 95 */ 96 public static final int STATS_LAST = 1; 97 98 /** 99 * Include only the current run in the stats. 100 */ 101 public static final int STATS_CURRENT = 2; 102 103 /** 104 * Include only the run since the last time the device was unplugged in the stats. 105 */ 106 public static final int STATS_SINCE_UNPLUGGED = 3; 107 108 // NOTE: Update this list if you add/change any stats above. 109 // These characters are supposed to represent "total", "last", "current", 110 // and "unplugged". They were shortened for efficiency sake. 111 private static final String[] STAT_NAMES = { "t", "l", "c", "u" }; 112 113 /** 114 * Bump the version on this if the checkin format changes. 115 */ 116 private static final int BATTERY_STATS_CHECKIN_VERSION = 5; 117 118 private static final long BYTES_PER_KB = 1024; 119 private static final long BYTES_PER_MB = 1048576; // 1024^2 120 private static final long BYTES_PER_GB = 1073741824; //1024^3 121 122 123 private static final String APK_DATA = "apk"; 124 private static final String PROCESS_DATA = "pr"; 125 private static final String SENSOR_DATA = "sr"; 126 private static final String WAKELOCK_DATA = "wl"; 127 private static final String KERNEL_WAKELOCK_DATA = "kwl"; 128 private static final String NETWORK_DATA = "nt"; 129 private static final String USER_ACTIVITY_DATA = "ua"; 130 private static final String BATTERY_DATA = "bt"; 131 private static final String BATTERY_LEVEL_DATA = "lv"; 132 private static final String WIFI_LOCK_DATA = "wfl"; 133 private static final String MISC_DATA = "m"; 134 private static final String SCREEN_BRIGHTNESS_DATA = "br"; 135 private static final String SIGNAL_STRENGTH_TIME_DATA = "sgt"; 136 private static final String SIGNAL_SCANNING_TIME_DATA = "sst"; 137 private static final String SIGNAL_STRENGTH_COUNT_DATA = "sgc"; 138 private static final String DATA_CONNECTION_TIME_DATA = "dct"; 139 private static final String DATA_CONNECTION_COUNT_DATA = "dcc"; 140 141 private final StringBuilder mFormatBuilder = new StringBuilder(32); 142 private final Formatter mFormatter = new Formatter(mFormatBuilder); 143 144 /** 145 * State for keeping track of counting information. 146 */ 147 public static abstract class Counter { 148 149 /** 150 * Returns the count associated with this Counter for the 151 * selected type of statistics. 152 * 153 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT 154 */ 155 public abstract int getCountLocked(int which); 156 157 /** 158 * Temporary for debugging. 159 */ 160 public abstract void logState(Printer pw, String prefix); 161 } 162 163 /** 164 * State for keeping track of timing information. 165 */ 166 public static abstract class Timer { 167 168 /** 169 * Returns the count associated with this Timer for the 170 * selected type of statistics. 171 * 172 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT 173 */ 174 public abstract int getCountLocked(int which); 175 176 /** 177 * Returns the total time in microseconds associated with this Timer for the 178 * selected type of statistics. 179 * 180 * @param batteryRealtime system realtime on battery in microseconds 181 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT 182 * @return a time in microseconds 183 */ 184 public abstract long getTotalTimeLocked(long batteryRealtime, int which); 185 186 /** 187 * Temporary for debugging. 188 */ 189 public abstract void logState(Printer pw, String prefix); 190 } 191 192 /** 193 * The statistics associated with a particular uid. 194 */ 195 public static abstract class Uid { 196 197 /** 198 * Returns a mapping containing wakelock statistics. 199 * 200 * @return a Map from Strings to Uid.Wakelock objects. 201 */ 202 public abstract Map<String, ? extends Wakelock> getWakelockStats(); 203 204 /** 205 * The statistics associated with a particular wake lock. 206 */ 207 public static abstract class Wakelock { 208 public abstract Timer getWakeTime(int type); 209 } 210 211 /** 212 * Returns a mapping containing sensor statistics. 213 * 214 * @return a Map from Integer sensor ids to Uid.Sensor objects. 215 */ 216 public abstract Map<Integer, ? extends Sensor> getSensorStats(); 217 218 /** 219 * Returns a mapping containing process statistics. 220 * 221 * @return a Map from Strings to Uid.Proc objects. 222 */ 223 public abstract Map<String, ? extends Proc> getProcessStats(); 224 225 /** 226 * Returns a mapping containing package statistics. 227 * 228 * @return a Map from Strings to Uid.Pkg objects. 229 */ 230 public abstract Map<String, ? extends Pkg> getPackageStats(); 231 232 /** 233 * {@hide} 234 */ 235 public abstract int getUid(); 236 237 /** 238 * {@hide} 239 */ 240 public abstract long getTcpBytesReceived(int which); 241 242 /** 243 * {@hide} 244 */ 245 public abstract long getTcpBytesSent(int which); 246 247 public abstract void noteWifiTurnedOnLocked(); 248 public abstract void noteWifiTurnedOffLocked(); 249 public abstract void noteFullWifiLockAcquiredLocked(); 250 public abstract void noteFullWifiLockReleasedLocked(); 251 public abstract void noteScanWifiLockAcquiredLocked(); 252 public abstract void noteScanWifiLockReleasedLocked(); 253 public abstract void noteWifiMulticastEnabledLocked(); 254 public abstract void noteWifiMulticastDisabledLocked(); 255 public abstract void noteAudioTurnedOnLocked(); 256 public abstract void noteAudioTurnedOffLocked(); 257 public abstract void noteVideoTurnedOnLocked(); 258 public abstract void noteVideoTurnedOffLocked(); 259 public abstract long getWifiTurnedOnTime(long batteryRealtime, int which); 260 public abstract long getFullWifiLockTime(long batteryRealtime, int which); 261 public abstract long getScanWifiLockTime(long batteryRealtime, int which); 262 public abstract long getWifiMulticastTime(long batteryRealtime, 263 int which); 264 public abstract long getAudioTurnedOnTime(long batteryRealtime, int which); 265 public abstract long getVideoTurnedOnTime(long batteryRealtime, int which); 266 267 /** 268 * Note that these must match the constants in android.os.LocalPowerManager. 269 */ 270 static final String[] USER_ACTIVITY_TYPES = { 271 "other", "cheek", "touch", "long_touch", "touch_up", "button", "unknown" 272 }; 273 274 public static final int NUM_USER_ACTIVITY_TYPES = 7; 275 276 public abstract void noteUserActivityLocked(int type); 277 public abstract boolean hasUserActivity(); 278 public abstract int getUserActivityCount(int type, int which); 279 280 public static abstract class Sensor { 281 // Magic sensor number for the GPS. 282 public static final int GPS = -10000; 283 284 public abstract int getHandle(); 285 286 public abstract Timer getSensorTime(); 287 } 288 289 /** 290 * The statistics associated with a particular process. 291 */ 292 public static abstract class Proc { 293 294 public static class ExcessiveWake { 295 public long overTime; 296 public long usedTime; 297 } 298 299 /** 300 * Returns the total time (in 1/100 sec) spent executing in user code. 301 * 302 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. 303 */ 304 public abstract long getUserTime(int which); 305 306 /** 307 * Returns the total time (in 1/100 sec) spent executing in system code. 308 * 309 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. 310 */ 311 public abstract long getSystemTime(int which); 312 313 /** 314 * Returns the number of times the process has been started. 315 * 316 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. 317 */ 318 public abstract int getStarts(int which); 319 320 /** 321 * Returns the cpu time spent in microseconds while the process was in the foreground. 322 * @param which one of STATS_TOTAL, STATS_LAST, STATS_CURRENT or STATS_UNPLUGGED 323 * @return foreground cpu time in microseconds 324 */ 325 public abstract long getForegroundTime(int which); 326 327 /** 328 * Returns the approximate cpu time spent in microseconds, at a certain CPU speed. 329 * @param speedStep the index of the CPU speed. This is not the actual speed of the 330 * CPU. 331 * @param which one of STATS_TOTAL, STATS_LAST, STATS_CURRENT or STATS_UNPLUGGED 332 * @see BatteryStats#getCpuSpeedSteps() 333 */ 334 public abstract long getTimeAtCpuSpeedStep(int speedStep, int which); 335 336 public abstract int countExcessiveWakes(); 337 338 public abstract ExcessiveWake getExcessiveWake(int i); 339 } 340 341 /** 342 * The statistics associated with a particular package. 343 */ 344 public static abstract class Pkg { 345 346 /** 347 * Returns the number of times this package has done something that could wake up the 348 * device from sleep. 349 * 350 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. 351 */ 352 public abstract int getWakeups(int which); 353 354 /** 355 * Returns a mapping containing service statistics. 356 */ 357 public abstract Map<String, ? extends Serv> getServiceStats(); 358 359 /** 360 * The statistics associated with a particular service. 361 */ 362 public abstract class Serv { 363 364 /** 365 * Returns the amount of time spent started. 366 * 367 * @param batteryUptime elapsed uptime on battery in microseconds. 368 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. 369 * @return 370 */ 371 public abstract long getStartTime(long batteryUptime, int which); 372 373 /** 374 * Returns the total number of times startService() has been called. 375 * 376 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. 377 */ 378 public abstract int getStarts(int which); 379 380 /** 381 * Returns the total number times the service has been launched. 382 * 383 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. 384 */ 385 public abstract int getLaunches(int which); 386 } 387 } 388 } 389 390 public final class HistoryItem implements Parcelable { 391 public HistoryItem next; 392 393 public long time; 394 395 public static final byte CMD_UPDATE = 0; 396 public static final byte CMD_START = 1; 397 398 public byte cmd; 399 400 public byte batteryLevel; 401 public byte batteryStatus; 402 public byte batteryHealth; 403 public byte batteryPlugType; 404 405 public char batteryTemperature; 406 public char batteryVoltage; 407 408 // Constants from SCREEN_BRIGHTNESS_* 409 public static final int STATE_BRIGHTNESS_MASK = 0x000000f; 410 public static final int STATE_BRIGHTNESS_SHIFT = 0; 411 // Constants from SIGNAL_STRENGTH_* 412 public static final int STATE_SIGNAL_STRENGTH_MASK = 0x00000f0; 413 public static final int STATE_SIGNAL_STRENGTH_SHIFT = 4; 414 // Constants from ServiceState.STATE_* 415 public static final int STATE_PHONE_STATE_MASK = 0x0000f00; 416 public static final int STATE_PHONE_STATE_SHIFT = 8; 417 // Constants from DATA_CONNECTION_* 418 public static final int STATE_DATA_CONNECTION_MASK = 0x000f000; 419 public static final int STATE_DATA_CONNECTION_SHIFT = 12; 420 421 public static final int STATE_BATTERY_PLUGGED_FLAG = 1<<30; 422 public static final int STATE_SCREEN_ON_FLAG = 1<<29; 423 public static final int STATE_GPS_ON_FLAG = 1<<28; 424 public static final int STATE_PHONE_IN_CALL_FLAG = 1<<27; 425 public static final int STATE_PHONE_SCANNING_FLAG = 1<<26; 426 public static final int STATE_WIFI_ON_FLAG = 1<<25; 427 public static final int STATE_WIFI_RUNNING_FLAG = 1<<24; 428 public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<23; 429 public static final int STATE_WIFI_SCAN_LOCK_FLAG = 1<<22; 430 public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<21; 431 public static final int STATE_BLUETOOTH_ON_FLAG = 1<<20; 432 public static final int STATE_AUDIO_ON_FLAG = 1<<19; 433 public static final int STATE_VIDEO_ON_FLAG = 1<<18; 434 public static final int STATE_WAKE_LOCK_FLAG = 1<<17; 435 public static final int STATE_SENSOR_ON_FLAG = 1<<16; 436 437 public int states; 438 439 public HistoryItem() { 440 } 441 442 public HistoryItem(long time, Parcel src) { 443 this.time = time; 444 int bat = src.readInt(); 445 cmd = (byte)(bat&0xff); 446 batteryLevel = (byte)((bat>>8)&0xff); 447 batteryStatus = (byte)((bat>>16)&0xf); 448 batteryHealth = (byte)((bat>>20)&0xf); 449 batteryPlugType = (byte)((bat>>24)&0xf); 450 bat = src.readInt(); 451 batteryTemperature = (char)(bat&0xffff); 452 batteryVoltage = (char)((bat>>16)&0xffff); 453 states = src.readInt(); 454 } 455 456 public int describeContents() { 457 return 0; 458 } 459 460 public void writeToParcel(Parcel dest, int flags) { 461 dest.writeLong(time); 462 int bat = (((int)cmd)&0xff) 463 | ((((int)batteryLevel)<<8)&0xff00) 464 | ((((int)batteryStatus)<<16)&0xf0000) 465 | ((((int)batteryHealth)<<20)&0xf00000) 466 | ((((int)batteryPlugType)<<24)&0xf000000); 467 dest.writeInt(bat); 468 bat = (((int)batteryTemperature)&0xffff) 469 | ((((int)batteryVoltage)<<16)&0xffff0000); 470 dest.writeInt(bat); 471 dest.writeInt(states); 472 } 473 474 public void setTo(long time, byte cmd, HistoryItem o) { 475 this.time = time; 476 this.cmd = cmd; 477 batteryLevel = o.batteryLevel; 478 batteryStatus = o.batteryStatus; 479 batteryHealth = o.batteryHealth; 480 batteryPlugType = o.batteryPlugType; 481 batteryTemperature = o.batteryTemperature; 482 batteryVoltage = o.batteryVoltage; 483 states = o.states; 484 } 485 486 public boolean same(HistoryItem o) { 487 return batteryLevel == o.batteryLevel 488 && batteryStatus == o.batteryStatus 489 && batteryHealth == o.batteryHealth 490 && batteryPlugType == o.batteryPlugType 491 && batteryTemperature == o.batteryTemperature 492 && batteryVoltage == o.batteryVoltage 493 && states == o.states; 494 } 495 } 496 497 public static final class BitDescription { 498 public final int mask; 499 public final int shift; 500 public final String name; 501 public final String[] values; 502 503 public BitDescription(int mask, String name) { 504 this.mask = mask; 505 this.shift = -1; 506 this.name = name; 507 this.values = null; 508 } 509 510 public BitDescription(int mask, int shift, String name, String[] values) { 511 this.mask = mask; 512 this.shift = shift; 513 this.name = name; 514 this.values = values; 515 } 516 } 517 518 /** 519 * Return the current history of battery state changes. 520 */ 521 public abstract HistoryItem getHistory(); 522 523 /** 524 * Returns the number of times the device has been started. 525 */ 526 public abstract int getStartCount(); 527 528 /** 529 * Returns the time in microseconds that the screen has been on while the device was 530 * running on battery. 531 * 532 * {@hide} 533 */ 534 public abstract long getScreenOnTime(long batteryRealtime, int which); 535 536 public static final int SCREEN_BRIGHTNESS_DARK = 0; 537 public static final int SCREEN_BRIGHTNESS_DIM = 1; 538 public static final int SCREEN_BRIGHTNESS_MEDIUM = 2; 539 public static final int SCREEN_BRIGHTNESS_LIGHT = 3; 540 public static final int SCREEN_BRIGHTNESS_BRIGHT = 4; 541 542 static final String[] SCREEN_BRIGHTNESS_NAMES = { 543 "dark", "dim", "medium", "light", "bright" 544 }; 545 546 public static final int NUM_SCREEN_BRIGHTNESS_BINS = 5; 547 548 /** 549 * Returns the time in microseconds that the screen has been on with 550 * the given brightness 551 * 552 * {@hide} 553 */ 554 public abstract long getScreenBrightnessTime(int brightnessBin, 555 long batteryRealtime, int which); 556 557 public abstract int getInputEventCount(int which); 558 559 /** 560 * Returns the time in microseconds that the phone has been on while the device was 561 * running on battery. 562 * 563 * {@hide} 564 */ 565 public abstract long getPhoneOnTime(long batteryRealtime, int which); 566 567 public static final int SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0; 568 public static final int SIGNAL_STRENGTH_POOR = 1; 569 public static final int SIGNAL_STRENGTH_MODERATE = 2; 570 public static final int SIGNAL_STRENGTH_GOOD = 3; 571 public static final int SIGNAL_STRENGTH_GREAT = 4; 572 573 static final String[] SIGNAL_STRENGTH_NAMES = { 574 "none", "poor", "moderate", "good", "great" 575 }; 576 577 public static final int NUM_SIGNAL_STRENGTH_BINS = 5; 578 579 /** 580 * Returns the time in microseconds that the phone has been running with 581 * the given signal strength. 582 * 583 * {@hide} 584 */ 585 public abstract long getPhoneSignalStrengthTime(int strengthBin, 586 long batteryRealtime, int which); 587 588 /** 589 * Returns the time in microseconds that the phone has been trying to 590 * acquire a signal. 591 * 592 * {@hide} 593 */ 594 public abstract long getPhoneSignalScanningTime( 595 long batteryRealtime, int which); 596 597 /** 598 * Returns the number of times the phone has entered the given signal strength. 599 * 600 * {@hide} 601 */ 602 public abstract int getPhoneSignalStrengthCount(int strengthBin, int which); 603 604 public static final int DATA_CONNECTION_NONE = 0; 605 public static final int DATA_CONNECTION_GPRS = 1; 606 public static final int DATA_CONNECTION_EDGE = 2; 607 public static final int DATA_CONNECTION_UMTS = 3; 608 public static final int DATA_CONNECTION_CDMA = 4; 609 public static final int DATA_CONNECTION_EVDO_0 = 5; 610 public static final int DATA_CONNECTION_EVDO_A = 6; 611 public static final int DATA_CONNECTION_1xRTT = 7; 612 public static final int DATA_CONNECTION_HSDPA = 8; 613 public static final int DATA_CONNECTION_HSUPA = 9; 614 public static final int DATA_CONNECTION_HSPA = 10; 615 public static final int DATA_CONNECTION_IDEN = 11; 616 public static final int DATA_CONNECTION_EVDO_B = 12; 617 public static final int DATA_CONNECTION_OTHER = 13; 618 619 static final String[] DATA_CONNECTION_NAMES = { 620 "none", "gprs", "edge", "umts", "cdma", "evdo_0", "evdo_A", 621 "1xrtt", "hsdpa", "hsupa", "hspa", "iden", "evdo_b", "other" 622 }; 623 624 public static final int NUM_DATA_CONNECTION_TYPES = DATA_CONNECTION_OTHER+1; 625 626 /** 627 * Returns the time in microseconds that the phone has been running with 628 * the given data connection. 629 * 630 * {@hide} 631 */ 632 public abstract long getPhoneDataConnectionTime(int dataType, 633 long batteryRealtime, int which); 634 635 /** 636 * Returns the number of times the phone has entered the given data 637 * connection type. 638 * 639 * {@hide} 640 */ 641 public abstract int getPhoneDataConnectionCount(int dataType, int which); 642 643 public static final BitDescription[] HISTORY_STATE_DESCRIPTIONS 644 = new BitDescription[] { 645 new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged"), 646 new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen"), 647 new BitDescription(HistoryItem.STATE_GPS_ON_FLAG, "gps"), 648 new BitDescription(HistoryItem.STATE_PHONE_IN_CALL_FLAG, "phone_in_call"), 649 new BitDescription(HistoryItem.STATE_PHONE_SCANNING_FLAG, "phone_scanning"), 650 new BitDescription(HistoryItem.STATE_WIFI_ON_FLAG, "wifi"), 651 new BitDescription(HistoryItem.STATE_WIFI_RUNNING_FLAG, "wifi_running"), 652 new BitDescription(HistoryItem.STATE_WIFI_FULL_LOCK_FLAG, "wifi_full_lock"), 653 new BitDescription(HistoryItem.STATE_WIFI_SCAN_LOCK_FLAG, "wifi_scan_lock"), 654 new BitDescription(HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG, "wifi_multicast"), 655 new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth"), 656 new BitDescription(HistoryItem.STATE_AUDIO_ON_FLAG, "audio"), 657 new BitDescription(HistoryItem.STATE_VIDEO_ON_FLAG, "video"), 658 new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock"), 659 new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor"), 660 new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK, 661 HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness", 662 SCREEN_BRIGHTNESS_NAMES), 663 new BitDescription(HistoryItem.STATE_SIGNAL_STRENGTH_MASK, 664 HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT, "signal_strength", 665 SIGNAL_STRENGTH_NAMES), 666 new BitDescription(HistoryItem.STATE_PHONE_STATE_MASK, 667 HistoryItem.STATE_PHONE_STATE_SHIFT, "phone_state", 668 new String[] {"in", "out", "emergency", "off"}), 669 new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK, 670 HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", 671 DATA_CONNECTION_NAMES), 672 }; 673 674 /** 675 * Returns the time in microseconds that wifi has been on while the device was 676 * running on battery. 677 * 678 * {@hide} 679 */ 680 public abstract long getWifiOnTime(long batteryRealtime, int which); 681 682 /** 683 * Returns the time in microseconds that wifi has been on and the driver has 684 * been in the running state while the device was running on battery. 685 * 686 * {@hide} 687 */ 688 public abstract long getWifiRunningTime(long batteryRealtime, int which); 689 690 /** 691 * Returns the time in microseconds that bluetooth has been on while the device was 692 * running on battery. 693 * 694 * {@hide} 695 */ 696 public abstract long getBluetoothOnTime(long batteryRealtime, int which); 697 698 /** 699 * Return whether we are currently running on battery. 700 */ 701 public abstract boolean getIsOnBattery(); 702 703 /** 704 * Returns a SparseArray containing the statistics for each uid. 705 */ 706 public abstract SparseArray<? extends Uid> getUidStats(); 707 708 /** 709 * Returns the current battery uptime in microseconds. 710 * 711 * @param curTime the amount of elapsed realtime in microseconds. 712 */ 713 public abstract long getBatteryUptime(long curTime); 714 715 /** 716 * @deprecated use getRadioDataUptime 717 */ 718 public long getRadioDataUptimeMs() { 719 return getRadioDataUptime() / 1000; 720 } 721 722 /** 723 * Returns the time that the radio was on for data transfers. 724 * @return the uptime in microseconds while unplugged 725 */ 726 public abstract long getRadioDataUptime(); 727 728 /** 729 * Returns the current battery realtime in microseconds. 730 * 731 * @param curTime the amount of elapsed realtime in microseconds. 732 */ 733 public abstract long getBatteryRealtime(long curTime); 734 735 /** 736 * Returns the battery percentage level at the last time the device was unplugged from power, or 737 * the last time it booted on battery power. 738 */ 739 public abstract int getDischargeStartLevel(); 740 741 /** 742 * Returns the current battery percentage level if we are in a discharge cycle, otherwise 743 * returns the level at the last plug event. 744 */ 745 public abstract int getDischargeCurrentLevel(); 746 747 /** 748 * Get the amount the battery has discharged since the stats were 749 * last reset after charging, as a lower-end approximation. 750 */ 751 public abstract int getLowDischargeAmountSinceCharge(); 752 753 /** 754 * Get the amount the battery has discharged since the stats were 755 * last reset after charging, as an upper-end approximation. 756 */ 757 public abstract int getHighDischargeAmountSinceCharge(); 758 759 /** 760 * Returns the total, last, or current battery uptime in microseconds. 761 * 762 * @param curTime the elapsed realtime in microseconds. 763 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. 764 */ 765 public abstract long computeBatteryUptime(long curTime, int which); 766 767 /** 768 * Returns the total, last, or current battery realtime in microseconds. 769 * 770 * @param curTime the current elapsed realtime in microseconds. 771 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. 772 */ 773 public abstract long computeBatteryRealtime(long curTime, int which); 774 775 /** 776 * Returns the total, last, or current uptime in microseconds. 777 * 778 * @param curTime the current elapsed realtime in microseconds. 779 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. 780 */ 781 public abstract long computeUptime(long curTime, int which); 782 783 /** 784 * Returns the total, last, or current realtime in microseconds. 785 * * 786 * @param curTime the current elapsed realtime in microseconds. 787 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. 788 */ 789 public abstract long computeRealtime(long curTime, int which); 790 791 public abstract Map<String, ? extends Timer> getKernelWakelockStats(); 792 793 /** Returns the number of different speeds that the CPU can run at */ 794 public abstract int getCpuSpeedSteps(); 795 796 private final static void formatTimeRaw(StringBuilder out, long seconds) { 797 long days = seconds / (60 * 60 * 24); 798 if (days != 0) { 799 out.append(days); 800 out.append("d "); 801 } 802 long used = days * 60 * 60 * 24; 803 804 long hours = (seconds - used) / (60 * 60); 805 if (hours != 0 || used != 0) { 806 out.append(hours); 807 out.append("h "); 808 } 809 used += hours * 60 * 60; 810 811 long mins = (seconds-used) / 60; 812 if (mins != 0 || used != 0) { 813 out.append(mins); 814 out.append("m "); 815 } 816 used += mins * 60; 817 818 if (seconds != 0 || used != 0) { 819 out.append(seconds-used); 820 out.append("s "); 821 } 822 } 823 824 private final static void formatTime(StringBuilder sb, long time) { 825 long sec = time / 100; 826 formatTimeRaw(sb, sec); 827 sb.append((time - (sec * 100)) * 10); 828 sb.append("ms "); 829 } 830 831 private final static void formatTimeMs(StringBuilder sb, long time) { 832 long sec = time / 1000; 833 formatTimeRaw(sb, sec); 834 sb.append(time - (sec * 1000)); 835 sb.append("ms "); 836 } 837 838 private final String formatRatioLocked(long num, long den) { 839 if (den == 0L) { 840 return "---%"; 841 } 842 float perc = ((float)num) / ((float)den) * 100; 843 mFormatBuilder.setLength(0); 844 mFormatter.format("%.1f%%", perc); 845 return mFormatBuilder.toString(); 846 } 847 848 private final String formatBytesLocked(long bytes) { 849 mFormatBuilder.setLength(0); 850 851 if (bytes < BYTES_PER_KB) { 852 return bytes + "B"; 853 } else if (bytes < BYTES_PER_MB) { 854 mFormatter.format("%.2fKB", bytes / (double) BYTES_PER_KB); 855 return mFormatBuilder.toString(); 856 } else if (bytes < BYTES_PER_GB){ 857 mFormatter.format("%.2fMB", bytes / (double) BYTES_PER_MB); 858 return mFormatBuilder.toString(); 859 } else { 860 mFormatter.format("%.2fGB", bytes / (double) BYTES_PER_GB); 861 return mFormatBuilder.toString(); 862 } 863 } 864 865 /** 866 * 867 * @param sb a StringBuilder object. 868 * @param timer a Timer object contining the wakelock times. 869 * @param batteryRealtime the current on-battery time in microseconds. 870 * @param name the name of the wakelock. 871 * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. 872 * @param linePrefix a String to be prepended to each line of output. 873 * @return the line prefix 874 */ 875 private static final String printWakeLock(StringBuilder sb, Timer timer, 876 long batteryRealtime, String name, int which, String linePrefix) { 877 878 if (timer != null) { 879 // Convert from microseconds to milliseconds with rounding 880 long totalTimeMicros = timer.getTotalTimeLocked(batteryRealtime, which); 881 long totalTimeMillis = (totalTimeMicros + 500) / 1000; 882 883 int count = timer.getCountLocked(which); 884 if (totalTimeMillis != 0) { 885 sb.append(linePrefix); 886 formatTimeMs(sb, totalTimeMillis); 887 if (name != null) sb.append(name); 888 sb.append(' '); 889 sb.append('('); 890 sb.append(count); 891 sb.append(" times)"); 892 return ", "; 893 } 894 } 895 return linePrefix; 896 } 897 898 /** 899 * Checkin version of wakelock printer. Prints simple comma-separated list. 900 * 901 * @param sb a StringBuilder object. 902 * @param timer a Timer object contining the wakelock times. 903 * @param now the current time in microseconds. 904 * @param name the name of the wakelock. 905 * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. 906 * @param linePrefix a String to be prepended to each line of output. 907 * @return the line prefix 908 */ 909 private static final String printWakeLockCheckin(StringBuilder sb, Timer timer, long now, 910 String name, int which, String linePrefix) { 911 long totalTimeMicros = 0; 912 int count = 0; 913 if (timer != null) { 914 totalTimeMicros = timer.getTotalTimeLocked(now, which); 915 count = timer.getCountLocked(which); 916 } 917 sb.append(linePrefix); 918 sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding 919 sb.append(','); 920 sb.append(name != null ? name + "," : ""); 921 sb.append(count); 922 return ","; 923 } 924 925 /** 926 * Dump a comma-separated line of values for terse checkin mode. 927 * 928 * @param pw the PageWriter to dump log to 929 * @param category category of data (e.g. "total", "last", "unplugged", "current" ) 930 * @param type type of data (e.g. "wakelock", "sensor", "process", "apk" , "process", "network") 931 * @param args type-dependent data arguments 932 */ 933 private static final void dumpLine(PrintWriter pw, int uid, String category, String type, 934 Object... args ) { 935 pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); 936 pw.print(uid); pw.print(','); 937 pw.print(category); pw.print(','); 938 pw.print(type); 939 940 for (Object arg : args) { 941 pw.print(','); 942 pw.print(arg); 943 } 944 pw.print('\n'); 945 } 946 947 /** 948 * Checkin server version of dump to produce more compact, computer-readable log. 949 * 950 * NOTE: all times are expressed in 'ms'. 951 */ 952 public final void dumpCheckinLocked(PrintWriter pw, int which, int reqUid) { 953 final long rawUptime = SystemClock.uptimeMillis() * 1000; 954 final long rawRealtime = SystemClock.elapsedRealtime() * 1000; 955 final long batteryUptime = getBatteryUptime(rawUptime); 956 final long batteryRealtime = getBatteryRealtime(rawRealtime); 957 final long whichBatteryUptime = computeBatteryUptime(rawUptime, which); 958 final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which); 959 final long totalRealtime = computeRealtime(rawRealtime, which); 960 final long totalUptime = computeUptime(rawUptime, which); 961 final long screenOnTime = getScreenOnTime(batteryRealtime, which); 962 final long phoneOnTime = getPhoneOnTime(batteryRealtime, which); 963 final long wifiOnTime = getWifiOnTime(batteryRealtime, which); 964 final long wifiRunningTime = getWifiRunningTime(batteryRealtime, which); 965 final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which); 966 967 StringBuilder sb = new StringBuilder(128); 968 969 SparseArray<? extends Uid> uidStats = getUidStats(); 970 final int NU = uidStats.size(); 971 972 String category = STAT_NAMES[which]; 973 974 // Dump "battery" stat 975 dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, 976 which == STATS_SINCE_CHARGED ? getStartCount() : "N/A", 977 whichBatteryRealtime / 1000, whichBatteryUptime / 1000, 978 totalRealtime / 1000, totalUptime / 1000); 979 980 // Calculate total network and wakelock times across all uids. 981 long rxTotal = 0; 982 long txTotal = 0; 983 long fullWakeLockTimeTotal = 0; 984 long partialWakeLockTimeTotal = 0; 985 986 for (int iu = 0; iu < NU; iu++) { 987 Uid u = uidStats.valueAt(iu); 988 rxTotal += u.getTcpBytesReceived(which); 989 txTotal += u.getTcpBytesSent(which); 990 991 Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats(); 992 if (wakelocks.size() > 0) { 993 for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent 994 : wakelocks.entrySet()) { 995 Uid.Wakelock wl = ent.getValue(); 996 997 Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL); 998 if (fullWakeTimer != null) { 999 fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(batteryRealtime, which); 1000 } 1001 1002 Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL); 1003 if (partialWakeTimer != null) { 1004 partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked( 1005 batteryRealtime, which); 1006 } 1007 } 1008 } 1009 } 1010 1011 // Dump misc stats 1012 dumpLine(pw, 0 /* uid */, category, MISC_DATA, 1013 screenOnTime / 1000, phoneOnTime / 1000, wifiOnTime / 1000, 1014 wifiRunningTime / 1000, bluetoothOnTime / 1000, rxTotal, txTotal, 1015 fullWakeLockTimeTotal, partialWakeLockTimeTotal, 1016 getInputEventCount(which)); 1017 1018 // Dump screen brightness stats 1019 Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS]; 1020 for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) { 1021 args[i] = getScreenBrightnessTime(i, batteryRealtime, which) / 1000; 1022 } 1023 dumpLine(pw, 0 /* uid */, category, SCREEN_BRIGHTNESS_DATA, args); 1024 1025 // Dump signal strength stats 1026 args = new Object[NUM_SIGNAL_STRENGTH_BINS]; 1027 for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) { 1028 args[i] = getPhoneSignalStrengthTime(i, batteryRealtime, which) / 1000; 1029 } 1030 dumpLine(pw, 0 /* uid */, category, SIGNAL_STRENGTH_TIME_DATA, args); 1031 dumpLine(pw, 0 /* uid */, category, SIGNAL_SCANNING_TIME_DATA, 1032 getPhoneSignalScanningTime(batteryRealtime, which) / 1000); 1033 for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) { 1034 args[i] = getPhoneSignalStrengthCount(i, which); 1035 } 1036 dumpLine(pw, 0 /* uid */, category, SIGNAL_STRENGTH_COUNT_DATA, args); 1037 1038 // Dump network type stats 1039 args = new Object[NUM_DATA_CONNECTION_TYPES]; 1040 for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) { 1041 args[i] = getPhoneDataConnectionTime(i, batteryRealtime, which) / 1000; 1042 } 1043 dumpLine(pw, 0 /* uid */, category, DATA_CONNECTION_TIME_DATA, args); 1044 for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) { 1045 args[i] = getPhoneDataConnectionCount(i, which); 1046 } 1047 dumpLine(pw, 0 /* uid */, category, DATA_CONNECTION_COUNT_DATA, args); 1048 1049 if (which == STATS_SINCE_UNPLUGGED) { 1050 dumpLine(pw, 0 /* uid */, category, BATTERY_LEVEL_DATA, getDischargeStartLevel(), 1051 getDischargeCurrentLevel()); 1052 } 1053 1054 if (reqUid < 0) { 1055 Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats(); 1056 if (kernelWakelocks.size() > 0) { 1057 for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) { 1058 sb.setLength(0); 1059 printWakeLockCheckin(sb, ent.getValue(), batteryRealtime, null, which, ""); 1060 1061 dumpLine(pw, 0 /* uid */, category, KERNEL_WAKELOCK_DATA, ent.getKey(), 1062 sb.toString()); 1063 } 1064 } 1065 } 1066 1067 for (int iu = 0; iu < NU; iu++) { 1068 final int uid = uidStats.keyAt(iu); 1069 if (reqUid >= 0 && uid != reqUid) { 1070 continue; 1071 } 1072 Uid u = uidStats.valueAt(iu); 1073 // Dump Network stats per uid, if any 1074 long rx = u.getTcpBytesReceived(which); 1075 long tx = u.getTcpBytesSent(which); 1076 long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which); 1077 long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which); 1078 long wifiTurnedOnTime = u.getWifiTurnedOnTime(batteryRealtime, which); 1079 1080 if (rx > 0 || tx > 0) dumpLine(pw, uid, category, NETWORK_DATA, rx, tx); 1081 1082 if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0 1083 || wifiTurnedOnTime != 0) { 1084 dumpLine(pw, uid, category, WIFI_LOCK_DATA, 1085 fullWifiLockOnTime, scanWifiLockOnTime, wifiTurnedOnTime); 1086 } 1087 1088 if (u.hasUserActivity()) { 1089 args = new Object[Uid.NUM_USER_ACTIVITY_TYPES]; 1090 boolean hasData = false; 1091 for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) { 1092 int val = u.getUserActivityCount(i, which); 1093 args[i] = val; 1094 if (val != 0) hasData = true; 1095 } 1096 if (hasData) { 1097 dumpLine(pw, 0 /* uid */, category, USER_ACTIVITY_DATA, args); 1098 } 1099 } 1100 1101 Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats(); 1102 if (wakelocks.size() > 0) { 1103 for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent 1104 : wakelocks.entrySet()) { 1105 Uid.Wakelock wl = ent.getValue(); 1106 String linePrefix = ""; 1107 sb.setLength(0); 1108 linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), 1109 batteryRealtime, "f", which, linePrefix); 1110 linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), 1111 batteryRealtime, "p", which, linePrefix); 1112 linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), 1113 batteryRealtime, "w", which, linePrefix); 1114 1115 // Only log if we had at lease one wakelock... 1116 if (sb.length() > 0) { 1117 dumpLine(pw, uid, category, WAKELOCK_DATA, ent.getKey(), sb.toString()); 1118 } 1119 } 1120 } 1121 1122 Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats(); 1123 if (sensors.size() > 0) { 1124 for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent 1125 : sensors.entrySet()) { 1126 Uid.Sensor se = ent.getValue(); 1127 int sensorNumber = ent.getKey(); 1128 Timer timer = se.getSensorTime(); 1129 if (timer != null) { 1130 // Convert from microseconds to milliseconds with rounding 1131 long totalTime = (timer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000; 1132 int count = timer.getCountLocked(which); 1133 if (totalTime != 0) { 1134 dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count); 1135 } 1136 } 1137 } 1138 } 1139 1140 Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); 1141 if (processStats.size() > 0) { 1142 for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent 1143 : processStats.entrySet()) { 1144 Uid.Proc ps = ent.getValue(); 1145 1146 long userTime = ps.getUserTime(which); 1147 long systemTime = ps.getSystemTime(which); 1148 int starts = ps.getStarts(which); 1149 1150 if (userTime != 0 || systemTime != 0 || starts != 0) { 1151 dumpLine(pw, uid, category, PROCESS_DATA, 1152 ent.getKey(), // proc 1153 userTime * 10, // cpu time in ms 1154 systemTime * 10, // user time in ms 1155 starts); // process starts 1156 } 1157 } 1158 } 1159 1160 Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats(); 1161 if (packageStats.size() > 0) { 1162 for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent 1163 : packageStats.entrySet()) { 1164 1165 Uid.Pkg ps = ent.getValue(); 1166 int wakeups = ps.getWakeups(which); 1167 Map<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats(); 1168 for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent 1169 : serviceStats.entrySet()) { 1170 BatteryStats.Uid.Pkg.Serv ss = sent.getValue(); 1171 long startTime = ss.getStartTime(batteryUptime, which); 1172 int starts = ss.getStarts(which); 1173 int launches = ss.getLaunches(which); 1174 if (startTime != 0 || starts != 0 || launches != 0) { 1175 dumpLine(pw, uid, category, APK_DATA, 1176 wakeups, // wakeup alarms 1177 ent.getKey(), // Apk 1178 sent.getKey(), // service 1179 startTime / 1000, // time spent started, in ms 1180 starts, 1181 launches); 1182 } 1183 } 1184 } 1185 } 1186 } 1187 } 1188 1189 @SuppressWarnings("unused") 1190 public final void dumpLocked(PrintWriter pw, String prefix, int which, int reqUid) { 1191 final long rawUptime = SystemClock.uptimeMillis() * 1000; 1192 final long rawRealtime = SystemClock.elapsedRealtime() * 1000; 1193 final long batteryUptime = getBatteryUptime(rawUptime); 1194 final long batteryRealtime = getBatteryRealtime(rawRealtime); 1195 1196 final long whichBatteryUptime = computeBatteryUptime(rawUptime, which); 1197 final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which); 1198 final long totalRealtime = computeRealtime(rawRealtime, which); 1199 final long totalUptime = computeUptime(rawUptime, which); 1200 1201 StringBuilder sb = new StringBuilder(128); 1202 1203 SparseArray<? extends Uid> uidStats = getUidStats(); 1204 final int NU = uidStats.size(); 1205 1206 sb.setLength(0); 1207 sb.append(prefix); 1208 sb.append(" Time on battery: "); 1209 formatTimeMs(sb, whichBatteryRealtime / 1000); sb.append("("); 1210 sb.append(formatRatioLocked(whichBatteryRealtime, totalRealtime)); 1211 sb.append(") realtime, "); 1212 formatTimeMs(sb, whichBatteryUptime / 1000); 1213 sb.append("("); sb.append(formatRatioLocked(whichBatteryUptime, totalRealtime)); 1214 sb.append(") uptime"); 1215 pw.println(sb.toString()); 1216 sb.setLength(0); 1217 sb.append(prefix); 1218 sb.append(" Total run time: "); 1219 formatTimeMs(sb, totalRealtime / 1000); 1220 sb.append("realtime, "); 1221 formatTimeMs(sb, totalUptime / 1000); 1222 sb.append("uptime, "); 1223 pw.println(sb.toString()); 1224 1225 final long screenOnTime = getScreenOnTime(batteryRealtime, which); 1226 final long phoneOnTime = getPhoneOnTime(batteryRealtime, which); 1227 final long wifiRunningTime = getWifiRunningTime(batteryRealtime, which); 1228 final long wifiOnTime = getWifiOnTime(batteryRealtime, which); 1229 final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which); 1230 sb.setLength(0); 1231 sb.append(prefix); 1232 sb.append(" Screen on: "); formatTimeMs(sb, screenOnTime / 1000); 1233 sb.append("("); sb.append(formatRatioLocked(screenOnTime, whichBatteryRealtime)); 1234 sb.append("), Input events: "); sb.append(getInputEventCount(which)); 1235 sb.append(", Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000); 1236 sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime)); 1237 sb.append(")"); 1238 pw.println(sb.toString()); 1239 sb.setLength(0); 1240 sb.append(prefix); 1241 sb.append(" Screen brightnesses: "); 1242 boolean didOne = false; 1243 for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) { 1244 final long time = getScreenBrightnessTime(i, batteryRealtime, which); 1245 if (time == 0) { 1246 continue; 1247 } 1248 if (didOne) sb.append(", "); 1249 didOne = true; 1250 sb.append(SCREEN_BRIGHTNESS_NAMES[i]); 1251 sb.append(" "); 1252 formatTimeMs(sb, time/1000); 1253 sb.append("("); 1254 sb.append(formatRatioLocked(time, screenOnTime)); 1255 sb.append(")"); 1256 } 1257 if (!didOne) sb.append("No activity"); 1258 pw.println(sb.toString()); 1259 1260 // Calculate total network and wakelock times across all uids. 1261 long rxTotal = 0; 1262 long txTotal = 0; 1263 long fullWakeLockTimeTotalMicros = 0; 1264 long partialWakeLockTimeTotalMicros = 0; 1265 1266 if (reqUid < 0) { 1267 Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats(); 1268 if (kernelWakelocks.size() > 0) { 1269 for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) { 1270 1271 String linePrefix = ": "; 1272 sb.setLength(0); 1273 sb.append(prefix); 1274 sb.append(" Kernel Wake lock "); 1275 sb.append(ent.getKey()); 1276 linePrefix = printWakeLock(sb, ent.getValue(), batteryRealtime, null, which, 1277 linePrefix); 1278 if (!linePrefix.equals(": ")) { 1279 sb.append(" realtime"); 1280 // Only print out wake locks that were held 1281 pw.println(sb.toString()); 1282 } 1283 } 1284 } 1285 } 1286 1287 for (int iu = 0; iu < NU; iu++) { 1288 Uid u = uidStats.valueAt(iu); 1289 rxTotal += u.getTcpBytesReceived(which); 1290 txTotal += u.getTcpBytesSent(which); 1291 1292 Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats(); 1293 if (wakelocks.size() > 0) { 1294 for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent 1295 : wakelocks.entrySet()) { 1296 Uid.Wakelock wl = ent.getValue(); 1297 1298 Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL); 1299 if (fullWakeTimer != null) { 1300 fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked( 1301 batteryRealtime, which); 1302 } 1303 1304 Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL); 1305 if (partialWakeTimer != null) { 1306 partialWakeLockTimeTotalMicros += partialWakeTimer.getTotalTimeLocked( 1307 batteryRealtime, which); 1308 } 1309 } 1310 } 1311 } 1312 1313 pw.print(prefix); 1314 pw.print(" Total received: "); pw.print(formatBytesLocked(rxTotal)); 1315 pw.print(", Total sent: "); pw.println(formatBytesLocked(txTotal)); 1316 sb.setLength(0); 1317 sb.append(prefix); 1318 sb.append(" Total full wakelock time: "); formatTimeMs(sb, 1319 (fullWakeLockTimeTotalMicros + 500) / 1000); 1320 sb.append(", Total partial waklock time: "); formatTimeMs(sb, 1321 (partialWakeLockTimeTotalMicros + 500) / 1000); 1322 pw.println(sb.toString()); 1323 1324 sb.setLength(0); 1325 sb.append(prefix); 1326 sb.append(" Signal levels: "); 1327 didOne = false; 1328 for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) { 1329 final long time = getPhoneSignalStrengthTime(i, batteryRealtime, which); 1330 if (time == 0) { 1331 continue; 1332 } 1333 if (didOne) sb.append(", "); 1334 didOne = true; 1335 sb.append(SIGNAL_STRENGTH_NAMES[i]); 1336 sb.append(" "); 1337 formatTimeMs(sb, time/1000); 1338 sb.append("("); 1339 sb.append(formatRatioLocked(time, whichBatteryRealtime)); 1340 sb.append(") "); 1341 sb.append(getPhoneSignalStrengthCount(i, which)); 1342 sb.append("x"); 1343 } 1344 if (!didOne) sb.append("No activity"); 1345 pw.println(sb.toString()); 1346 1347 sb.setLength(0); 1348 sb.append(prefix); 1349 sb.append(" Signal scanning time: "); 1350 formatTimeMs(sb, getPhoneSignalScanningTime(batteryRealtime, which) / 1000); 1351 pw.println(sb.toString()); 1352 1353 sb.setLength(0); 1354 sb.append(prefix); 1355 sb.append(" Radio types: "); 1356 didOne = false; 1357 for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) { 1358 final long time = getPhoneDataConnectionTime(i, batteryRealtime, which); 1359 if (time == 0) { 1360 continue; 1361 } 1362 if (didOne) sb.append(", "); 1363 didOne = true; 1364 sb.append(DATA_CONNECTION_NAMES[i]); 1365 sb.append(" "); 1366 formatTimeMs(sb, time/1000); 1367 sb.append("("); 1368 sb.append(formatRatioLocked(time, whichBatteryRealtime)); 1369 sb.append(") "); 1370 sb.append(getPhoneDataConnectionCount(i, which)); 1371 sb.append("x"); 1372 } 1373 if (!didOne) sb.append("No activity"); 1374 pw.println(sb.toString()); 1375 1376 sb.setLength(0); 1377 sb.append(prefix); 1378 sb.append(" Radio data uptime when unplugged: "); 1379 sb.append(getRadioDataUptime() / 1000); 1380 sb.append(" ms"); 1381 pw.println(sb.toString()); 1382 1383 sb.setLength(0); 1384 sb.append(prefix); 1385 sb.append(" Wifi on: "); formatTimeMs(sb, wifiOnTime / 1000); 1386 sb.append("("); sb.append(formatRatioLocked(wifiOnTime, whichBatteryRealtime)); 1387 sb.append("), Wifi running: "); formatTimeMs(sb, wifiRunningTime / 1000); 1388 sb.append("("); sb.append(formatRatioLocked(wifiRunningTime, whichBatteryRealtime)); 1389 sb.append("), Bluetooth on: "); formatTimeMs(sb, bluetoothOnTime / 1000); 1390 sb.append("("); sb.append(formatRatioLocked(bluetoothOnTime, whichBatteryRealtime)); 1391 sb.append(")"); 1392 pw.println(sb.toString()); 1393 1394 pw.println(" "); 1395 1396 if (which == STATS_SINCE_UNPLUGGED) { 1397 if (getIsOnBattery()) { 1398 pw.print(prefix); pw.println(" Device is currently unplugged"); 1399 pw.print(prefix); pw.print(" Discharge cycle start level: "); 1400 pw.println(getDischargeStartLevel()); 1401 pw.print(prefix); pw.print(" Discharge cycle current level: "); 1402 pw.println(getDischargeCurrentLevel()); 1403 } else { 1404 pw.print(prefix); pw.println(" Device is currently plugged into power"); 1405 pw.print(prefix); pw.print(" Last discharge cycle start level: "); 1406 pw.println(getDischargeStartLevel()); 1407 pw.print(prefix); pw.print(" Last discharge cycle end level: "); 1408 pw.println(getDischargeCurrentLevel()); 1409 } 1410 pw.println(" "); 1411 } else { 1412 pw.print(prefix); pw.println(" Device battery use since last full charge"); 1413 pw.print(prefix); pw.print(" Amount discharged (lower bound): "); 1414 pw.println(getLowDischargeAmountSinceCharge()); 1415 pw.print(prefix); pw.print(" Amount discharged (upper bound): "); 1416 pw.println(getHighDischargeAmountSinceCharge()); 1417 pw.println(" "); 1418 } 1419 1420 1421 for (int iu=0; iu<NU; iu++) { 1422 final int uid = uidStats.keyAt(iu); 1423 if (reqUid >= 0 && uid != reqUid) { 1424 continue; 1425 } 1426 1427 Uid u = uidStats.valueAt(iu); 1428 1429 pw.println(prefix + " #" + uid + ":"); 1430 boolean uidActivity = false; 1431 1432 long tcpReceived = u.getTcpBytesReceived(which); 1433 long tcpSent = u.getTcpBytesSent(which); 1434 long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which); 1435 long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which); 1436 long wifiTurnedOnTime = u.getWifiTurnedOnTime(batteryRealtime, which); 1437 1438 if (tcpReceived != 0 || tcpSent != 0) { 1439 pw.print(prefix); pw.print(" Network: "); 1440 pw.print(formatBytesLocked(tcpReceived)); pw.print(" received, "); 1441 pw.print(formatBytesLocked(tcpSent)); pw.println(" sent"); 1442 } 1443 1444 if (u.hasUserActivity()) { 1445 boolean hasData = false; 1446 for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) { 1447 int val = u.getUserActivityCount(i, which); 1448 if (val != 0) { 1449 if (!hasData) { 1450 sb.setLength(0); 1451 sb.append(" User activity: "); 1452 hasData = true; 1453 } else { 1454 sb.append(", "); 1455 } 1456 sb.append(val); 1457 sb.append(" "); 1458 sb.append(Uid.USER_ACTIVITY_TYPES[i]); 1459 } 1460 } 1461 if (hasData) { 1462 pw.println(sb.toString()); 1463 } 1464 } 1465 1466 if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0 1467 || wifiTurnedOnTime != 0) { 1468 sb.setLength(0); 1469 sb.append(prefix); sb.append(" Turned Wifi On: "); 1470 formatTimeMs(sb, wifiTurnedOnTime / 1000); 1471 sb.append("("); sb.append(formatRatioLocked(wifiTurnedOnTime, 1472 whichBatteryRealtime)); sb.append(")\n"); 1473 sb.append(prefix); sb.append(" Full Wifi Lock: "); 1474 formatTimeMs(sb, fullWifiLockOnTime / 1000); 1475 sb.append("("); sb.append(formatRatioLocked(fullWifiLockOnTime, 1476 whichBatteryRealtime)); sb.append(")\n"); 1477 sb.append(prefix); sb.append(" Scan Wifi Lock: "); 1478 formatTimeMs(sb, scanWifiLockOnTime / 1000); 1479 sb.append("("); sb.append(formatRatioLocked(scanWifiLockOnTime, 1480 whichBatteryRealtime)); sb.append(")"); 1481 pw.println(sb.toString()); 1482 } 1483 1484 Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats(); 1485 if (wakelocks.size() > 0) { 1486 for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent 1487 : wakelocks.entrySet()) { 1488 Uid.Wakelock wl = ent.getValue(); 1489 String linePrefix = ": "; 1490 sb.setLength(0); 1491 sb.append(prefix); 1492 sb.append(" Wake lock "); 1493 sb.append(ent.getKey()); 1494 linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime, 1495 "full", which, linePrefix); 1496 linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime, 1497 "partial", which, linePrefix); 1498 linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime, 1499 "window", which, linePrefix); 1500 if (!linePrefix.equals(": ")) { 1501 sb.append(" realtime"); 1502 // Only print out wake locks that were held 1503 pw.println(sb.toString()); 1504 uidActivity = true; 1505 } 1506 } 1507 } 1508 1509 Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats(); 1510 if (sensors.size() > 0) { 1511 for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent 1512 : sensors.entrySet()) { 1513 Uid.Sensor se = ent.getValue(); 1514 int sensorNumber = ent.getKey(); 1515 sb.setLength(0); 1516 sb.append(prefix); 1517 sb.append(" Sensor "); 1518 int handle = se.getHandle(); 1519 if (handle == Uid.Sensor.GPS) { 1520 sb.append("GPS"); 1521 } else { 1522 sb.append(handle); 1523 } 1524 sb.append(": "); 1525 1526 Timer timer = se.getSensorTime(); 1527 if (timer != null) { 1528 // Convert from microseconds to milliseconds with rounding 1529 long totalTime = (timer.getTotalTimeLocked( 1530 batteryRealtime, which) + 500) / 1000; 1531 int count = timer.getCountLocked(which); 1532 //timer.logState(); 1533 if (totalTime != 0) { 1534 formatTimeMs(sb, totalTime); 1535 sb.append("realtime ("); 1536 sb.append(count); 1537 sb.append(" times)"); 1538 } else { 1539 sb.append("(not used)"); 1540 } 1541 } else { 1542 sb.append("(not used)"); 1543 } 1544 1545 pw.println(sb.toString()); 1546 uidActivity = true; 1547 } 1548 } 1549 1550 Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); 1551 if (processStats.size() > 0) { 1552 for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent 1553 : processStats.entrySet()) { 1554 Uid.Proc ps = ent.getValue(); 1555 long userTime; 1556 long systemTime; 1557 int starts; 1558 int numExcessive; 1559 1560 userTime = ps.getUserTime(which); 1561 systemTime = ps.getSystemTime(which); 1562 starts = ps.getStarts(which); 1563 numExcessive = which == STATS_SINCE_CHARGED 1564 ? ps.countExcessiveWakes() : 0; 1565 1566 if (userTime != 0 || systemTime != 0 || starts != 0 1567 || numExcessive != 0) { 1568 sb.setLength(0); 1569 sb.append(prefix); sb.append(" Proc "); 1570 sb.append(ent.getKey()); sb.append(":\n"); 1571 sb.append(prefix); sb.append(" CPU: "); 1572 formatTime(sb, userTime); sb.append("usr + "); 1573 formatTime(sb, systemTime); sb.append("krn\n"); 1574 sb.append(prefix); sb.append(" "); sb.append(starts); 1575 sb.append(" proc starts"); 1576 pw.println(sb.toString()); 1577 for (int e=0; e<numExcessive; e++) { 1578 Uid.Proc.ExcessiveWake ew = ps.getExcessiveWake(e); 1579 if (ew != null) { 1580 pw.print(prefix); pw.print(" * Killed for wake lock use: "); 1581 TimeUtils.formatDuration(ew.usedTime, pw); 1582 pw.print(" over "); 1583 TimeUtils.formatDuration(ew.overTime, pw); 1584 pw.print(" ("); 1585 pw.print((ew.usedTime*100)/ew.overTime); 1586 pw.println("%)"); 1587 } 1588 } 1589 uidActivity = true; 1590 } 1591 } 1592 } 1593 1594 Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats(); 1595 if (packageStats.size() > 0) { 1596 for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent 1597 : packageStats.entrySet()) { 1598 pw.print(prefix); pw.print(" Apk "); pw.print(ent.getKey()); pw.println(":"); 1599 boolean apkActivity = false; 1600 Uid.Pkg ps = ent.getValue(); 1601 int wakeups = ps.getWakeups(which); 1602 if (wakeups != 0) { 1603 pw.print(prefix); pw.print(" "); 1604 pw.print(wakeups); pw.println(" wakeup alarms"); 1605 apkActivity = true; 1606 } 1607 Map<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats(); 1608 if (serviceStats.size() > 0) { 1609 for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent 1610 : serviceStats.entrySet()) { 1611 BatteryStats.Uid.Pkg.Serv ss = sent.getValue(); 1612 long startTime = ss.getStartTime(batteryUptime, which); 1613 int starts = ss.getStarts(which); 1614 int launches = ss.getLaunches(which); 1615 if (startTime != 0 || starts != 0 || launches != 0) { 1616 sb.setLength(0); 1617 sb.append(prefix); sb.append(" Service "); 1618 sb.append(sent.getKey()); sb.append(":\n"); 1619 sb.append(prefix); sb.append(" Created for: "); 1620 formatTimeMs(sb, startTime / 1000); 1621 sb.append(" uptime\n"); 1622 sb.append(prefix); sb.append(" Starts: "); 1623 sb.append(starts); 1624 sb.append(", launches: "); sb.append(launches); 1625 pw.println(sb.toString()); 1626 apkActivity = true; 1627 } 1628 } 1629 } 1630 if (!apkActivity) { 1631 pw.print(prefix); pw.println(" (nothing executed)"); 1632 } 1633 uidActivity = true; 1634 } 1635 } 1636 if (!uidActivity) { 1637 pw.print(prefix); pw.println(" (nothing executed)"); 1638 } 1639 } 1640 } 1641 1642 void printBitDescriptions(PrintWriter pw, int oldval, int newval, BitDescription[] descriptions) { 1643 int diff = oldval ^ newval; 1644 if (diff == 0) return; 1645 for (int i=0; i<descriptions.length; i++) { 1646 BitDescription bd = descriptions[i]; 1647 if ((diff&bd.mask) != 0) { 1648 if (bd.shift < 0) { 1649 pw.print((newval&bd.mask) != 0 ? " +" : " -"); 1650 pw.print(bd.name); 1651 } else { 1652 pw.print(" "); 1653 pw.print(bd.name); 1654 pw.print("="); 1655 int val = (newval&bd.mask)>>bd.shift; 1656 if (bd.values != null && val >= 0 && val < bd.values.length) { 1657 pw.print(bd.values[val]); 1658 } else { 1659 pw.print(val); 1660 } 1661 } 1662 } 1663 } 1664 } 1665 1666 /** 1667 * Dumps a human-readable summary of the battery statistics to the given PrintWriter. 1668 * 1669 * @param pw a Printer to receive the dump output. 1670 */ 1671 @SuppressWarnings("unused") 1672 public void dumpLocked(PrintWriter pw) { 1673 HistoryItem rec = getHistory(); 1674 if (rec != null) { 1675 pw.println("Battery History:"); 1676 int oldState = 0; 1677 int oldStatus = -1; 1678 int oldHealth = -1; 1679 int oldPlug = -1; 1680 int oldTemp = -1; 1681 int oldVolt = -1; 1682 while (rec != null) { 1683 pw.print(" "); 1684 pw.print(rec.time); 1685 pw.print(" "); 1686 if (rec.cmd == HistoryItem.CMD_START) { 1687 pw.println(" START"); 1688 } else { 1689 if (rec.batteryLevel < 10) pw.print("00"); 1690 else if (rec.batteryLevel < 100) pw.print("0"); 1691 pw.print(rec.batteryLevel); 1692 pw.print(" "); 1693 if (rec.states < 0x10) pw.print("0000000"); 1694 else if (rec.states < 0x100) pw.print("000000"); 1695 else if (rec.states < 0x1000) pw.print("00000"); 1696 else if (rec.states < 0x10000) pw.print("0000"); 1697 else if (rec.states < 0x100000) pw.print("000"); 1698 else if (rec.states < 0x1000000) pw.print("00"); 1699 else if (rec.states < 0x10000000) pw.print("0"); 1700 pw.print(Integer.toHexString(rec.states)); 1701 if (oldStatus != rec.batteryStatus) { 1702 oldStatus = rec.batteryStatus; 1703 pw.print(" status="); 1704 switch (oldStatus) { 1705 case BatteryManager.BATTERY_STATUS_UNKNOWN: 1706 pw.print("unknown"); 1707 break; 1708 case BatteryManager.BATTERY_STATUS_CHARGING: 1709 pw.print("charging"); 1710 break; 1711 case BatteryManager.BATTERY_STATUS_DISCHARGING: 1712 pw.print("discharging"); 1713 break; 1714 case BatteryManager.BATTERY_STATUS_NOT_CHARGING: 1715 pw.print("not-charging"); 1716 break; 1717 case BatteryManager.BATTERY_STATUS_FULL: 1718 pw.print("full"); 1719 break; 1720 default: 1721 pw.print(oldStatus); 1722 break; 1723 } 1724 } 1725 if (oldHealth != rec.batteryHealth) { 1726 oldHealth = rec.batteryHealth; 1727 pw.print(" health="); 1728 switch (oldHealth) { 1729 case BatteryManager.BATTERY_HEALTH_UNKNOWN: 1730 pw.print("unknown"); 1731 break; 1732 case BatteryManager.BATTERY_HEALTH_GOOD: 1733 pw.print("good"); 1734 break; 1735 case BatteryManager.BATTERY_HEALTH_OVERHEAT: 1736 pw.print("overheat"); 1737 break; 1738 case BatteryManager.BATTERY_HEALTH_DEAD: 1739 pw.print("dead"); 1740 break; 1741 case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE: 1742 pw.print("over-voltage"); 1743 break; 1744 case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE: 1745 pw.print("failure"); 1746 break; 1747 default: 1748 pw.print(oldHealth); 1749 break; 1750 } 1751 } 1752 if (oldPlug != rec.batteryPlugType) { 1753 oldPlug = rec.batteryPlugType; 1754 pw.print(" plug="); 1755 switch (oldPlug) { 1756 case 0: 1757 pw.print("none"); 1758 break; 1759 case BatteryManager.BATTERY_PLUGGED_AC: 1760 pw.print("ac"); 1761 break; 1762 case BatteryManager.BATTERY_PLUGGED_USB: 1763 pw.print("usb"); 1764 break; 1765 default: 1766 pw.print(oldPlug); 1767 break; 1768 } 1769 } 1770 if (oldTemp != rec.batteryTemperature) { 1771 oldTemp = rec.batteryTemperature; 1772 pw.print(" temp="); 1773 pw.print(oldTemp); 1774 } 1775 if (oldVolt != rec.batteryVoltage) { 1776 oldVolt = rec.batteryVoltage; 1777 pw.print(" volt="); 1778 pw.print(oldVolt); 1779 } 1780 printBitDescriptions(pw, oldState, rec.states, 1781 HISTORY_STATE_DESCRIPTIONS); 1782 pw.println(); 1783 } 1784 oldState = rec.states; 1785 rec = rec.next; 1786 } 1787 } 1788 1789 pw.println("Statistics since last charge:"); 1790 pw.println(" System starts: " + getStartCount() 1791 + ", currently on battery: " + getIsOnBattery()); 1792 dumpLocked(pw, "", STATS_SINCE_CHARGED, -1); 1793 pw.println(""); 1794 pw.println("Statistics since last unplugged:"); 1795 dumpLocked(pw, "", STATS_SINCE_UNPLUGGED, -1); 1796 } 1797 1798 @SuppressWarnings("unused") 1799 public void dumpCheckinLocked(PrintWriter pw, String[] args) { 1800 boolean isUnpluggedOnly = false; 1801 1802 for (String arg : args) { 1803 if ("-u".equals(arg)) { 1804 if (LOCAL_LOGV) Log.v("BatteryStats", "Dumping unplugged data"); 1805 isUnpluggedOnly = true; 1806 } 1807 } 1808 1809 if (isUnpluggedOnly) { 1810 dumpCheckinLocked(pw, STATS_SINCE_UNPLUGGED, -1); 1811 } 1812 else { 1813 dumpCheckinLocked(pw, STATS_SINCE_CHARGED, -1); 1814 dumpCheckinLocked(pw, STATS_SINCE_UNPLUGGED, -1); 1815 } 1816 } 1817} 1818