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