BatteryStatsService.java revision 9cfba3502079f5919ec065da2f8d86fe35c475da
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.content.Context; 22import android.content.pm.ApplicationInfo; 23import android.content.pm.PackageManager; 24import android.net.wifi.IWifiManager; 25import android.net.wifi.WifiActivityEnergyInfo; 26import android.os.BatteryStats; 27import android.os.Binder; 28import android.os.Handler; 29import android.os.IBinder; 30import android.os.Looper; 31import android.os.Message; 32import android.os.Parcel; 33import android.os.ParcelFileDescriptor; 34import android.os.ParcelFormatException; 35import android.os.PowerManager; 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.os.health.HealthStatsParceler; 44import android.os.health.HealthStatsWriter; 45import android.os.health.UidHealthStats; 46import android.telephony.DataConnectionRealTimeInfo; 47import android.telephony.ModemActivityInfo; 48import android.telephony.SignalStrength; 49import android.telephony.TelephonyManager; 50import android.util.IntArray; 51import android.util.Slog; 52 53import android.util.TimeUtils; 54import com.android.internal.annotations.GuardedBy; 55import com.android.internal.app.IBatteryStats; 56import com.android.internal.os.BatteryStatsHelper; 57import com.android.internal.os.BatteryStatsImpl; 58import com.android.internal.os.PowerProfile; 59import com.android.internal.telephony.ITelephony; 60import com.android.server.FgThread; 61import com.android.server.LocalServices; 62 63import java.io.File; 64import java.io.FileDescriptor; 65import java.io.IOException; 66import java.io.PrintWriter; 67import java.nio.ByteBuffer; 68import java.nio.CharBuffer; 69import java.nio.charset.CharsetDecoder; 70import java.nio.charset.CodingErrorAction; 71import java.nio.charset.StandardCharsets; 72import java.util.Arrays; 73import java.util.List; 74import java.util.Map; 75 76/** 77 * All information we are collecting about things that can happen that impact 78 * battery life. 79 */ 80public final class BatteryStatsService extends IBatteryStats.Stub 81 implements PowerManagerInternal.LowPowerModeListener { 82 static final String TAG = "BatteryStatsService"; 83 84 static IBatteryStats sService; 85 final BatteryStatsImpl mStats; 86 final BatteryStatsHandler mHandler; 87 Context mContext; 88 PowerManagerInternal mPowerManagerInternal; 89 90 class BatteryStatsHandler extends Handler implements BatteryStatsImpl.ExternalStatsSync { 91 public static final int MSG_SYNC_EXTERNAL_STATS = 1; 92 public static final int MSG_WRITE_TO_DISK = 2; 93 private int mUpdateFlags = 0; 94 private IntArray mUidsToRemove = new IntArray(); 95 96 public BatteryStatsHandler(Looper looper) { 97 super(looper); 98 } 99 100 @Override 101 public void handleMessage(Message msg) { 102 switch (msg.what) { 103 case MSG_SYNC_EXTERNAL_STATS: 104 final int updateFlags; 105 synchronized (this) { 106 removeMessages(MSG_SYNC_EXTERNAL_STATS); 107 updateFlags = mUpdateFlags; 108 mUpdateFlags = 0; 109 } 110 updateExternalStats((String)msg.obj, updateFlags); 111 112 // other parts of the system could be calling into us 113 // from mStats in order to report of changes. We must grab the mStats 114 // lock before grabbing our own or we'll end up in a deadlock. 115 synchronized (mStats) { 116 synchronized (this) { 117 final int numUidsToRemove = mUidsToRemove.size(); 118 for (int i = 0; i < numUidsToRemove; i++) { 119 mStats.removeIsolatedUidLocked(mUidsToRemove.get(i)); 120 } 121 } 122 mUidsToRemove.clear(); 123 } 124 break; 125 126 case MSG_WRITE_TO_DISK: 127 updateExternalStats("write", UPDATE_ALL); 128 synchronized (mStats) { 129 mStats.writeAsyncLocked(); 130 } 131 break; 132 } 133 } 134 135 @Override 136 public void scheduleSync(String reason, int updateFlags) { 137 synchronized (this) { 138 scheduleSyncLocked(reason, updateFlags); 139 } 140 } 141 142 @Override 143 public void scheduleCpuSyncDueToRemovedUid(int uid) { 144 synchronized (this) { 145 scheduleSyncLocked("remove-uid", UPDATE_CPU); 146 mUidsToRemove.add(uid); 147 } 148 } 149 150 private void scheduleSyncLocked(String reason, int updateFlags) { 151 if (mUpdateFlags == 0) { 152 sendMessage(Message.obtain(this, MSG_SYNC_EXTERNAL_STATS, reason)); 153 } 154 mUpdateFlags |= updateFlags; 155 } 156 } 157 158 BatteryStatsService(File systemDir, Handler handler) { 159 // Our handler here will be accessing the disk, use a different thread than 160 // what the ActivityManagerService gave us (no I/O on that one!). 161 mHandler = new BatteryStatsHandler(FgThread.getHandler().getLooper()); 162 163 // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through. 164 mStats = new BatteryStatsImpl(systemDir, handler, mHandler); 165 } 166 167 public void publish(Context context) { 168 mContext = context; 169 mStats.setRadioScanningTimeout(mContext.getResources().getInteger( 170 com.android.internal.R.integer.config_radioScanningTimeout) 171 * 1000L); 172 mStats.setPowerProfile(new PowerProfile(context)); 173 ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder()); 174 } 175 176 /** 177 * At the time when the constructor runs, the power manager has not yet been 178 * initialized. So we initialize the low power observer later. 179 */ 180 public void initPowerManagement() { 181 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class); 182 mPowerManagerInternal.registerLowPowerModeObserver(this); 183 mStats.notePowerSaveMode(mPowerManagerInternal.getLowPowerModeEnabled()); 184 (new WakeupReasonThread()).start(); 185 } 186 187 public void shutdown() { 188 Slog.w("BatteryStats", "Writing battery stats before shutdown..."); 189 190 updateExternalStats("shutdown", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL); 191 synchronized (mStats) { 192 mStats.shutdownLocked(); 193 } 194 } 195 196 public static IBatteryStats getService() { 197 if (sService != null) { 198 return sService; 199 } 200 IBinder b = ServiceManager.getService(BatteryStats.SERVICE_NAME); 201 sService = asInterface(b); 202 return sService; 203 } 204 205 @Override 206 public void onLowPowerModeChanged(boolean enabled) { 207 synchronized (mStats) { 208 mStats.notePowerSaveMode(enabled); 209 } 210 } 211 212 /** 213 * @return the current statistics object, which may be modified 214 * to reflect events that affect battery usage. You must lock the 215 * stats object before doing anything with it. 216 */ 217 public BatteryStatsImpl getActiveStatistics() { 218 return mStats; 219 } 220 221 /** 222 * Schedules a write to disk to occur. This will cause the BatteryStatsImpl 223 * object to update with the latest info, then write to disk. 224 */ 225 public void scheduleWriteToDisk() { 226 mHandler.sendEmptyMessage(BatteryStatsHandler.MSG_WRITE_TO_DISK); 227 } 228 229 // These are for direct use by the activity manager... 230 231 /** 232 * Remove a UID from the BatteryStats and BatteryStats' external dependencies. 233 */ 234 void removeUid(int uid) { 235 synchronized (mStats) { 236 mStats.removeUidStatsLocked(uid); 237 } 238 } 239 240 void addIsolatedUid(int isolatedUid, int appUid) { 241 synchronized (mStats) { 242 mStats.addIsolatedUidLocked(isolatedUid, appUid); 243 } 244 } 245 246 void removeIsolatedUid(int isolatedUid, int appUid) { 247 synchronized (mStats) { 248 mStats.scheduleRemoveIsolatedUidLocked(isolatedUid, appUid); 249 } 250 } 251 252 void noteProcessStart(String name, int uid) { 253 synchronized (mStats) { 254 mStats.noteProcessStartLocked(name, uid); 255 } 256 } 257 258 void noteProcessCrash(String name, int uid) { 259 synchronized (mStats) { 260 mStats.noteProcessCrashLocked(name, uid); 261 } 262 } 263 264 void noteProcessAnr(String name, int uid) { 265 synchronized (mStats) { 266 mStats.noteProcessAnrLocked(name, uid); 267 } 268 } 269 270 void noteProcessFinish(String name, int uid) { 271 synchronized (mStats) { 272 mStats.noteProcessFinishLocked(name, uid); 273 } 274 } 275 276 void noteUidProcessState(int uid, int state) { 277 synchronized (mStats) { 278 mStats.noteUidProcessStateLocked(uid, state); 279 } 280 } 281 282 // Public interface... 283 284 public byte[] getStatistics() { 285 mContext.enforceCallingPermission( 286 android.Manifest.permission.BATTERY_STATS, null); 287 //Slog.i("foo", "SENDING BATTERY INFO:"); 288 //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM)); 289 Parcel out = Parcel.obtain(); 290 updateExternalStats("get-stats", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL); 291 synchronized (mStats) { 292 mStats.writeToParcel(out, 0); 293 } 294 byte[] data = out.marshall(); 295 out.recycle(); 296 return data; 297 } 298 299 public ParcelFileDescriptor getStatisticsStream() { 300 mContext.enforceCallingPermission( 301 android.Manifest.permission.BATTERY_STATS, null); 302 //Slog.i("foo", "SENDING BATTERY INFO:"); 303 //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM)); 304 Parcel out = Parcel.obtain(); 305 updateExternalStats("get-stats", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL); 306 synchronized (mStats) { 307 mStats.writeToParcel(out, 0); 308 } 309 byte[] data = out.marshall(); 310 out.recycle(); 311 try { 312 return ParcelFileDescriptor.fromData(data, "battery-stats"); 313 } catch (IOException e) { 314 Slog.w(TAG, "Unable to create shared memory", e); 315 return null; 316 } 317 } 318 319 public boolean isCharging() { 320 synchronized (mStats) { 321 return mStats.isCharging(); 322 } 323 } 324 325 public long computeBatteryTimeRemaining() { 326 synchronized (mStats) { 327 long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime()); 328 return time >= 0 ? (time/1000) : time; 329 } 330 } 331 332 public long computeChargeTimeRemaining() { 333 synchronized (mStats) { 334 long time = mStats.computeChargeTimeRemaining(SystemClock.elapsedRealtime()); 335 return time >= 0 ? (time/1000) : time; 336 } 337 } 338 339 public void noteEvent(int code, String name, int uid) { 340 enforceCallingPermission(); 341 synchronized (mStats) { 342 mStats.noteEventLocked(code, name, uid); 343 } 344 } 345 346 public void noteSyncStart(String name, int uid) { 347 enforceCallingPermission(); 348 synchronized (mStats) { 349 mStats.noteSyncStartLocked(name, uid); 350 } 351 } 352 353 public void noteSyncFinish(String name, int uid) { 354 enforceCallingPermission(); 355 synchronized (mStats) { 356 mStats.noteSyncFinishLocked(name, uid); 357 } 358 } 359 360 public void noteJobStart(String name, int uid) { 361 enforceCallingPermission(); 362 synchronized (mStats) { 363 mStats.noteJobStartLocked(name, uid); 364 } 365 } 366 367 public void noteJobFinish(String name, int uid) { 368 enforceCallingPermission(); 369 synchronized (mStats) { 370 mStats.noteJobFinishLocked(name, uid); 371 } 372 } 373 374 public void noteAlarmStart(String name, int uid) { 375 enforceCallingPermission(); 376 synchronized (mStats) { 377 mStats.noteAlarmStartLocked(name, uid); 378 } 379 } 380 381 public void noteAlarmFinish(String name, int uid) { 382 enforceCallingPermission(); 383 synchronized (mStats) { 384 mStats.noteAlarmFinishLocked(name, uid); 385 } 386 } 387 388 public void noteStartWakelock(int uid, int pid, String name, String historyName, int type, 389 boolean unimportantForLogging) { 390 enforceCallingPermission(); 391 synchronized (mStats) { 392 mStats.noteStartWakeLocked(uid, pid, name, historyName, type, unimportantForLogging, 393 SystemClock.elapsedRealtime(), SystemClock.uptimeMillis()); 394 } 395 } 396 397 public void noteStopWakelock(int uid, int pid, String name, String historyName, int type) { 398 enforceCallingPermission(); 399 synchronized (mStats) { 400 mStats.noteStopWakeLocked(uid, pid, name, historyName, type, 401 SystemClock.elapsedRealtime(), SystemClock.uptimeMillis()); 402 } 403 } 404 405 public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, 406 String historyName, int type, boolean unimportantForLogging) { 407 enforceCallingPermission(); 408 synchronized (mStats) { 409 mStats.noteStartWakeFromSourceLocked(ws, pid, name, historyName, 410 type, unimportantForLogging); 411 } 412 } 413 414 public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name, 415 String historyName, int type, WorkSource newWs, int newPid, String newName, 416 String newHistoryName, int newType, boolean newUnimportantForLogging) { 417 enforceCallingPermission(); 418 synchronized (mStats) { 419 mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, historyName, type, 420 newWs, newPid, newName, newHistoryName, newType, newUnimportantForLogging); 421 } 422 } 423 424 public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, String historyName, 425 int type) { 426 enforceCallingPermission(); 427 synchronized (mStats) { 428 mStats.noteStopWakeFromSourceLocked(ws, pid, name, historyName, type); 429 } 430 } 431 432 public void noteStartSensor(int uid, int sensor) { 433 enforceCallingPermission(); 434 synchronized (mStats) { 435 mStats.noteStartSensorLocked(uid, sensor); 436 } 437 } 438 439 public void noteStopSensor(int uid, int sensor) { 440 enforceCallingPermission(); 441 synchronized (mStats) { 442 mStats.noteStopSensorLocked(uid, sensor); 443 } 444 } 445 446 public void noteVibratorOn(int uid, long durationMillis) { 447 enforceCallingPermission(); 448 synchronized (mStats) { 449 mStats.noteVibratorOnLocked(uid, durationMillis); 450 } 451 } 452 453 public void noteVibratorOff(int uid) { 454 enforceCallingPermission(); 455 synchronized (mStats) { 456 mStats.noteVibratorOffLocked(uid); 457 } 458 } 459 460 public void noteStartGps(int uid) { 461 enforceCallingPermission(); 462 synchronized (mStats) { 463 mStats.noteStartGpsLocked(uid); 464 } 465 } 466 467 public void noteStopGps(int uid) { 468 enforceCallingPermission(); 469 synchronized (mStats) { 470 mStats.noteStopGpsLocked(uid); 471 } 472 } 473 474 public void noteScreenState(int state) { 475 enforceCallingPermission(); 476 synchronized (mStats) { 477 mStats.noteScreenStateLocked(state); 478 } 479 } 480 481 public void noteScreenBrightness(int brightness) { 482 enforceCallingPermission(); 483 synchronized (mStats) { 484 mStats.noteScreenBrightnessLocked(brightness); 485 } 486 } 487 488 public void noteUserActivity(int uid, int event) { 489 enforceCallingPermission(); 490 synchronized (mStats) { 491 mStats.noteUserActivityLocked(uid, event); 492 } 493 } 494 495 public void noteWakeUp(String reason, int reasonUid) { 496 enforceCallingPermission(); 497 synchronized (mStats) { 498 mStats.noteWakeUpLocked(reason, reasonUid); 499 } 500 } 501 502 public void noteInteractive(boolean interactive) { 503 enforceCallingPermission(); 504 synchronized (mStats) { 505 mStats.noteInteractiveLocked(interactive); 506 } 507 } 508 509 public void noteConnectivityChanged(int type, String extra) { 510 enforceCallingPermission(); 511 synchronized (mStats) { 512 mStats.noteConnectivityChangedLocked(type, extra); 513 } 514 } 515 516 public void noteMobileRadioPowerState(int powerState, long timestampNs) { 517 enforceCallingPermission(); 518 synchronized (mStats) { 519 mStats.noteMobileRadioPowerState(powerState, timestampNs); 520 } 521 } 522 523 public void notePhoneOn() { 524 enforceCallingPermission(); 525 synchronized (mStats) { 526 mStats.notePhoneOnLocked(); 527 } 528 } 529 530 public void notePhoneOff() { 531 enforceCallingPermission(); 532 synchronized (mStats) { 533 mStats.notePhoneOffLocked(); 534 } 535 } 536 537 public void notePhoneSignalStrength(SignalStrength signalStrength) { 538 enforceCallingPermission(); 539 synchronized (mStats) { 540 mStats.notePhoneSignalStrengthLocked(signalStrength); 541 } 542 } 543 544 public void notePhoneDataConnectionState(int dataType, boolean hasData) { 545 enforceCallingPermission(); 546 synchronized (mStats) { 547 mStats.notePhoneDataConnectionStateLocked(dataType, hasData); 548 } 549 } 550 551 public void notePhoneState(int state) { 552 enforceCallingPermission(); 553 int simState = TelephonyManager.getDefault().getSimState(); 554 synchronized (mStats) { 555 mStats.notePhoneStateLocked(state, simState); 556 } 557 } 558 559 public void noteWifiOn() { 560 enforceCallingPermission(); 561 synchronized (mStats) { 562 mStats.noteWifiOnLocked(); 563 } 564 } 565 566 public void noteWifiOff() { 567 enforceCallingPermission(); 568 synchronized (mStats) { 569 mStats.noteWifiOffLocked(); 570 } 571 } 572 573 public void noteStartAudio(int uid) { 574 enforceCallingPermission(); 575 synchronized (mStats) { 576 mStats.noteAudioOnLocked(uid); 577 } 578 } 579 580 public void noteStopAudio(int uid) { 581 enforceCallingPermission(); 582 synchronized (mStats) { 583 mStats.noteAudioOffLocked(uid); 584 } 585 } 586 587 public void noteStartVideo(int uid) { 588 enforceCallingPermission(); 589 synchronized (mStats) { 590 mStats.noteVideoOnLocked(uid); 591 } 592 } 593 594 public void noteStopVideo(int uid) { 595 enforceCallingPermission(); 596 synchronized (mStats) { 597 mStats.noteVideoOffLocked(uid); 598 } 599 } 600 601 public void noteResetAudio() { 602 enforceCallingPermission(); 603 synchronized (mStats) { 604 mStats.noteResetAudioLocked(); 605 } 606 } 607 608 public void noteResetVideo() { 609 enforceCallingPermission(); 610 synchronized (mStats) { 611 mStats.noteResetVideoLocked(); 612 } 613 } 614 615 public void noteFlashlightOn(int uid) { 616 enforceCallingPermission(); 617 synchronized (mStats) { 618 mStats.noteFlashlightOnLocked(uid); 619 } 620 } 621 622 public void noteFlashlightOff(int uid) { 623 enforceCallingPermission(); 624 synchronized (mStats) { 625 mStats.noteFlashlightOffLocked(uid); 626 } 627 } 628 629 public void noteStartCamera(int uid) { 630 enforceCallingPermission(); 631 synchronized (mStats) { 632 mStats.noteCameraOnLocked(uid); 633 } 634 } 635 636 public void noteStopCamera(int uid) { 637 enforceCallingPermission(); 638 synchronized (mStats) { 639 mStats.noteCameraOffLocked(uid); 640 } 641 } 642 643 public void noteResetCamera() { 644 enforceCallingPermission(); 645 synchronized (mStats) { 646 mStats.noteResetCameraLocked(); 647 } 648 } 649 650 public void noteResetFlashlight() { 651 enforceCallingPermission(); 652 synchronized (mStats) { 653 mStats.noteResetFlashlightLocked(); 654 } 655 } 656 657 @Override 658 public void noteWifiRadioPowerState(int powerState, long tsNanos) { 659 enforceCallingPermission(); 660 661 // There was a change in WiFi power state. 662 // Collect data now for the past activity. 663 synchronized (mStats) { 664 if (mStats.isOnBattery()) { 665 final String type = (powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH || 666 powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM) ? "active" 667 : "inactive"; 668 mHandler.scheduleSync("wifi-data: " + type, 669 BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI); 670 } 671 mStats.noteWifiRadioPowerState(powerState, tsNanos); 672 } 673 } 674 675 public void noteWifiRunning(WorkSource ws) { 676 enforceCallingPermission(); 677 synchronized (mStats) { 678 mStats.noteWifiRunningLocked(ws); 679 } 680 } 681 682 public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) { 683 enforceCallingPermission(); 684 synchronized (mStats) { 685 mStats.noteWifiRunningChangedLocked(oldWs, newWs); 686 } 687 } 688 689 public void noteWifiStopped(WorkSource ws) { 690 enforceCallingPermission(); 691 synchronized (mStats) { 692 mStats.noteWifiStoppedLocked(ws); 693 } 694 } 695 696 public void noteWifiState(int wifiState, String accessPoint) { 697 enforceCallingPermission(); 698 synchronized (mStats) { 699 mStats.noteWifiStateLocked(wifiState, accessPoint); 700 } 701 } 702 703 public void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth) { 704 enforceCallingPermission(); 705 synchronized (mStats) { 706 mStats.noteWifiSupplicantStateChangedLocked(supplState, failedAuth); 707 } 708 } 709 710 public void noteWifiRssiChanged(int newRssi) { 711 enforceCallingPermission(); 712 synchronized (mStats) { 713 mStats.noteWifiRssiChangedLocked(newRssi); 714 } 715 } 716 717 public void noteFullWifiLockAcquired(int uid) { 718 enforceCallingPermission(); 719 synchronized (mStats) { 720 mStats.noteFullWifiLockAcquiredLocked(uid); 721 } 722 } 723 724 public void noteFullWifiLockReleased(int uid) { 725 enforceCallingPermission(); 726 synchronized (mStats) { 727 mStats.noteFullWifiLockReleasedLocked(uid); 728 } 729 } 730 731 public void noteWifiScanStarted(int uid) { 732 enforceCallingPermission(); 733 synchronized (mStats) { 734 mStats.noteWifiScanStartedLocked(uid); 735 } 736 } 737 738 public void noteWifiScanStopped(int uid) { 739 enforceCallingPermission(); 740 synchronized (mStats) { 741 mStats.noteWifiScanStoppedLocked(uid); 742 } 743 } 744 745 public void noteWifiMulticastEnabled(int uid) { 746 enforceCallingPermission(); 747 synchronized (mStats) { 748 mStats.noteWifiMulticastEnabledLocked(uid); 749 } 750 } 751 752 public void noteWifiMulticastDisabled(int uid) { 753 enforceCallingPermission(); 754 synchronized (mStats) { 755 mStats.noteWifiMulticastDisabledLocked(uid); 756 } 757 } 758 759 public void noteFullWifiLockAcquiredFromSource(WorkSource ws) { 760 enforceCallingPermission(); 761 synchronized (mStats) { 762 mStats.noteFullWifiLockAcquiredFromSourceLocked(ws); 763 } 764 } 765 766 public void noteFullWifiLockReleasedFromSource(WorkSource ws) { 767 enforceCallingPermission(); 768 synchronized (mStats) { 769 mStats.noteFullWifiLockReleasedFromSourceLocked(ws); 770 } 771 } 772 773 public void noteWifiScanStartedFromSource(WorkSource ws) { 774 enforceCallingPermission(); 775 synchronized (mStats) { 776 mStats.noteWifiScanStartedFromSourceLocked(ws); 777 } 778 } 779 780 public void noteWifiScanStoppedFromSource(WorkSource ws) { 781 enforceCallingPermission(); 782 synchronized (mStats) { 783 mStats.noteWifiScanStoppedFromSourceLocked(ws); 784 } 785 } 786 787 public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) { 788 enforceCallingPermission(); 789 synchronized (mStats) { 790 mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph); 791 } 792 } 793 794 public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) { 795 enforceCallingPermission(); 796 synchronized (mStats) { 797 mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws); 798 } 799 } 800 801 public void noteWifiMulticastEnabledFromSource(WorkSource ws) { 802 enforceCallingPermission(); 803 synchronized (mStats) { 804 mStats.noteWifiMulticastEnabledFromSourceLocked(ws); 805 } 806 } 807 808 @Override 809 public void noteWifiMulticastDisabledFromSource(WorkSource ws) { 810 enforceCallingPermission(); 811 synchronized (mStats) { 812 mStats.noteWifiMulticastDisabledFromSourceLocked(ws); 813 } 814 } 815 816 @Override 817 public void noteNetworkInterfaceType(String iface, int networkType) { 818 enforceCallingPermission(); 819 synchronized (mStats) { 820 mStats.noteNetworkInterfaceTypeLocked(iface, networkType); 821 } 822 } 823 824 @Override 825 public void noteNetworkStatsEnabled() { 826 enforceCallingPermission(); 827 synchronized (mStats) { 828 mStats.noteNetworkStatsEnabledLocked(); 829 } 830 } 831 832 @Override 833 public void noteDeviceIdleMode(int mode, String activeReason, int activeUid) { 834 enforceCallingPermission(); 835 synchronized (mStats) { 836 mStats.noteDeviceIdleModeLocked(mode, activeReason, activeUid); 837 } 838 } 839 840 public void notePackageInstalled(String pkgName, int versionCode) { 841 enforceCallingPermission(); 842 synchronized (mStats) { 843 mStats.notePackageInstalledLocked(pkgName, versionCode); 844 } 845 } 846 847 public void notePackageUninstalled(String pkgName) { 848 enforceCallingPermission(); 849 synchronized (mStats) { 850 mStats.notePackageUninstalledLocked(pkgName); 851 } 852 } 853 854 @Override 855 public void noteBleScanStarted(WorkSource ws) { 856 enforceCallingPermission(); 857 synchronized (mStats) { 858 mStats.noteBluetoothScanStartedFromSourceLocked(ws); 859 } 860 } 861 862 @Override 863 public void noteBleScanStopped(WorkSource ws) { 864 enforceCallingPermission(); 865 synchronized (mStats) { 866 mStats.noteBluetoothScanStoppedFromSourceLocked(ws); 867 } 868 } 869 870 @Override 871 public void noteResetBleScan() { 872 enforceCallingPermission(); 873 synchronized (mStats) { 874 mStats.noteResetBluetoothScanLocked(); 875 } 876 } 877 878 public boolean isOnBattery() { 879 return mStats.isOnBattery(); 880 } 881 882 @Override 883 public void setBatteryState(final int status, final int health, final int plugType, 884 final int level, final int temp, final int volt) { 885 enforceCallingPermission(); 886 887 // BatteryService calls us here and we may update external state. It would be wrong 888 // to block such a low level service like BatteryService on external stats like WiFi. 889 mHandler.post(new Runnable() { 890 @Override 891 public void run() { 892 synchronized (mStats) { 893 final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE; 894 if (mStats.isOnBattery() == onBattery) { 895 // The battery state has not changed, so we don't need to sync external 896 // stats immediately. 897 mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt); 898 return; 899 } 900 } 901 902 // Sync external stats first as the battery has changed states. If we don't sync 903 // immediately here, we may not collect the relevant data later. 904 updateExternalStats("battery-state", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL); 905 synchronized (mStats) { 906 mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt); 907 } 908 } 909 }); 910 } 911 912 public long getAwakeTimeBattery() { 913 mContext.enforceCallingOrSelfPermission( 914 android.Manifest.permission.BATTERY_STATS, null); 915 return mStats.getAwakeTimeBattery(); 916 } 917 918 public long getAwakeTimePlugged() { 919 mContext.enforceCallingOrSelfPermission( 920 android.Manifest.permission.BATTERY_STATS, null); 921 return mStats.getAwakeTimePlugged(); 922 } 923 924 public void enforceCallingPermission() { 925 if (Binder.getCallingPid() == Process.myPid()) { 926 return; 927 } 928 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS, 929 Binder.getCallingPid(), Binder.getCallingUid(), null); 930 } 931 932 final class WakeupReasonThread extends Thread { 933 private static final int MAX_REASON_SIZE = 512; 934 private CharsetDecoder mDecoder; 935 private ByteBuffer mUtf8Buffer; 936 private CharBuffer mUtf16Buffer; 937 938 WakeupReasonThread() { 939 super("BatteryStats_wakeupReason"); 940 } 941 942 public void run() { 943 Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND); 944 945 mDecoder = StandardCharsets.UTF_8 946 .newDecoder() 947 .onMalformedInput(CodingErrorAction.REPLACE) 948 .onUnmappableCharacter(CodingErrorAction.REPLACE) 949 .replaceWith("?"); 950 951 mUtf8Buffer = ByteBuffer.allocateDirect(MAX_REASON_SIZE); 952 mUtf16Buffer = CharBuffer.allocate(MAX_REASON_SIZE); 953 954 try { 955 String reason; 956 while ((reason = waitWakeup()) != null) { 957 synchronized (mStats) { 958 mStats.noteWakeupReasonLocked(reason); 959 } 960 } 961 } catch (RuntimeException e) { 962 Slog.e(TAG, "Failure reading wakeup reasons", e); 963 } 964 } 965 966 private String waitWakeup() { 967 mUtf8Buffer.clear(); 968 mUtf16Buffer.clear(); 969 mDecoder.reset(); 970 971 int bytesWritten = nativeWaitWakeup(mUtf8Buffer); 972 if (bytesWritten < 0) { 973 return null; 974 } else if (bytesWritten == 0) { 975 return "unknown"; 976 } 977 978 // Set the buffer's limit to the number of bytes written. 979 mUtf8Buffer.limit(bytesWritten); 980 981 // Decode the buffer from UTF-8 to UTF-16. 982 // Unmappable characters will be replaced. 983 mDecoder.decode(mUtf8Buffer, mUtf16Buffer, true); 984 mUtf16Buffer.flip(); 985 986 // Create a String from the UTF-16 buffer. 987 return mUtf16Buffer.toString(); 988 } 989 } 990 991 private static native int nativeWaitWakeup(ByteBuffer outBuffer); 992 993 private void dumpHelp(PrintWriter pw) { 994 pw.println("Battery stats (batterystats) dump options:"); 995 pw.println(" [--checkin] [--history] [--history-start] [--charged] [-c]"); 996 pw.println(" [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]"); 997 pw.println(" --checkin: generate output for a checkin report; will write (and clear) the"); 998 pw.println(" last old completed stats when they had been reset."); 999 pw.println(" --c: write the current stats in checkin format."); 1000 pw.println(" --history: show only history data."); 1001 pw.println(" --history-start <num>: show only history data starting at given time offset."); 1002 pw.println(" --charged: only output data since last charged."); 1003 pw.println(" --daily: only output full daily data."); 1004 pw.println(" --reset: reset the stats, clearing all current data."); 1005 pw.println(" --write: force write current collected stats to disk."); 1006 pw.println(" --new-daily: immediately create and write new daily stats record."); 1007 pw.println(" --read-daily: read-load last written daily stats."); 1008 pw.println(" <package.name>: optional name of package to filter output by."); 1009 pw.println(" -h: print this help text."); 1010 pw.println("Battery stats (batterystats) commands:"); 1011 pw.println(" enable|disable <option>"); 1012 pw.println(" Enable or disable a running option. Option state is not saved across boots."); 1013 pw.println(" Options are:"); 1014 pw.println(" full-history: include additional detailed events in battery history:"); 1015 pw.println(" wake_lock_in, alarms and proc events"); 1016 pw.println(" no-auto-reset: don't automatically reset stats when unplugged"); 1017 } 1018 1019 private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) { 1020 i++; 1021 if (i >= args.length) { 1022 pw.println("Missing option argument for " + (enable ? "--enable" : "--disable")); 1023 dumpHelp(pw); 1024 return -1; 1025 } 1026 if ("full-wake-history".equals(args[i]) || "full-history".equals(args[i])) { 1027 synchronized (mStats) { 1028 mStats.setRecordAllHistoryLocked(enable); 1029 } 1030 } else if ("no-auto-reset".equals(args[i])) { 1031 synchronized (mStats) { 1032 mStats.setNoAutoReset(enable); 1033 } 1034 } else { 1035 pw.println("Unknown enable/disable option: " + args[i]); 1036 dumpHelp(pw); 1037 return -1; 1038 } 1039 return i; 1040 } 1041 1042 1043 @Override 1044 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1045 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1046 != PackageManager.PERMISSION_GRANTED) { 1047 pw.println("Permission Denial: can't dump BatteryStats from from pid=" 1048 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 1049 + " without permission " + android.Manifest.permission.DUMP); 1050 return; 1051 } 1052 1053 int flags = 0; 1054 boolean useCheckinFormat = false; 1055 boolean isRealCheckin = false; 1056 boolean noOutput = false; 1057 boolean writeData = false; 1058 long historyStart = -1; 1059 int reqUid = -1; 1060 if (args != null) { 1061 for (int i=0; i<args.length; i++) { 1062 String arg = args[i]; 1063 if ("--checkin".equals(arg)) { 1064 useCheckinFormat = true; 1065 isRealCheckin = true; 1066 } else if ("--history".equals(arg)) { 1067 flags |= BatteryStats.DUMP_HISTORY_ONLY; 1068 } else if ("--history-start".equals(arg)) { 1069 flags |= BatteryStats.DUMP_HISTORY_ONLY; 1070 i++; 1071 if (i >= args.length) { 1072 pw.println("Missing time argument for --history-since"); 1073 dumpHelp(pw); 1074 return; 1075 } 1076 historyStart = Long.parseLong(args[i]); 1077 writeData = true; 1078 } else if ("-c".equals(arg)) { 1079 useCheckinFormat = true; 1080 flags |= BatteryStats.DUMP_INCLUDE_HISTORY; 1081 } else if ("--charged".equals(arg)) { 1082 flags |= BatteryStats.DUMP_CHARGED_ONLY; 1083 } else if ("--daily".equals(arg)) { 1084 flags |= BatteryStats.DUMP_DAILY_ONLY; 1085 } else if ("--reset".equals(arg)) { 1086 synchronized (mStats) { 1087 mStats.resetAllStatsCmdLocked(); 1088 pw.println("Battery stats reset."); 1089 noOutput = true; 1090 } 1091 updateExternalStats("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL); 1092 } else if ("--write".equals(arg)) { 1093 updateExternalStats("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL); 1094 synchronized (mStats) { 1095 mStats.writeSyncLocked(); 1096 pw.println("Battery stats written."); 1097 noOutput = true; 1098 } 1099 } else if ("--new-daily".equals(arg)) { 1100 synchronized (mStats) { 1101 mStats.recordDailyStatsLocked(); 1102 pw.println("New daily stats written."); 1103 noOutput = true; 1104 } 1105 } else if ("--read-daily".equals(arg)) { 1106 synchronized (mStats) { 1107 mStats.readDailyStatsLocked(); 1108 pw.println("Last daily stats read."); 1109 noOutput = true; 1110 } 1111 } else if ("--enable".equals(arg) || "enable".equals(arg)) { 1112 i = doEnableOrDisable(pw, i, args, true); 1113 if (i < 0) { 1114 return; 1115 } 1116 pw.println("Enabled: " + args[i]); 1117 return; 1118 } else if ("--disable".equals(arg) || "disable".equals(arg)) { 1119 i = doEnableOrDisable(pw, i, args, false); 1120 if (i < 0) { 1121 return; 1122 } 1123 pw.println("Disabled: " + args[i]); 1124 return; 1125 } else if ("-h".equals(arg)) { 1126 dumpHelp(pw); 1127 return; 1128 } else if ("-a".equals(arg)) { 1129 flags |= BatteryStats.DUMP_VERBOSE; 1130 } else if (arg.length() > 0 && arg.charAt(0) == '-'){ 1131 pw.println("Unknown option: " + arg); 1132 dumpHelp(pw); 1133 return; 1134 } else { 1135 // Not an option, last argument must be a package name. 1136 try { 1137 reqUid = mContext.getPackageManager().getPackageUidAsUser(arg, 1138 UserHandle.getCallingUserId()); 1139 } catch (PackageManager.NameNotFoundException e) { 1140 pw.println("Unknown package: " + arg); 1141 dumpHelp(pw); 1142 return; 1143 } 1144 } 1145 } 1146 } 1147 if (noOutput) { 1148 return; 1149 } 1150 1151 long ident = Binder.clearCallingIdentity(); 1152 try { 1153 if (BatteryStatsHelper.checkWifiOnly(mContext)) { 1154 flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY; 1155 } 1156 // Fetch data from external sources and update the BatteryStatsImpl object with them. 1157 updateExternalStats("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL); 1158 } finally { 1159 Binder.restoreCallingIdentity(ident); 1160 } 1161 1162 if (reqUid >= 0) { 1163 // By default, if the caller is only interested in a specific package, then 1164 // we only dump the aggregated data since charged. 1165 if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_CHARGED_ONLY)) == 0) { 1166 flags |= BatteryStats.DUMP_CHARGED_ONLY; 1167 // Also if they are doing -c, we don't want history. 1168 flags &= ~BatteryStats.DUMP_INCLUDE_HISTORY; 1169 } 1170 } 1171 1172 if (useCheckinFormat) { 1173 List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications( 1174 PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_ALL); 1175 if (isRealCheckin) { 1176 // For a real checkin, first we want to prefer to use the last complete checkin 1177 // file if there is one. 1178 synchronized (mStats.mCheckinFile) { 1179 if (mStats.mCheckinFile.exists()) { 1180 try { 1181 byte[] raw = mStats.mCheckinFile.readFully(); 1182 if (raw != null) { 1183 Parcel in = Parcel.obtain(); 1184 in.unmarshall(raw, 0, raw.length); 1185 in.setDataPosition(0); 1186 BatteryStatsImpl checkinStats = new BatteryStatsImpl( 1187 null, mStats.mHandler, null); 1188 checkinStats.readSummaryFromParcel(in); 1189 in.recycle(); 1190 checkinStats.dumpCheckinLocked(mContext, pw, apps, flags, 1191 historyStart); 1192 mStats.mCheckinFile.delete(); 1193 return; 1194 } 1195 } catch (IOException | ParcelFormatException e) { 1196 Slog.w(TAG, "Failure reading checkin file " 1197 + mStats.mCheckinFile.getBaseFile(), e); 1198 } 1199 } 1200 } 1201 } 1202 synchronized (mStats) { 1203 mStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart); 1204 if (writeData) { 1205 mStats.writeAsyncLocked(); 1206 } 1207 } 1208 } else { 1209 synchronized (mStats) { 1210 mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart); 1211 if (writeData) { 1212 mStats.writeAsyncLocked(); 1213 } 1214 } 1215 } 1216 } 1217 1218 // Objects for extracting data from external sources. 1219 private final Object mExternalStatsLock = new Object(); 1220 1221 @GuardedBy("mExternalStatsLock") 1222 private IWifiManager mWifiManager; 1223 1224 // WiFi keeps an accumulated total of stats, unlike Bluetooth. 1225 // Keep the last WiFi stats so we can compute a delta. 1226 @GuardedBy("mExternalStatsLock") 1227 private WifiActivityEnergyInfo mLastInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0); 1228 1229 @GuardedBy("mExternalStatsLock") 1230 private WifiActivityEnergyInfo pullWifiEnergyInfoLocked() { 1231 if (mWifiManager == null) { 1232 mWifiManager = IWifiManager.Stub.asInterface( 1233 ServiceManager.getService(Context.WIFI_SERVICE)); 1234 if (mWifiManager == null) { 1235 return null; 1236 } 1237 } 1238 1239 try { 1240 // We read the data even if we are not on battery. This is so that we keep the 1241 // correct delta from when we should start reading (aka when we are on battery). 1242 WifiActivityEnergyInfo info = mWifiManager.reportActivityInfo(); 1243 if (info != null && info.isValid()) { 1244 if (info.mControllerEnergyUsed < 0 || info.mControllerIdleTimeMs < 0 || 1245 info.mControllerRxTimeMs < 0 || info.mControllerTxTimeMs < 0) { 1246 Slog.wtf(TAG, "Reported WiFi energy data is invalid: " + info); 1247 return null; 1248 } 1249 1250 final long timePeriodMs = info.mTimestamp - mLastInfo.mTimestamp; 1251 final long lastIdleMs = mLastInfo.mControllerIdleTimeMs; 1252 final long lastTxMs = mLastInfo.mControllerTxTimeMs; 1253 final long lastRxMs = mLastInfo.mControllerRxTimeMs; 1254 final long lastEnergy = mLastInfo.mControllerEnergyUsed; 1255 1256 // We will modify the last info object to be the delta, and store the new 1257 // WifiActivityEnergyInfo object as our last one. 1258 final WifiActivityEnergyInfo result = mLastInfo; 1259 result.mTimestamp = info.getTimeStamp(); 1260 result.mStackState = info.getStackState(); 1261 1262 // These times seem to be the most reliable. 1263 result.mControllerTxTimeMs = info.mControllerTxTimeMs - lastTxMs; 1264 result.mControllerRxTimeMs = info.mControllerRxTimeMs - lastRxMs; 1265 1266 // WiFi calculates the idle time as a difference from the on time and the various 1267 // Rx + Tx times. There seems to be some missing time there because this sometimes 1268 // becomes negative. Just cap it at 0 and move on. 1269 // b/21613534 1270 result.mControllerIdleTimeMs = Math.max(0, info.mControllerIdleTimeMs - lastIdleMs); 1271 result.mControllerEnergyUsed = 1272 Math.max(0, info.mControllerEnergyUsed - lastEnergy); 1273 1274 if (result.mControllerTxTimeMs < 0 || 1275 result.mControllerRxTimeMs < 0) { 1276 // The stats were reset by the WiFi system (which is why our delta is negative). 1277 // Returns the unaltered stats. 1278 result.mControllerEnergyUsed = info.mControllerEnergyUsed; 1279 result.mControllerRxTimeMs = info.mControllerRxTimeMs; 1280 result.mControllerTxTimeMs = info.mControllerTxTimeMs; 1281 result.mControllerIdleTimeMs = info.mControllerIdleTimeMs; 1282 1283 Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + result); 1284 } 1285 1286 // There is some accuracy error in reports so allow some slop in the results. 1287 final long SAMPLE_ERROR_MILLIS = 750; 1288 final long totalTimeMs = result.mControllerIdleTimeMs + result.mControllerRxTimeMs + 1289 result.mControllerTxTimeMs; 1290 if (totalTimeMs > timePeriodMs + SAMPLE_ERROR_MILLIS) { 1291 StringBuilder sb = new StringBuilder(); 1292 sb.append("Total time "); 1293 TimeUtils.formatDuration(totalTimeMs, sb); 1294 sb.append(" is longer than sample period "); 1295 TimeUtils.formatDuration(timePeriodMs, sb); 1296 sb.append(".\n"); 1297 sb.append("Previous WiFi snapshot: ").append("idle="); 1298 TimeUtils.formatDuration(lastIdleMs, sb); 1299 sb.append(" rx="); 1300 TimeUtils.formatDuration(lastRxMs, sb); 1301 sb.append(" tx="); 1302 TimeUtils.formatDuration(lastTxMs, sb); 1303 sb.append(" e=").append(lastEnergy); 1304 sb.append("\n"); 1305 sb.append("Current WiFi snapshot: ").append("idle="); 1306 TimeUtils.formatDuration(info.mControllerIdleTimeMs, sb); 1307 sb.append(" rx="); 1308 TimeUtils.formatDuration(info.mControllerRxTimeMs, sb); 1309 sb.append(" tx="); 1310 TimeUtils.formatDuration(info.mControllerTxTimeMs, sb); 1311 sb.append(" e=").append(info.mControllerEnergyUsed); 1312 Slog.wtf(TAG, sb.toString()); 1313 } 1314 1315 mLastInfo = info; 1316 return result; 1317 } 1318 } catch (RemoteException e) { 1319 // Nothing to report, WiFi is dead. 1320 } 1321 return null; 1322 } 1323 1324 @GuardedBy("mExternalStatsLock") 1325 private BluetoothActivityEnergyInfo pullBluetoothEnergyInfoLocked() { 1326 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1327 if (adapter != null) { 1328 BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo( 1329 BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED); 1330 if (info != null && info.isValid()) { 1331 if (info.getControllerEnergyUsed() < 0 || info.getControllerIdleTimeMillis() < 0 || 1332 info.getControllerRxTimeMillis() < 0 || info.getControllerTxTimeMillis() < 0) { 1333 Slog.wtf(TAG, "Bluetooth energy data is invalid: " + info); 1334 } 1335 return info; 1336 } 1337 } 1338 return null; 1339 } 1340 1341 @GuardedBy("mExternalStatsLock") 1342 private ModemActivityInfo pullModemActivityInfoLocked() { 1343 ITelephony tm = ITelephony.Stub.asInterface(ServiceManager.getService( 1344 Context.TELEPHONY_SERVICE)); 1345 try { 1346 if (tm != null) { 1347 ModemActivityInfo info = tm.getModemActivityInfo(); 1348 if (info == null || info.isValid()) { 1349 return info; 1350 } 1351 Slog.wtf(TAG, "Modem activity info is invalid: " + info); 1352 } 1353 } catch (RemoteException e) { 1354 // Nothing to do. 1355 } 1356 return null; 1357 } 1358 1359 /** 1360 * Fetches data from external sources (WiFi controller, bluetooth chipset) and updates 1361 * batterystats with that information. 1362 * 1363 * We first grab a lock specific to this method, then once all the data has been collected, 1364 * we grab the mStats lock and update the data. 1365 * 1366 * @param reason The reason why this collection was requested. Useful for debugging. 1367 * @param updateFlags Which external stats to update. Can be a combination of 1368 * {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_CPU}, 1369 * {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_RADIO}, 1370 * {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_WIFI}, 1371 * and {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_BT}. 1372 */ 1373 void updateExternalStats(final String reason, final int updateFlags) { 1374 synchronized (mExternalStatsLock) { 1375 if (mContext == null) { 1376 // We haven't started yet (which means the BatteryStatsImpl object has 1377 // no power profile. Don't consume data we can't compute yet. 1378 return; 1379 } 1380 1381 if (BatteryStatsImpl.DEBUG_ENERGY) { 1382 Slog.d(TAG, "Updating external stats: reason=" + reason); 1383 } 1384 1385 WifiActivityEnergyInfo wifiEnergyInfo = null; 1386 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) { 1387 wifiEnergyInfo = pullWifiEnergyInfoLocked(); 1388 } 1389 1390 ModemActivityInfo modemActivityInfo = null; 1391 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) { 1392 modemActivityInfo = pullModemActivityInfoLocked(); 1393 } 1394 1395 BluetoothActivityEnergyInfo bluetoothEnergyInfo = null; 1396 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_BT) != 0) { 1397 // We only pull bluetooth stats when we have to, as we are not distributing its 1398 // use amongst apps and the sampling frequency does not matter. 1399 bluetoothEnergyInfo = pullBluetoothEnergyInfoLocked(); 1400 } 1401 1402 synchronized (mStats) { 1403 final long elapsedRealtime = SystemClock.elapsedRealtime(); 1404 final long uptime = SystemClock.uptimeMillis(); 1405 if (mStats.mRecordAllHistory) { 1406 mStats.addHistoryEventLocked(elapsedRealtime, uptime, 1407 BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS, reason, 0); 1408 } 1409 1410 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_CPU) != 0) { 1411 mStats.updateCpuTimeLocked(); 1412 mStats.updateKernelWakelocksLocked(); 1413 } 1414 1415 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) { 1416 mStats.updateMobileRadioStateLocked(elapsedRealtime, modemActivityInfo); 1417 } 1418 1419 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) { 1420 mStats.updateWifiStateLocked(wifiEnergyInfo); 1421 } 1422 1423 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_BT) != 0) { 1424 mStats.updateBluetoothStateLocked(bluetoothEnergyInfo); 1425 } 1426 } 1427 } 1428 } 1429 1430 /** 1431 * Gets a snapshot of the system health for a particular uid. 1432 */ 1433 @Override 1434 public HealthStatsParceler takeUidSnapshot(int requestUid) { 1435 if (requestUid != Binder.getCallingUid()) { 1436 mContext.enforceCallingOrSelfPermission( 1437 android.Manifest.permission.BATTERY_STATS, null); 1438 } 1439 long ident = Binder.clearCallingIdentity(); 1440 try { 1441 updateExternalStats("get-health-stats-for-uid", 1442 BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL); 1443 synchronized (mStats) { 1444 return getHealthStatsForUidLocked(requestUid); 1445 } 1446 } catch (Exception ex) { 1447 Slog.d(TAG, "Crashed while writing for takeUidSnapshot(" + requestUid + ")", ex); 1448 throw ex; 1449 } finally { 1450 Binder.restoreCallingIdentity(ident); 1451 } 1452 } 1453 1454 /** 1455 * Gets a snapshot of the system health for a number of uids. 1456 */ 1457 @Override 1458 public HealthStatsParceler[] takeUidSnapshots(int[] requestUids) { 1459 if (!onlyCaller(requestUids)) { 1460 mContext.enforceCallingOrSelfPermission( 1461 android.Manifest.permission.BATTERY_STATS, null); 1462 } 1463 long ident = Binder.clearCallingIdentity(); 1464 int i=-1; 1465 try { 1466 updateExternalStats("get-health-stats-for-uids", 1467 BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL); 1468 synchronized (mStats) { 1469 final int N = requestUids.length; 1470 final HealthStatsParceler[] results = new HealthStatsParceler[N]; 1471 for (i=0; i<N; i++) { 1472 results[i] = getHealthStatsForUidLocked(requestUids[i]); 1473 } 1474 return results; 1475 } 1476 } catch (Exception ex) { 1477 Slog.d(TAG, "Crashed while writing for takeUidSnapshots(" 1478 + Arrays.toString(requestUids) + ") i=" + i, ex); 1479 throw ex; 1480 } finally { 1481 Binder.restoreCallingIdentity(ident); 1482 } 1483 } 1484 1485 /** 1486 * Returns whether the Binder.getCallingUid is the only thing in requestUids. 1487 */ 1488 private static boolean onlyCaller(int[] requestUids) { 1489 final int caller = Binder.getCallingUid(); 1490 final int N = requestUids.length; 1491 for (int i=0; i<N; i++) { 1492 if (requestUids[i] != caller) { 1493 return false; 1494 } 1495 } 1496 return true; 1497 } 1498 1499 /** 1500 * Gets a HealthStatsParceler for the given uid. You should probably call 1501 * updateExternalStats first. 1502 */ 1503 HealthStatsParceler getHealthStatsForUidLocked(int requestUid) { 1504 final HealthStatsBatteryStatsWriter writer = new HealthStatsBatteryStatsWriter(); 1505 final HealthStatsWriter uidWriter = new HealthStatsWriter(UidHealthStats.CONSTANTS); 1506 final BatteryStats.Uid uid = mStats.getUidStats().get(requestUid); 1507 if (uid != null) { 1508 writer.writeUid(uidWriter, mStats, uid); 1509 } 1510 return new HealthStatsParceler(uidWriter); 1511 } 1512 1513} 1514