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