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