BatteryStatsService.java revision 1e38382b542f5cef9957a89692b02c55a3dd351c
1/* 2 * Copyright (C) 2006-2007 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 com.android.server.am; 18 19import android.bluetooth.BluetoothActivityEnergyInfo; 20import android.bluetooth.BluetoothAdapter; 21import android.bluetooth.BluetoothHeadset; 22import android.bluetooth.BluetoothProfile; 23import android.content.Context; 24import android.content.pm.ApplicationInfo; 25import android.content.pm.PackageManager; 26import android.net.wifi.IWifiManager; 27import android.net.wifi.WifiActivityEnergyInfo; 28import android.os.BatteryStats; 29import android.os.Binder; 30import android.os.Handler; 31import android.os.IBinder; 32import android.os.Looper; 33import android.os.Message; 34import android.os.Parcel; 35import android.os.ParcelFileDescriptor; 36import android.os.PowerManagerInternal; 37import android.os.Process; 38import android.os.RemoteException; 39import android.os.ServiceManager; 40import android.os.SystemClock; 41import android.os.UserHandle; 42import android.os.WorkSource; 43import android.telephony.DataConnectionRealTimeInfo; 44import android.telephony.SignalStrength; 45import android.telephony.TelephonyManager; 46import android.util.Slog; 47 48import com.android.internal.annotations.GuardedBy; 49import com.android.internal.app.IBatteryStats; 50import com.android.internal.os.BatteryStatsHelper; 51import com.android.internal.os.BatteryStatsImpl; 52import com.android.internal.os.PowerProfile; 53import com.android.server.FgThread; 54import com.android.server.LocalServices; 55 56import java.io.File; 57import java.io.FileDescriptor; 58import java.io.IOException; 59import java.io.PrintWriter; 60import java.util.List; 61 62/** 63 * All information we are collecting about things that can happen that impact 64 * battery life. 65 */ 66public final class BatteryStatsService extends IBatteryStats.Stub 67 implements PowerManagerInternal.LowPowerModeListener { 68 static final String TAG = "BatteryStatsService"; 69 70 static IBatteryStats sService; 71 final BatteryStatsImpl mStats; 72 final BatteryStatsHandler mHandler; 73 Context mContext; 74 private boolean mBluetoothPendingStats; 75 private BluetoothHeadset mBluetoothHeadset; 76 PowerManagerInternal mPowerManagerInternal; 77 78 class BatteryStatsHandler extends Handler implements BatteryStatsImpl.ExternalStatsSync { 79 public static final int MSG_SYNC_EXTERNAL_STATS = 1; 80 public static final int MSG_WRITE_TO_DISK = 2; 81 82 public BatteryStatsHandler(Looper looper) { 83 super(looper); 84 } 85 86 @Override 87 public void handleMessage(Message msg) { 88 switch (msg.what) { 89 case MSG_SYNC_EXTERNAL_STATS: 90 updateExternalStats(); 91 break; 92 93 case MSG_WRITE_TO_DISK: 94 updateExternalStats(); 95 synchronized (mStats) { 96 mStats.writeAsyncLocked(); 97 } 98 break; 99 } 100 } 101 102 @Override 103 public void scheduleSync() { 104 if (!hasMessages(MSG_SYNC_EXTERNAL_STATS)) { 105 sendEmptyMessage(MSG_SYNC_EXTERNAL_STATS); 106 } 107 } 108 } 109 110 BatteryStatsService(File systemDir, Handler handler) { 111 // Our handler here will be accessing the disk, use a different thread than 112 // what the ActivityManagerService gave us (no I/O on that one!). 113 mHandler = new BatteryStatsHandler(FgThread.getHandler().getLooper()); 114 115 // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through. 116 mStats = new BatteryStatsImpl(systemDir, handler, mHandler); 117 } 118 119 public void publish(Context context) { 120 mContext = context; 121 ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder()); 122 mStats.setNumSpeedSteps(new PowerProfile(mContext).getNumSpeedSteps()); 123 mStats.setRadioScanningTimeout(mContext.getResources().getInteger( 124 com.android.internal.R.integer.config_radioScanningTimeout) 125 * 1000L); 126 mStats.setPowerProfile(new PowerProfile(context)); 127 } 128 129 /** 130 * At the time when the constructor runs, the power manager has not yet been 131 * initialized. So we initialize the low power observer later. 132 */ 133 public void initPowerManagement() { 134 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class); 135 mPowerManagerInternal.registerLowPowerModeObserver(this); 136 mStats.notePowerSaveMode(mPowerManagerInternal.getLowPowerModeEnabled()); 137 (new WakeupReasonThread()).start(); 138 } 139 140 public void shutdown() { 141 Slog.w("BatteryStats", "Writing battery stats before shutdown..."); 142 143 updateExternalStats(); 144 synchronized (mStats) { 145 mStats.shutdownLocked(); 146 } 147 } 148 149 public static IBatteryStats getService() { 150 if (sService != null) { 151 return sService; 152 } 153 IBinder b = ServiceManager.getService(BatteryStats.SERVICE_NAME); 154 sService = asInterface(b); 155 return sService; 156 } 157 158 @Override 159 public void onLowPowerModeChanged(boolean enabled) { 160 synchronized (mStats) { 161 mStats.notePowerSaveMode(enabled); 162 } 163 } 164 165 /** 166 * @return the current statistics object, which may be modified 167 * to reflect events that affect battery usage. You must lock the 168 * stats object before doing anything with it. 169 */ 170 public BatteryStatsImpl getActiveStatistics() { 171 return mStats; 172 } 173 174 /** 175 * Schedules a write to disk to occur. This will cause the BatteryStatsImpl 176 * object to update with the latest info, then write to disk. 177 */ 178 public void scheduleWriteToDisk() { 179 mHandler.sendEmptyMessage(BatteryStatsHandler.MSG_WRITE_TO_DISK); 180 } 181 182 // These are for direct use by the activity manager... 183 184 void addIsolatedUid(int isolatedUid, int appUid) { 185 synchronized (mStats) { 186 mStats.addIsolatedUidLocked(isolatedUid, appUid); 187 } 188 } 189 190 void removeIsolatedUid(int isolatedUid, int appUid) { 191 synchronized (mStats) { 192 mStats.removeIsolatedUidLocked(isolatedUid, appUid); 193 } 194 } 195 196 void noteProcessStart(String name, int uid) { 197 synchronized (mStats) { 198 mStats.noteProcessStartLocked(name, uid); 199 } 200 } 201 202 void noteProcessCrash(String name, int uid) { 203 synchronized (mStats) { 204 mStats.noteProcessCrashLocked(name, uid); 205 } 206 } 207 208 void noteProcessAnr(String name, int uid) { 209 synchronized (mStats) { 210 mStats.noteProcessAnrLocked(name, uid); 211 } 212 } 213 214 void noteProcessState(String name, int uid, int state) { 215 synchronized (mStats) { 216 mStats.noteProcessStateLocked(name, uid, state); 217 } 218 } 219 220 void noteProcessFinish(String name, int uid) { 221 synchronized (mStats) { 222 mStats.noteProcessFinishLocked(name, uid); 223 } 224 } 225 226 // Public interface... 227 228 public byte[] getStatistics() { 229 mContext.enforceCallingPermission( 230 android.Manifest.permission.BATTERY_STATS, null); 231 //Slog.i("foo", "SENDING BATTERY INFO:"); 232 //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM)); 233 Parcel out = Parcel.obtain(); 234 updateExternalStats(); 235 synchronized (mStats) { 236 mStats.writeToParcel(out, 0); 237 } 238 byte[] data = out.marshall(); 239 out.recycle(); 240 return data; 241 } 242 243 public ParcelFileDescriptor getStatisticsStream() { 244 mContext.enforceCallingPermission( 245 android.Manifest.permission.BATTERY_STATS, null); 246 //Slog.i("foo", "SENDING BATTERY INFO:"); 247 //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM)); 248 Parcel out = Parcel.obtain(); 249 updateExternalStats(); 250 synchronized (mStats) { 251 mStats.writeToParcel(out, 0); 252 } 253 byte[] data = out.marshall(); 254 out.recycle(); 255 try { 256 return ParcelFileDescriptor.fromData(data, "battery-stats"); 257 } catch (IOException e) { 258 Slog.w(TAG, "Unable to create shared memory", e); 259 return null; 260 } 261 } 262 263 public boolean isCharging() { 264 synchronized (mStats) { 265 return mStats.isCharging(); 266 } 267 } 268 269 public long computeBatteryTimeRemaining() { 270 synchronized (mStats) { 271 long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime()); 272 return time >= 0 ? (time/1000) : time; 273 } 274 } 275 276 public long computeChargeTimeRemaining() { 277 synchronized (mStats) { 278 long time = mStats.computeChargeTimeRemaining(SystemClock.elapsedRealtime()); 279 return time >= 0 ? (time/1000) : time; 280 } 281 } 282 283 public void noteEvent(int code, String name, int uid) { 284 enforceCallingPermission(); 285 synchronized (mStats) { 286 mStats.noteEventLocked(code, name, uid); 287 } 288 } 289 290 public void noteSyncStart(String name, int uid) { 291 enforceCallingPermission(); 292 synchronized (mStats) { 293 mStats.noteSyncStartLocked(name, uid); 294 } 295 } 296 297 public void noteSyncFinish(String name, int uid) { 298 enforceCallingPermission(); 299 synchronized (mStats) { 300 mStats.noteSyncFinishLocked(name, uid); 301 } 302 } 303 304 public void noteJobStart(String name, int uid) { 305 enforceCallingPermission(); 306 synchronized (mStats) { 307 mStats.noteJobStartLocked(name, uid); 308 } 309 } 310 311 public void noteJobFinish(String name, int uid) { 312 enforceCallingPermission(); 313 synchronized (mStats) { 314 mStats.noteJobFinishLocked(name, uid); 315 } 316 } 317 318 public void noteAlarmStart(String name, int uid) { 319 enforceCallingPermission(); 320 synchronized (mStats) { 321 mStats.noteAlarmStartLocked(name, uid); 322 } 323 } 324 325 public void noteAlarmFinish(String name, int uid) { 326 enforceCallingPermission(); 327 synchronized (mStats) { 328 mStats.noteAlarmFinishLocked(name, uid); 329 } 330 } 331 332 public void noteStartWakelock(int uid, int pid, String name, String historyName, int type, 333 boolean unimportantForLogging) { 334 enforceCallingPermission(); 335 synchronized (mStats) { 336 mStats.noteStartWakeLocked(uid, pid, name, historyName, type, unimportantForLogging, 337 SystemClock.elapsedRealtime(), SystemClock.uptimeMillis()); 338 } 339 } 340 341 public void noteStopWakelock(int uid, int pid, String name, String historyName, int type) { 342 enforceCallingPermission(); 343 synchronized (mStats) { 344 mStats.noteStopWakeLocked(uid, pid, name, historyName, type, 345 SystemClock.elapsedRealtime(), SystemClock.uptimeMillis()); 346 } 347 } 348 349 public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, 350 String historyName, int type, boolean unimportantForLogging) { 351 enforceCallingPermission(); 352 synchronized (mStats) { 353 mStats.noteStartWakeFromSourceLocked(ws, pid, name, historyName, 354 type, unimportantForLogging); 355 } 356 } 357 358 public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name, 359 String historyName, int type, WorkSource newWs, int newPid, String newName, 360 String newHistoryName, int newType, boolean newUnimportantForLogging) { 361 enforceCallingPermission(); 362 synchronized (mStats) { 363 mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, historyName, type, 364 newWs, newPid, newName, newHistoryName, newType, newUnimportantForLogging); 365 } 366 } 367 368 public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, String historyName, 369 int type) { 370 enforceCallingPermission(); 371 synchronized (mStats) { 372 mStats.noteStopWakeFromSourceLocked(ws, pid, name, historyName, type); 373 } 374 } 375 376 public void noteStartSensor(int uid, int sensor) { 377 enforceCallingPermission(); 378 synchronized (mStats) { 379 mStats.noteStartSensorLocked(uid, sensor); 380 } 381 } 382 383 public void noteStopSensor(int uid, int sensor) { 384 enforceCallingPermission(); 385 synchronized (mStats) { 386 mStats.noteStopSensorLocked(uid, sensor); 387 } 388 } 389 390 public void noteVibratorOn(int uid, long durationMillis) { 391 enforceCallingPermission(); 392 synchronized (mStats) { 393 mStats.noteVibratorOnLocked(uid, durationMillis); 394 } 395 } 396 397 public void noteVibratorOff(int uid) { 398 enforceCallingPermission(); 399 synchronized (mStats) { 400 mStats.noteVibratorOffLocked(uid); 401 } 402 } 403 404 public void noteStartGps(int uid) { 405 enforceCallingPermission(); 406 synchronized (mStats) { 407 mStats.noteStartGpsLocked(uid); 408 } 409 } 410 411 public void noteStopGps(int uid) { 412 enforceCallingPermission(); 413 synchronized (mStats) { 414 mStats.noteStopGpsLocked(uid); 415 } 416 } 417 418 public void noteScreenState(int state) { 419 enforceCallingPermission(); 420 synchronized (mStats) { 421 mStats.noteScreenStateLocked(state); 422 } 423 } 424 425 public void noteScreenBrightness(int brightness) { 426 enforceCallingPermission(); 427 synchronized (mStats) { 428 mStats.noteScreenBrightnessLocked(brightness); 429 } 430 } 431 432 public void noteUserActivity(int uid, int event) { 433 enforceCallingPermission(); 434 synchronized (mStats) { 435 mStats.noteUserActivityLocked(uid, event); 436 } 437 } 438 439 public void noteInteractive(boolean interactive) { 440 enforceCallingPermission(); 441 synchronized (mStats) { 442 mStats.noteInteractiveLocked(interactive); 443 } 444 } 445 446 public void noteConnectivityChanged(int type, String extra) { 447 enforceCallingPermission(); 448 synchronized (mStats) { 449 mStats.noteConnectivityChangedLocked(type, extra); 450 } 451 } 452 453 public void noteMobileRadioPowerState(int powerState, long timestampNs) { 454 enforceCallingPermission(); 455 synchronized (mStats) { 456 mStats.noteMobileRadioPowerState(powerState, timestampNs); 457 } 458 } 459 460 public void notePhoneOn() { 461 enforceCallingPermission(); 462 synchronized (mStats) { 463 mStats.notePhoneOnLocked(); 464 } 465 } 466 467 public void notePhoneOff() { 468 enforceCallingPermission(); 469 synchronized (mStats) { 470 mStats.notePhoneOffLocked(); 471 } 472 } 473 474 public void notePhoneSignalStrength(SignalStrength signalStrength) { 475 enforceCallingPermission(); 476 synchronized (mStats) { 477 mStats.notePhoneSignalStrengthLocked(signalStrength); 478 } 479 } 480 481 public void notePhoneDataConnectionState(int dataType, boolean hasData) { 482 enforceCallingPermission(); 483 synchronized (mStats) { 484 mStats.notePhoneDataConnectionStateLocked(dataType, hasData); 485 } 486 } 487 488 public void notePhoneState(int state) { 489 enforceCallingPermission(); 490 int simState = TelephonyManager.getDefault().getSimState(); 491 synchronized (mStats) { 492 mStats.notePhoneStateLocked(state, simState); 493 } 494 } 495 496 public void noteWifiOn() { 497 enforceCallingPermission(); 498 synchronized (mStats) { 499 mStats.noteWifiOnLocked(); 500 } 501 } 502 503 public void noteWifiOff() { 504 enforceCallingPermission(); 505 synchronized (mStats) { 506 mStats.noteWifiOffLocked(); 507 } 508 } 509 510 public void noteStartAudio(int uid) { 511 enforceCallingPermission(); 512 synchronized (mStats) { 513 mStats.noteAudioOnLocked(uid); 514 } 515 } 516 517 public void noteStopAudio(int uid) { 518 enforceCallingPermission(); 519 synchronized (mStats) { 520 mStats.noteAudioOffLocked(uid); 521 } 522 } 523 524 public void noteStartVideo(int uid) { 525 enforceCallingPermission(); 526 synchronized (mStats) { 527 mStats.noteVideoOnLocked(uid); 528 } 529 } 530 531 public void noteStopVideo(int uid) { 532 enforceCallingPermission(); 533 synchronized (mStats) { 534 mStats.noteVideoOffLocked(uid); 535 } 536 } 537 538 public void noteResetAudio() { 539 enforceCallingPermission(); 540 synchronized (mStats) { 541 mStats.noteResetAudioLocked(); 542 } 543 } 544 545 public void noteResetVideo() { 546 enforceCallingPermission(); 547 synchronized (mStats) { 548 mStats.noteResetVideoLocked(); 549 } 550 } 551 552 public void noteFlashlightOn() { 553 enforceCallingPermission(); 554 synchronized (mStats) { 555 mStats.noteFlashlightOnLocked(); 556 } 557 } 558 559 public void noteFlashlightOff() { 560 enforceCallingPermission(); 561 synchronized (mStats) { 562 mStats.noteFlashlightOffLocked(); 563 } 564 } 565 566 @Override 567 public void noteWifiRadioPowerState(int powerState, long tsNanos) { 568 enforceCallingPermission(); 569 570 // There was a change in WiFi power state. 571 // Collect data now for the past activity. 572 mHandler.scheduleSync(); 573 } 574 575 public void noteWifiRunning(WorkSource ws) { 576 enforceCallingPermission(); 577 synchronized (mStats) { 578 mStats.noteWifiRunningLocked(ws); 579 } 580 } 581 582 public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) { 583 enforceCallingPermission(); 584 synchronized (mStats) { 585 mStats.noteWifiRunningChangedLocked(oldWs, newWs); 586 } 587 } 588 589 public void noteWifiStopped(WorkSource ws) { 590 enforceCallingPermission(); 591 synchronized (mStats) { 592 mStats.noteWifiStoppedLocked(ws); 593 } 594 } 595 596 public void noteWifiState(int wifiState, String accessPoint) { 597 enforceCallingPermission(); 598 synchronized (mStats) { 599 mStats.noteWifiStateLocked(wifiState, accessPoint); 600 } 601 } 602 603 public void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth) { 604 enforceCallingPermission(); 605 synchronized (mStats) { 606 mStats.noteWifiSupplicantStateChangedLocked(supplState, failedAuth); 607 } 608 } 609 610 public void noteWifiRssiChanged(int newRssi) { 611 enforceCallingPermission(); 612 synchronized (mStats) { 613 mStats.noteWifiRssiChangedLocked(newRssi); 614 } 615 } 616 617 public void noteBluetoothOn() { 618 enforceCallingPermission(); 619 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 620 if (adapter != null) { 621 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, 622 BluetoothProfile.HEADSET); 623 } 624 synchronized (mStats) { 625 if (mBluetoothHeadset != null) { 626 mStats.noteBluetoothOnLocked(); 627 mStats.setBtHeadset(mBluetoothHeadset); 628 } else { 629 mBluetoothPendingStats = true; 630 } 631 } 632 } 633 634 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = 635 new BluetoothProfile.ServiceListener() { 636 public void onServiceConnected(int profile, BluetoothProfile proxy) { 637 mBluetoothHeadset = (BluetoothHeadset) proxy; 638 synchronized (mStats) { 639 if (mBluetoothPendingStats) { 640 mStats.noteBluetoothOnLocked(); 641 mStats.setBtHeadset(mBluetoothHeadset); 642 mBluetoothPendingStats = false; 643 } 644 } 645 } 646 647 public void onServiceDisconnected(int profile) { 648 mBluetoothHeadset = null; 649 } 650 }; 651 652 public void noteBluetoothOff() { 653 enforceCallingPermission(); 654 synchronized (mStats) { 655 mBluetoothPendingStats = false; 656 mStats.noteBluetoothOffLocked(); 657 } 658 } 659 660 public void noteBluetoothState(int bluetoothState) { 661 enforceCallingPermission(); 662 synchronized (mStats) { 663 mStats.noteBluetoothStateLocked(bluetoothState); 664 } 665 } 666 667 public void noteFullWifiLockAcquired(int uid) { 668 enforceCallingPermission(); 669 synchronized (mStats) { 670 mStats.noteFullWifiLockAcquiredLocked(uid); 671 } 672 } 673 674 public void noteFullWifiLockReleased(int uid) { 675 enforceCallingPermission(); 676 synchronized (mStats) { 677 mStats.noteFullWifiLockReleasedLocked(uid); 678 } 679 } 680 681 public void noteWifiScanStarted(int uid) { 682 enforceCallingPermission(); 683 synchronized (mStats) { 684 mStats.noteWifiScanStartedLocked(uid); 685 } 686 } 687 688 public void noteWifiScanStopped(int uid) { 689 enforceCallingPermission(); 690 synchronized (mStats) { 691 mStats.noteWifiScanStoppedLocked(uid); 692 } 693 } 694 695 public void noteWifiMulticastEnabled(int uid) { 696 enforceCallingPermission(); 697 synchronized (mStats) { 698 mStats.noteWifiMulticastEnabledLocked(uid); 699 } 700 } 701 702 public void noteWifiMulticastDisabled(int uid) { 703 enforceCallingPermission(); 704 synchronized (mStats) { 705 mStats.noteWifiMulticastDisabledLocked(uid); 706 } 707 } 708 709 public void noteFullWifiLockAcquiredFromSource(WorkSource ws) { 710 enforceCallingPermission(); 711 synchronized (mStats) { 712 mStats.noteFullWifiLockAcquiredFromSourceLocked(ws); 713 } 714 } 715 716 public void noteFullWifiLockReleasedFromSource(WorkSource ws) { 717 enforceCallingPermission(); 718 synchronized (mStats) { 719 mStats.noteFullWifiLockReleasedFromSourceLocked(ws); 720 } 721 } 722 723 public void noteWifiScanStartedFromSource(WorkSource ws) { 724 enforceCallingPermission(); 725 synchronized (mStats) { 726 mStats.noteWifiScanStartedFromSourceLocked(ws); 727 } 728 } 729 730 public void noteWifiScanStoppedFromSource(WorkSource ws) { 731 enforceCallingPermission(); 732 synchronized (mStats) { 733 mStats.noteWifiScanStoppedFromSourceLocked(ws); 734 } 735 } 736 737 public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) { 738 enforceCallingPermission(); 739 synchronized (mStats) { 740 mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph); 741 } 742 } 743 744 public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) { 745 enforceCallingPermission(); 746 synchronized (mStats) { 747 mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws); 748 } 749 } 750 751 public void noteWifiMulticastEnabledFromSource(WorkSource ws) { 752 enforceCallingPermission(); 753 synchronized (mStats) { 754 mStats.noteWifiMulticastEnabledFromSourceLocked(ws); 755 } 756 } 757 758 @Override 759 public void noteWifiMulticastDisabledFromSource(WorkSource ws) { 760 enforceCallingPermission(); 761 synchronized (mStats) { 762 mStats.noteWifiMulticastDisabledFromSourceLocked(ws); 763 } 764 } 765 766 @Override 767 public void noteNetworkInterfaceType(String iface, int networkType) { 768 enforceCallingPermission(); 769 synchronized (mStats) { 770 mStats.noteNetworkInterfaceTypeLocked(iface, networkType); 771 } 772 } 773 774 @Override 775 public void noteNetworkStatsEnabled() { 776 enforceCallingPermission(); 777 synchronized (mStats) { 778 mStats.noteNetworkStatsEnabledLocked(); 779 } 780 } 781 782 @Override 783 public void noteDeviceIdleMode(boolean enabled, boolean fromActive, boolean fromMotion) { 784 enforceCallingPermission(); 785 synchronized (mStats) { 786 mStats.noteDeviceIdleModeLocked(enabled, fromActive, fromMotion); 787 } 788 } 789 790 public void notePackageInstalled(String pkgName, int versionCode) { 791 enforceCallingPermission(); 792 synchronized (mStats) { 793 mStats.notePackageInstalledLocked(pkgName, versionCode); 794 } 795 } 796 797 public void notePackageUninstalled(String pkgName) { 798 enforceCallingPermission(); 799 synchronized (mStats) { 800 mStats.notePackageUninstalledLocked(pkgName); 801 } 802 } 803 804 public boolean isOnBattery() { 805 return mStats.isOnBattery(); 806 } 807 808 public void setBatteryState(int status, int health, int plugType, int level, 809 int temp, int volt) { 810 enforceCallingPermission(); 811 synchronized (mStats) { 812 final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE; 813 if (mStats.isOnBattery() == onBattery) { 814 // The battery state has not changed, so we don't need to sync external 815 // stats immediately. 816 mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt); 817 return; 818 } 819 } 820 821 // Sync external stats first as the battery has changed states. If we don't sync 822 // immediately here, we may not collect the relevant data later. 823 updateExternalStats(); 824 synchronized (mStats) { 825 mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt); 826 } 827 } 828 829 public long getAwakeTimeBattery() { 830 mContext.enforceCallingOrSelfPermission( 831 android.Manifest.permission.BATTERY_STATS, null); 832 return mStats.getAwakeTimeBattery(); 833 } 834 835 public long getAwakeTimePlugged() { 836 mContext.enforceCallingOrSelfPermission( 837 android.Manifest.permission.BATTERY_STATS, null); 838 return mStats.getAwakeTimePlugged(); 839 } 840 841 public void enforceCallingPermission() { 842 if (Binder.getCallingPid() == Process.myPid()) { 843 return; 844 } 845 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS, 846 Binder.getCallingPid(), Binder.getCallingUid(), null); 847 } 848 849 final class WakeupReasonThread extends Thread { 850 final int[] mIrqs = new int[32]; 851 final String[] mReasons = new String[32]; 852 853 WakeupReasonThread() { 854 super("BatteryStats_wakeupReason"); 855 } 856 857 public void run() { 858 Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND); 859 860 try { 861 int num; 862 while ((num=nativeWaitWakeup(mIrqs, mReasons)) >= 0) { 863 synchronized (mStats) { 864 if (num > 0) { 865 for (int i=0; i<num; i++) { 866 mStats.noteWakeupReasonLocked(mReasons[i]); 867 } 868 } else { 869 mStats.noteWakeupReasonLocked("unknown"); 870 } 871 } 872 } 873 } catch (RuntimeException e) { 874 Slog.e(TAG, "Failure reading wakeup reasons", e); 875 } 876 } 877 } 878 879 private static native int nativeWaitWakeup(int[] outIrqs, String[] outReasons); 880 881 private void dumpHelp(PrintWriter pw) { 882 pw.println("Battery stats (batterystats) dump options:"); 883 pw.println(" [--checkin] [--history] [--history-start] [--charged] [-c]"); 884 pw.println(" [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]"); 885 pw.println(" --checkin: format output for a checkin report."); 886 pw.println(" --history: show only history data."); 887 pw.println(" --history-start <num>: show only history data starting at given time offset."); 888 pw.println(" --charged: only output data since last charged."); 889 pw.println(" --daily: only output full daily data."); 890 pw.println(" --reset: reset the stats, clearing all current data."); 891 pw.println(" --write: force write current collected stats to disk."); 892 pw.println(" --new-daily: immediately create and write new daily stats record."); 893 pw.println(" --read-daily: read-load last written daily stats."); 894 pw.println(" <package.name>: optional name of package to filter output by."); 895 pw.println(" -h: print this help text."); 896 pw.println("Battery stats (batterystats) commands:"); 897 pw.println(" enable|disable <option>"); 898 pw.println(" Enable or disable a running option. Option state is not saved across boots."); 899 pw.println(" Options are:"); 900 pw.println(" full-history: include additional detailed events in battery history:"); 901 pw.println(" wake_lock_in, alarms and proc events"); 902 pw.println(" no-auto-reset: don't automatically reset stats when unplugged"); 903 } 904 905 private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) { 906 i++; 907 if (i >= args.length) { 908 pw.println("Missing option argument for " + (enable ? "--enable" : "--disable")); 909 dumpHelp(pw); 910 return -1; 911 } 912 if ("full-wake-history".equals(args[i]) || "full-history".equals(args[i])) { 913 synchronized (mStats) { 914 mStats.setRecordAllHistoryLocked(enable); 915 } 916 } else if ("no-auto-reset".equals(args[i])) { 917 synchronized (mStats) { 918 mStats.setNoAutoReset(enable); 919 } 920 } else { 921 pw.println("Unknown enable/disable option: " + args[i]); 922 dumpHelp(pw); 923 return -1; 924 } 925 return i; 926 } 927 928 929 @Override 930 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 931 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 932 != PackageManager.PERMISSION_GRANTED) { 933 pw.println("Permission Denial: can't dump BatteryStats from from pid=" 934 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 935 + " without permission " + android.Manifest.permission.DUMP); 936 return; 937 } 938 939 int flags = 0; 940 boolean useCheckinFormat = false; 941 boolean isRealCheckin = false; 942 boolean noOutput = false; 943 boolean writeData = false; 944 long historyStart = -1; 945 int reqUid = -1; 946 if (args != null) { 947 for (int i=0; i<args.length; i++) { 948 String arg = args[i]; 949 if ("--checkin".equals(arg)) { 950 useCheckinFormat = true; 951 isRealCheckin = true; 952 } else if ("--history".equals(arg)) { 953 flags |= BatteryStats.DUMP_HISTORY_ONLY; 954 } else if ("--history-start".equals(arg)) { 955 flags |= BatteryStats.DUMP_HISTORY_ONLY; 956 i++; 957 if (i >= args.length) { 958 pw.println("Missing time argument for --history-since"); 959 dumpHelp(pw); 960 return; 961 } 962 historyStart = Long.parseLong(args[i]); 963 writeData = true; 964 } else if ("-c".equals(arg)) { 965 useCheckinFormat = true; 966 flags |= BatteryStats.DUMP_INCLUDE_HISTORY; 967 } else if ("--charged".equals(arg)) { 968 flags |= BatteryStats.DUMP_CHARGED_ONLY; 969 } else if ("--daily".equals(arg)) { 970 flags |= BatteryStats.DUMP_DAILY_ONLY; 971 } else if ("--reset".equals(arg)) { 972 synchronized (mStats) { 973 mStats.resetAllStatsCmdLocked(); 974 pw.println("Battery stats reset."); 975 noOutput = true; 976 } 977 updateExternalStats(); 978 } else if ("--write".equals(arg)) { 979 updateExternalStats(); 980 synchronized (mStats) { 981 mStats.writeSyncLocked(); 982 pw.println("Battery stats written."); 983 noOutput = true; 984 } 985 } else if ("--new-daily".equals(arg)) { 986 synchronized (mStats) { 987 mStats.recordDailyStatsLocked(); 988 pw.println("New daily stats written."); 989 noOutput = true; 990 } 991 } else if ("--read-daily".equals(arg)) { 992 synchronized (mStats) { 993 mStats.readDailyStatsLocked(); 994 pw.println("Last daily stats read."); 995 noOutput = true; 996 } 997 } else if ("--enable".equals(arg) || "enable".equals(arg)) { 998 i = doEnableOrDisable(pw, i, args, true); 999 if (i < 0) { 1000 return; 1001 } 1002 pw.println("Enabled: " + args[i]); 1003 return; 1004 } else if ("--disable".equals(arg) || "disable".equals(arg)) { 1005 i = doEnableOrDisable(pw, i, args, false); 1006 if (i < 0) { 1007 return; 1008 } 1009 pw.println("Disabled: " + args[i]); 1010 return; 1011 } else if ("-h".equals(arg)) { 1012 dumpHelp(pw); 1013 return; 1014 } else if ("-a".equals(arg)) { 1015 flags |= BatteryStats.DUMP_VERBOSE; 1016 } else if (arg.length() > 0 && arg.charAt(0) == '-'){ 1017 pw.println("Unknown option: " + arg); 1018 dumpHelp(pw); 1019 return; 1020 } else { 1021 // Not an option, last argument must be a package name. 1022 try { 1023 reqUid = mContext.getPackageManager().getPackageUid(arg, 1024 UserHandle.getCallingUserId()); 1025 } catch (PackageManager.NameNotFoundException e) { 1026 pw.println("Unknown package: " + arg); 1027 dumpHelp(pw); 1028 return; 1029 } 1030 } 1031 } 1032 } 1033 if (noOutput) { 1034 return; 1035 } 1036 if (BatteryStatsHelper.checkWifiOnly(mContext)) { 1037 flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY; 1038 } 1039 if (reqUid >= 0) { 1040 // By default, if the caller is only interested in a specific package, then 1041 // we only dump the aggregated data since charged. 1042 if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_CHARGED_ONLY)) == 0) { 1043 flags |= BatteryStats.DUMP_CHARGED_ONLY; 1044 // Also if they are doing -c, we don't want history. 1045 flags &= ~BatteryStats.DUMP_INCLUDE_HISTORY; 1046 } 1047 } 1048 1049 // Fetch data from external sources and update the BatteryStatsImpl object with them. 1050 updateExternalStats(); 1051 1052 if (useCheckinFormat) { 1053 List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0); 1054 if (isRealCheckin) { 1055 // For a real checkin, first we want to prefer to use the last complete checkin 1056 // file if there is one. 1057 synchronized (mStats.mCheckinFile) { 1058 if (mStats.mCheckinFile.exists()) { 1059 try { 1060 byte[] raw = mStats.mCheckinFile.readFully(); 1061 if (raw != null) { 1062 Parcel in = Parcel.obtain(); 1063 in.unmarshall(raw, 0, raw.length); 1064 in.setDataPosition(0); 1065 BatteryStatsImpl checkinStats = new BatteryStatsImpl( 1066 null, mStats.mHandler, null); 1067 checkinStats.readSummaryFromParcel(in); 1068 in.recycle(); 1069 checkinStats.dumpCheckinLocked(mContext, pw, apps, flags, 1070 historyStart); 1071 mStats.mCheckinFile.delete(); 1072 return; 1073 } 1074 } catch (IOException e) { 1075 Slog.w(TAG, "Failure reading checkin file " 1076 + mStats.mCheckinFile.getBaseFile(), e); 1077 } 1078 } 1079 } 1080 } 1081 synchronized (mStats) { 1082 mStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart); 1083 if (writeData) { 1084 mStats.writeAsyncLocked(); 1085 } 1086 } 1087 } else { 1088 synchronized (mStats) { 1089 mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart); 1090 if (writeData) { 1091 mStats.writeAsyncLocked(); 1092 } 1093 } 1094 } 1095 } 1096 1097 // Objects for extracting data from external sources. 1098 private final Object mExternalStatsLock = new Object(); 1099 1100 @GuardedBy("mExternalStatsLock") 1101 private IWifiManager mWifiManager; 1102 1103 // WiFi keeps an accumulated total of stats, unlike Bluetooth. 1104 // Keep the last WiFi stats so we can compute a delta. 1105 @GuardedBy("mExternalStatsLock") 1106 private WifiActivityEnergyInfo mLastInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0); 1107 1108 @GuardedBy("mExternalStatsLock") 1109 private WifiActivityEnergyInfo pullWifiEnergyInfoLocked() { 1110 if (mWifiManager == null) { 1111 mWifiManager = IWifiManager.Stub.asInterface( 1112 ServiceManager.getService(Context.WIFI_SERVICE)); 1113 if (mWifiManager == null) { 1114 return null; 1115 } 1116 } 1117 1118 try { 1119 // We read the data even if we are not on battery. This is so that we keep the 1120 // correct delta from when we should start reading (aka when we are on battery). 1121 WifiActivityEnergyInfo info = mWifiManager.reportActivityInfo(); 1122 if (info != null && info.isValid()) { 1123 // We will modify the last info object to be the delta, and store the new 1124 // WifiActivityEnergyInfo object as our last one. 1125 final WifiActivityEnergyInfo result = mLastInfo; 1126 result.mTimestamp = info.getTimeStamp(); 1127 result.mStackState = info.getStackState(); 1128 result.mControllerTxTimeMs = 1129 info.mControllerTxTimeMs - mLastInfo.mControllerTxTimeMs; 1130 result.mControllerRxTimeMs = 1131 info.mControllerRxTimeMs - mLastInfo.mControllerRxTimeMs; 1132 result.mControllerEnergyUsed = 1133 info.mControllerEnergyUsed - mLastInfo.mControllerEnergyUsed; 1134 1135 // WiFi calculates the idle time as a difference from the on time and the various 1136 // Rx + Tx times. There seems to be some missing time there because this sometimes 1137 // becomes negative. Just cap it at 0 and move on. 1138 result.mControllerIdleTimeMs = 1139 Math.max(0, info.mControllerIdleTimeMs - mLastInfo.mControllerIdleTimeMs); 1140 1141 if (result.mControllerTxTimeMs < 0 || 1142 result.mControllerRxTimeMs < 0) { 1143 // The stats were reset by the WiFi system (which is why our delta is negative). 1144 // Returns the unaltered stats. 1145 result.mControllerEnergyUsed = info.mControllerEnergyUsed; 1146 result.mControllerRxTimeMs = info.mControllerRxTimeMs; 1147 result.mControllerTxTimeMs = info.mControllerTxTimeMs; 1148 result.mControllerIdleTimeMs = info.mControllerIdleTimeMs; 1149 1150 Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + result); 1151 } 1152 mLastInfo = info; 1153 return result; 1154 } 1155 } catch (RemoteException e) { 1156 // Nothing to report, WiFi is dead. 1157 } 1158 return null; 1159 } 1160 1161 @GuardedBy("mExternalStatsLock") 1162 private BluetoothActivityEnergyInfo pullBluetoothEnergyInfoLocked() { 1163 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1164 if (adapter != null) { 1165 BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo( 1166 BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED); 1167 if (info != null && info.isValid()) { 1168 return info; 1169 } 1170 } 1171 return null; 1172 } 1173 1174 /** 1175 * Fetches data from external sources (WiFi controller, bluetooth chipset) and updates 1176 * batterystats with that information. 1177 * 1178 * We first grab a lock specific to this method, then once all the data has been collected, 1179 * we grab the mStats lock and update the data. 1180 */ 1181 void updateExternalStats() { 1182 synchronized (mExternalStatsLock) { 1183 if (mContext == null) { 1184 // We haven't started yet (which means the BatteryStatsImpl object has 1185 // no power profile. Don't consume data we can't compute yet. 1186 return; 1187 } 1188 1189 final WifiActivityEnergyInfo wifiEnergyInfo = pullWifiEnergyInfoLocked(); 1190 final BluetoothActivityEnergyInfo bluetoothEnergyInfo = pullBluetoothEnergyInfoLocked(); 1191 synchronized (mStats) { 1192 mStats.updateKernelWakelocksLocked(); 1193 mStats.updateMobileRadioStateLocked(SystemClock.elapsedRealtime()); 1194 mStats.updateWifiStateLocked(wifiEnergyInfo); 1195 mStats.updateBluetoothStateLocked(bluetoothEnergyInfo); 1196 } 1197 } 1198 } 1199} 1200