2 * Copyright (C) 2006-2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.am;
19 import android.bluetooth.BluetoothActivityEnergyInfo;
20 import android.bluetooth.BluetoothAdapter;
21 import android.content.Context;
22 import android.content.pm.ApplicationInfo;
23 import android.content.pm.PackageManager;
24 import android.net.wifi.IWifiManager;
25 import android.net.wifi.WifiActivityEnergyInfo;
26 import android.os.BatteryStats;
27 import android.os.Binder;
28 import android.os.Handler;
29 import android.os.IBinder;
30 import android.os.Looper;
31 import android.os.Message;
32 import android.os.Parcel;
33 import android.os.ParcelFileDescriptor;
34 import android.os.ParcelFormatException;
35 import android.os.PowerManager;
36 import android.os.PowerManagerInternal;
37 import android.os.Process;
38 import android.os.RemoteException;
39 import android.os.ServiceManager;
40 import android.os.SystemClock;
41 import android.os.UserHandle;
42 import android.os.WorkSource;
43 import android.os.health.HealthStatsParceler;
44 import android.os.health.HealthStatsWriter;
45 import android.os.health.UidHealthStats;
46 import android.telephony.DataConnectionRealTimeInfo;
47 import android.telephony.ModemActivityInfo;
48 import android.telephony.SignalStrength;
49 import android.telephony.TelephonyManager;
50 import android.util.IntArray;
51 import android.util.Slog;
53 import android.util.TimeUtils;
54 import com.android.internal.annotations.GuardedBy;
55 import com.android.internal.app.IBatteryStats;
56 import com.android.internal.os.BatteryStatsHelper;
57 import com.android.internal.os.BatteryStatsImpl;
58 import com.android.internal.os.PowerProfile;
59 import com.android.internal.telephony.ITelephony;
60 import com.android.server.FgThread;
61 import com.android.server.LocalServices;
64 import java.io.FileDescriptor;
65 import java.io.IOException;
66 import java.io.PrintWriter;
67 import java.nio.ByteBuffer;
68 import java.nio.CharBuffer;
69 import java.nio.charset.CharsetDecoder;
70 import java.nio.charset.CodingErrorAction;
71 import java.nio.charset.StandardCharsets;
72 import java.util.Arrays;
73 import java.util.List;
77 * All information we are collecting about things that can happen that impact
80 public final class BatteryStatsService extends IBatteryStats.Stub
81 implements PowerManagerInternal.LowPowerModeListener {
82 static final String TAG = "BatteryStatsService";
84 static IBatteryStats sService;
85 final BatteryStatsImpl mStats;
86 final BatteryStatsHandler mHandler;
88 PowerManagerInternal mPowerManagerInternal;
90 class BatteryStatsHandler extends Handler implements BatteryStatsImpl.ExternalStatsSync {
91 public static final int MSG_SYNC_EXTERNAL_STATS = 1;
92 public static final int MSG_WRITE_TO_DISK = 2;
93 private int mUpdateFlags = 0;
94 private IntArray mUidsToRemove = new IntArray();
96 public BatteryStatsHandler(Looper looper) {
101 public void handleMessage(Message msg) {
103 case MSG_SYNC_EXTERNAL_STATS:
104 final int updateFlags;
105 synchronized (this) {
106 removeMessages(MSG_SYNC_EXTERNAL_STATS);
107 updateFlags = mUpdateFlags;
110 updateExternalStats((String)msg.obj, updateFlags);
112 // other parts of the system could be calling into us
113 // from mStats in order to report of changes. We must grab the mStats
114 // lock before grabbing our own or we'll end up in a deadlock.
115 synchronized (mStats) {
116 synchronized (this) {
117 final int numUidsToRemove = mUidsToRemove.size();
118 for (int i = 0; i < numUidsToRemove; i++) {
119 mStats.removeIsolatedUidLocked(mUidsToRemove.get(i));
122 mUidsToRemove.clear();
126 case MSG_WRITE_TO_DISK:
127 updateExternalStats("write", UPDATE_ALL);
128 synchronized (mStats) {
129 mStats.writeAsyncLocked();
136 public void scheduleSync(String reason, int updateFlags) {
137 synchronized (this) {
138 scheduleSyncLocked(reason, updateFlags);
143 public void scheduleCpuSyncDueToRemovedUid(int uid) {
144 synchronized (this) {
145 scheduleSyncLocked("remove-uid", UPDATE_CPU);
146 mUidsToRemove.add(uid);
150 private void scheduleSyncLocked(String reason, int updateFlags) {
151 if (mUpdateFlags == 0) {
152 sendMessage(Message.obtain(this, MSG_SYNC_EXTERNAL_STATS, reason));
154 mUpdateFlags |= updateFlags;
158 BatteryStatsService(File systemDir, Handler handler) {
159 // Our handler here will be accessing the disk, use a different thread than
160 // what the ActivityManagerService gave us (no I/O on that one!).
161 mHandler = new BatteryStatsHandler(FgThread.getHandler().getLooper());
163 // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
164 mStats = new BatteryStatsImpl(systemDir, handler, mHandler);
167 public void publish(Context context) {
169 mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
170 com.android.internal.R.integer.config_radioScanningTimeout)
172 mStats.setPowerProfile(new PowerProfile(context));
173 ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
177 * At the time when the constructor runs, the power manager has not yet been
178 * initialized. So we initialize the low power observer later.
180 public void initPowerManagement() {
181 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
182 mPowerManagerInternal.registerLowPowerModeObserver(this);
183 mStats.notePowerSaveMode(mPowerManagerInternal.getLowPowerModeEnabled());
184 (new WakeupReasonThread()).start();
187 public void shutdown() {
188 Slog.w("BatteryStats", "Writing battery stats before shutdown...");
190 updateExternalStats("shutdown", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
191 synchronized (mStats) {
192 mStats.shutdownLocked();
196 public static IBatteryStats getService() {
197 if (sService != null) {
200 IBinder b = ServiceManager.getService(BatteryStats.SERVICE_NAME);
201 sService = asInterface(b);
206 public void onLowPowerModeChanged(boolean enabled) {
207 synchronized (mStats) {
208 mStats.notePowerSaveMode(enabled);
213 * @return the current statistics object, which may be modified
214 * to reflect events that affect battery usage. You must lock the
215 * stats object before doing anything with it.
217 public BatteryStatsImpl getActiveStatistics() {
222 * Schedules a write to disk to occur. This will cause the BatteryStatsImpl
223 * object to update with the latest info, then write to disk.
225 public void scheduleWriteToDisk() {
226 mHandler.sendEmptyMessage(BatteryStatsHandler.MSG_WRITE_TO_DISK);
229 // These are for direct use by the activity manager...
232 * Remove a UID from the BatteryStats and BatteryStats' external dependencies.
234 void removeUid(int uid) {
235 synchronized (mStats) {
236 mStats.removeUidStatsLocked(uid);
240 void addIsolatedUid(int isolatedUid, int appUid) {
241 synchronized (mStats) {
242 mStats.addIsolatedUidLocked(isolatedUid, appUid);
246 void removeIsolatedUid(int isolatedUid, int appUid) {
247 synchronized (mStats) {
248 mStats.scheduleRemoveIsolatedUidLocked(isolatedUid, appUid);
252 void noteProcessStart(String name, int uid) {
253 synchronized (mStats) {
254 mStats.noteProcessStartLocked(name, uid);
258 void noteProcessCrash(String name, int uid) {
259 synchronized (mStats) {
260 mStats.noteProcessCrashLocked(name, uid);
264 void noteProcessAnr(String name, int uid) {
265 synchronized (mStats) {
266 mStats.noteProcessAnrLocked(name, uid);
270 void noteProcessFinish(String name, int uid) {
271 synchronized (mStats) {
272 mStats.noteProcessFinishLocked(name, uid);
276 void noteUidProcessState(int uid, int state) {
277 synchronized (mStats) {
278 mStats.noteUidProcessStateLocked(uid, state);
282 // Public interface...
284 public byte[] getStatistics() {
285 mContext.enforceCallingPermission(
286 android.Manifest.permission.BATTERY_STATS, null);
287 //Slog.i("foo", "SENDING BATTERY INFO:");
288 //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
289 Parcel out = Parcel.obtain();
290 updateExternalStats("get-stats", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
291 synchronized (mStats) {
292 mStats.writeToParcel(out, 0);
294 byte[] data = out.marshall();
299 public ParcelFileDescriptor getStatisticsStream() {
300 mContext.enforceCallingPermission(
301 android.Manifest.permission.BATTERY_STATS, null);
302 //Slog.i("foo", "SENDING BATTERY INFO:");
303 //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
304 Parcel out = Parcel.obtain();
305 updateExternalStats("get-stats", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
306 synchronized (mStats) {
307 mStats.writeToParcel(out, 0);
309 byte[] data = out.marshall();
312 return ParcelFileDescriptor.fromData(data, "battery-stats");
313 } catch (IOException e) {
314 Slog.w(TAG, "Unable to create shared memory", e);
319 public boolean isCharging() {
320 synchronized (mStats) {
321 return mStats.isCharging();
325 public long computeBatteryTimeRemaining() {
326 synchronized (mStats) {
327 long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
328 return time >= 0 ? (time/1000) : time;
332 public long computeChargeTimeRemaining() {
333 synchronized (mStats) {
334 long time = mStats.computeChargeTimeRemaining(SystemClock.elapsedRealtime());
335 return time >= 0 ? (time/1000) : time;
339 public void noteEvent(int code, String name, int uid) {
340 enforceCallingPermission();
341 synchronized (mStats) {
342 mStats.noteEventLocked(code, name, uid);
346 public void noteSyncStart(String name, int uid) {
347 enforceCallingPermission();
348 synchronized (mStats) {
349 mStats.noteSyncStartLocked(name, uid);
353 public void noteSyncFinish(String name, int uid) {
354 enforceCallingPermission();
355 synchronized (mStats) {
356 mStats.noteSyncFinishLocked(name, uid);
360 public void noteJobStart(String name, int uid) {
361 enforceCallingPermission();
362 synchronized (mStats) {
363 mStats.noteJobStartLocked(name, uid);
367 public void noteJobFinish(String name, int uid) {
368 enforceCallingPermission();
369 synchronized (mStats) {
370 mStats.noteJobFinishLocked(name, uid);
374 public void noteAlarmStart(String name, int uid) {
375 enforceCallingPermission();
376 synchronized (mStats) {
377 mStats.noteAlarmStartLocked(name, uid);
381 public void noteAlarmFinish(String name, int uid) {
382 enforceCallingPermission();
383 synchronized (mStats) {
384 mStats.noteAlarmFinishLocked(name, uid);
388 public void noteStartWakelock(int uid, int pid, String name, String historyName, int type,
389 boolean unimportantForLogging) {
390 enforceCallingPermission();
391 synchronized (mStats) {
392 mStats.noteStartWakeLocked(uid, pid, name, historyName, type, unimportantForLogging,
393 SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
397 public void noteStopWakelock(int uid, int pid, String name, String historyName, int type) {
398 enforceCallingPermission();
399 synchronized (mStats) {
400 mStats.noteStopWakeLocked(uid, pid, name, historyName, type,
401 SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
405 public void noteStartWakelockFromSource(WorkSource ws, int pid, String name,
406 String historyName, int type, boolean unimportantForLogging) {
407 enforceCallingPermission();
408 synchronized (mStats) {
409 mStats.noteStartWakeFromSourceLocked(ws, pid, name, historyName,
410 type, unimportantForLogging);
414 public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name,
415 String historyName, int type, WorkSource newWs, int newPid, String newName,
416 String newHistoryName, int newType, boolean newUnimportantForLogging) {
417 enforceCallingPermission();
418 synchronized (mStats) {
419 mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, historyName, type,
420 newWs, newPid, newName, newHistoryName, newType, newUnimportantForLogging);
424 public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, String historyName,
426 enforceCallingPermission();
427 synchronized (mStats) {
428 mStats.noteStopWakeFromSourceLocked(ws, pid, name, historyName, type);
432 public void noteStartSensor(int uid, int sensor) {
433 enforceCallingPermission();
434 synchronized (mStats) {
435 mStats.noteStartSensorLocked(uid, sensor);
439 public void noteStopSensor(int uid, int sensor) {
440 enforceCallingPermission();
441 synchronized (mStats) {
442 mStats.noteStopSensorLocked(uid, sensor);
446 public void noteVibratorOn(int uid, long durationMillis) {
447 enforceCallingPermission();
448 synchronized (mStats) {
449 mStats.noteVibratorOnLocked(uid, durationMillis);
453 public void noteVibratorOff(int uid) {
454 enforceCallingPermission();
455 synchronized (mStats) {
456 mStats.noteVibratorOffLocked(uid);
460 public void noteStartGps(int uid) {
461 enforceCallingPermission();
462 synchronized (mStats) {
463 mStats.noteStartGpsLocked(uid);
467 public void noteStopGps(int uid) {
468 enforceCallingPermission();
469 synchronized (mStats) {
470 mStats.noteStopGpsLocked(uid);
474 public void noteScreenState(int state) {
475 enforceCallingPermission();
476 synchronized (mStats) {
477 mStats.noteScreenStateLocked(state);
481 public void noteScreenBrightness(int brightness) {
482 enforceCallingPermission();
483 synchronized (mStats) {
484 mStats.noteScreenBrightnessLocked(brightness);
488 public void noteUserActivity(int uid, int event) {
489 enforceCallingPermission();
490 synchronized (mStats) {
491 mStats.noteUserActivityLocked(uid, event);
495 public void noteWakeUp(String reason, int reasonUid) {
496 enforceCallingPermission();
497 synchronized (mStats) {
498 mStats.noteWakeUpLocked(reason, reasonUid);
502 public void noteInteractive(boolean interactive) {
503 enforceCallingPermission();
504 synchronized (mStats) {
505 mStats.noteInteractiveLocked(interactive);
509 public void noteConnectivityChanged(int type, String extra) {
510 enforceCallingPermission();
511 synchronized (mStats) {
512 mStats.noteConnectivityChangedLocked(type, extra);
516 public void noteMobileRadioPowerState(int powerState, long timestampNs) {
517 enforceCallingPermission();
518 synchronized (mStats) {
519 mStats.noteMobileRadioPowerState(powerState, timestampNs);
523 public void notePhoneOn() {
524 enforceCallingPermission();
525 synchronized (mStats) {
526 mStats.notePhoneOnLocked();
530 public void notePhoneOff() {
531 enforceCallingPermission();
532 synchronized (mStats) {
533 mStats.notePhoneOffLocked();
537 public void notePhoneSignalStrength(SignalStrength signalStrength) {
538 enforceCallingPermission();
539 synchronized (mStats) {
540 mStats.notePhoneSignalStrengthLocked(signalStrength);
544 public void notePhoneDataConnectionState(int dataType, boolean hasData) {
545 enforceCallingPermission();
546 synchronized (mStats) {
547 mStats.notePhoneDataConnectionStateLocked(dataType, hasData);
551 public void notePhoneState(int state) {
552 enforceCallingPermission();
553 int simState = TelephonyManager.getDefault().getSimState();
554 synchronized (mStats) {
555 mStats.notePhoneStateLocked(state, simState);
559 public void noteWifiOn() {
560 enforceCallingPermission();
561 synchronized (mStats) {
562 mStats.noteWifiOnLocked();
566 public void noteWifiOff() {
567 enforceCallingPermission();
568 synchronized (mStats) {
569 mStats.noteWifiOffLocked();
573 public void noteStartAudio(int uid) {
574 enforceCallingPermission();
575 synchronized (mStats) {
576 mStats.noteAudioOnLocked(uid);
580 public void noteStopAudio(int uid) {
581 enforceCallingPermission();
582 synchronized (mStats) {
583 mStats.noteAudioOffLocked(uid);
587 public void noteStartVideo(int uid) {
588 enforceCallingPermission();
589 synchronized (mStats) {
590 mStats.noteVideoOnLocked(uid);
594 public void noteStopVideo(int uid) {
595 enforceCallingPermission();
596 synchronized (mStats) {
597 mStats.noteVideoOffLocked(uid);
601 public void noteResetAudio() {
602 enforceCallingPermission();
603 synchronized (mStats) {
604 mStats.noteResetAudioLocked();
608 public void noteResetVideo() {
609 enforceCallingPermission();
610 synchronized (mStats) {
611 mStats.noteResetVideoLocked();
615 public void noteFlashlightOn(int uid) {
616 enforceCallingPermission();
617 synchronized (mStats) {
618 mStats.noteFlashlightOnLocked(uid);
622 public void noteFlashlightOff(int uid) {
623 enforceCallingPermission();
624 synchronized (mStats) {
625 mStats.noteFlashlightOffLocked(uid);
629 public void noteStartCamera(int uid) {
630 enforceCallingPermission();
631 synchronized (mStats) {
632 mStats.noteCameraOnLocked(uid);
636 public void noteStopCamera(int uid) {
637 enforceCallingPermission();
638 synchronized (mStats) {
639 mStats.noteCameraOffLocked(uid);
643 public void noteResetCamera() {
644 enforceCallingPermission();
645 synchronized (mStats) {
646 mStats.noteResetCameraLocked();
650 public void noteResetFlashlight() {
651 enforceCallingPermission();
652 synchronized (mStats) {
653 mStats.noteResetFlashlightLocked();
658 public void noteWifiRadioPowerState(int powerState, long tsNanos) {
659 enforceCallingPermission();
661 // There was a change in WiFi power state.
662 // Collect data now for the past activity.
663 synchronized (mStats) {
664 if (mStats.isOnBattery()) {
665 final String type = (powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH ||
666 powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM) ? "active"
668 mHandler.scheduleSync("wifi-data: " + type,
669 BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI);
671 mStats.noteWifiRadioPowerState(powerState, tsNanos);
675 public void noteWifiRunning(WorkSource ws) {
676 enforceCallingPermission();
677 synchronized (mStats) {
678 mStats.noteWifiRunningLocked(ws);
682 public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) {
683 enforceCallingPermission();
684 synchronized (mStats) {
685 mStats.noteWifiRunningChangedLocked(oldWs, newWs);
689 public void noteWifiStopped(WorkSource ws) {
690 enforceCallingPermission();
691 synchronized (mStats) {
692 mStats.noteWifiStoppedLocked(ws);
696 public void noteWifiState(int wifiState, String accessPoint) {
697 enforceCallingPermission();
698 synchronized (mStats) {
699 mStats.noteWifiStateLocked(wifiState, accessPoint);
703 public void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth) {
704 enforceCallingPermission();
705 synchronized (mStats) {
706 mStats.noteWifiSupplicantStateChangedLocked(supplState, failedAuth);
710 public void noteWifiRssiChanged(int newRssi) {
711 enforceCallingPermission();
712 synchronized (mStats) {
713 mStats.noteWifiRssiChangedLocked(newRssi);
717 public void noteFullWifiLockAcquired(int uid) {
718 enforceCallingPermission();
719 synchronized (mStats) {
720 mStats.noteFullWifiLockAcquiredLocked(uid);
724 public void noteFullWifiLockReleased(int uid) {
725 enforceCallingPermission();
726 synchronized (mStats) {
727 mStats.noteFullWifiLockReleasedLocked(uid);
731 public void noteWifiScanStarted(int uid) {
732 enforceCallingPermission();
733 synchronized (mStats) {
734 mStats.noteWifiScanStartedLocked(uid);
738 public void noteWifiScanStopped(int uid) {
739 enforceCallingPermission();
740 synchronized (mStats) {
741 mStats.noteWifiScanStoppedLocked(uid);
745 public void noteWifiMulticastEnabled(int uid) {
746 enforceCallingPermission();
747 synchronized (mStats) {
748 mStats.noteWifiMulticastEnabledLocked(uid);
752 public void noteWifiMulticastDisabled(int uid) {
753 enforceCallingPermission();
754 synchronized (mStats) {
755 mStats.noteWifiMulticastDisabledLocked(uid);
759 public void noteFullWifiLockAcquiredFromSource(WorkSource ws) {
760 enforceCallingPermission();
761 synchronized (mStats) {
762 mStats.noteFullWifiLockAcquiredFromSourceLocked(ws);
766 public void noteFullWifiLockReleasedFromSource(WorkSource ws) {
767 enforceCallingPermission();
768 synchronized (mStats) {
769 mStats.noteFullWifiLockReleasedFromSourceLocked(ws);
773 public void noteWifiScanStartedFromSource(WorkSource ws) {
774 enforceCallingPermission();
775 synchronized (mStats) {
776 mStats.noteWifiScanStartedFromSourceLocked(ws);
780 public void noteWifiScanStoppedFromSource(WorkSource ws) {
781 enforceCallingPermission();
782 synchronized (mStats) {
783 mStats.noteWifiScanStoppedFromSourceLocked(ws);
787 public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) {
788 enforceCallingPermission();
789 synchronized (mStats) {
790 mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph);
794 public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) {
795 enforceCallingPermission();
796 synchronized (mStats) {
797 mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws);
801 public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
802 enforceCallingPermission();
803 synchronized (mStats) {
804 mStats.noteWifiMulticastEnabledFromSourceLocked(ws);
809 public void noteWifiMulticastDisabledFromSource(WorkSource ws) {
810 enforceCallingPermission();
811 synchronized (mStats) {
812 mStats.noteWifiMulticastDisabledFromSourceLocked(ws);
817 public void noteNetworkInterfaceType(String iface, int networkType) {
818 enforceCallingPermission();
819 synchronized (mStats) {
820 mStats.noteNetworkInterfaceTypeLocked(iface, networkType);
825 public void noteNetworkStatsEnabled() {
826 enforceCallingPermission();
827 synchronized (mStats) {
828 mStats.noteNetworkStatsEnabledLocked();
833 public void noteDeviceIdleMode(int mode, String activeReason, int activeUid) {
834 enforceCallingPermission();
835 synchronized (mStats) {
836 mStats.noteDeviceIdleModeLocked(mode, activeReason, activeUid);
840 public void notePackageInstalled(String pkgName, int versionCode) {
841 enforceCallingPermission();
842 synchronized (mStats) {
843 mStats.notePackageInstalledLocked(pkgName, versionCode);
847 public void notePackageUninstalled(String pkgName) {
848 enforceCallingPermission();
849 synchronized (mStats) {
850 mStats.notePackageUninstalledLocked(pkgName);
855 public void noteBleScanStarted(WorkSource ws) {
856 enforceCallingPermission();
857 synchronized (mStats) {
858 mStats.noteBluetoothScanStartedFromSourceLocked(ws);
863 public void noteBleScanStopped(WorkSource ws) {
864 enforceCallingPermission();
865 synchronized (mStats) {
866 mStats.noteBluetoothScanStoppedFromSourceLocked(ws);
871 public void noteResetBleScan() {
872 enforceCallingPermission();
873 synchronized (mStats) {
874 mStats.noteResetBluetoothScanLocked();
878 public boolean isOnBattery() {
879 return mStats.isOnBattery();
883 public void setBatteryState(final int status, final int health, final int plugType,
884 final int level, final int temp, final int volt) {
885 enforceCallingPermission();
887 // BatteryService calls us here and we may update external state. It would be wrong
888 // to block such a low level service like BatteryService on external stats like WiFi.
889 mHandler.post(new Runnable() {
892 synchronized (mStats) {
893 final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
894 if (mStats.isOnBattery() == onBattery) {
895 // The battery state has not changed, so we don't need to sync external
896 // stats immediately.
897 mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt);
902 // Sync external stats first as the battery has changed states. If we don't sync
903 // immediately here, we may not collect the relevant data later.
904 updateExternalStats("battery-state", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
905 synchronized (mStats) {
906 mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt);
912 public long getAwakeTimeBattery() {
913 mContext.enforceCallingOrSelfPermission(
914 android.Manifest.permission.BATTERY_STATS, null);
915 return mStats.getAwakeTimeBattery();
918 public long getAwakeTimePlugged() {
919 mContext.enforceCallingOrSelfPermission(
920 android.Manifest.permission.BATTERY_STATS, null);
921 return mStats.getAwakeTimePlugged();
924 public void enforceCallingPermission() {
925 if (Binder.getCallingPid() == Process.myPid()) {
928 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
929 Binder.getCallingPid(), Binder.getCallingUid(), null);
932 final class WakeupReasonThread extends Thread {
933 private static final int MAX_REASON_SIZE = 512;
934 private CharsetDecoder mDecoder;
935 private ByteBuffer mUtf8Buffer;
936 private CharBuffer mUtf16Buffer;
938 WakeupReasonThread() {
939 super("BatteryStats_wakeupReason");
943 Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
945 mDecoder = StandardCharsets.UTF_8
947 .onMalformedInput(CodingErrorAction.REPLACE)
948 .onUnmappableCharacter(CodingErrorAction.REPLACE)
951 mUtf8Buffer = ByteBuffer.allocateDirect(MAX_REASON_SIZE);
952 mUtf16Buffer = CharBuffer.allocate(MAX_REASON_SIZE);
956 while ((reason = waitWakeup()) != null) {
957 synchronized (mStats) {
958 mStats.noteWakeupReasonLocked(reason);
961 } catch (RuntimeException e) {
962 Slog.e(TAG, "Failure reading wakeup reasons", e);
966 private String waitWakeup() {
968 mUtf16Buffer.clear();
971 int bytesWritten = nativeWaitWakeup(mUtf8Buffer);
972 if (bytesWritten < 0) {
974 } else if (bytesWritten == 0) {
978 // Set the buffer's limit to the number of bytes written.
979 mUtf8Buffer.limit(bytesWritten);
981 // Decode the buffer from UTF-8 to UTF-16.
982 // Unmappable characters will be replaced.
983 mDecoder.decode(mUtf8Buffer, mUtf16Buffer, true);
986 // Create a String from the UTF-16 buffer.
987 return mUtf16Buffer.toString();
991 private static native int nativeWaitWakeup(ByteBuffer outBuffer);
993 private void dumpHelp(PrintWriter pw) {
994 pw.println("Battery stats (batterystats) dump options:");
995 pw.println(" [--checkin] [--history] [--history-start] [--charged] [-c]");
996 pw.println(" [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]");
997 pw.println(" --checkin: generate output for a checkin report; will write (and clear) the");
998 pw.println(" last old completed stats when they had been reset.");
999 pw.println(" --c: write the current stats in checkin format.");
1000 pw.println(" --history: show only history data.");
1001 pw.println(" --history-start <num>: show only history data starting at given time offset.");
1002 pw.println(" --charged: only output data since last charged.");
1003 pw.println(" --daily: only output full daily data.");
1004 pw.println(" --reset: reset the stats, clearing all current data.");
1005 pw.println(" --write: force write current collected stats to disk.");
1006 pw.println(" --new-daily: immediately create and write new daily stats record.");
1007 pw.println(" --read-daily: read-load last written daily stats.");
1008 pw.println(" <package.name>: optional name of package to filter output by.");
1009 pw.println(" -h: print this help text.");
1010 pw.println("Battery stats (batterystats) commands:");
1011 pw.println(" enable|disable <option>");
1012 pw.println(" Enable or disable a running option. Option state is not saved across boots.");
1013 pw.println(" Options are:");
1014 pw.println(" full-history: include additional detailed events in battery history:");
1015 pw.println(" wake_lock_in, alarms and proc events");
1016 pw.println(" no-auto-reset: don't automatically reset stats when unplugged");
1019 private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
1021 if (i >= args.length) {
1022 pw.println("Missing option argument for " + (enable ? "--enable" : "--disable"));
1026 if ("full-wake-history".equals(args[i]) || "full-history".equals(args[i])) {
1027 synchronized (mStats) {
1028 mStats.setRecordAllHistoryLocked(enable);
1030 } else if ("no-auto-reset".equals(args[i])) {
1031 synchronized (mStats) {
1032 mStats.setNoAutoReset(enable);
1035 pw.println("Unknown enable/disable option: " + args[i]);
1044 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1045 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1046 != PackageManager.PERMISSION_GRANTED) {
1047 pw.println("Permission Denial: can't dump BatteryStats from from pid="
1048 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
1049 + " without permission " + android.Manifest.permission.DUMP);
1054 boolean useCheckinFormat = false;
1055 boolean isRealCheckin = false;
1056 boolean noOutput = false;
1057 boolean writeData = false;
1058 long historyStart = -1;
1061 for (int i=0; i<args.length; i++) {
1062 String arg = args[i];
1063 if ("--checkin".equals(arg)) {
1064 useCheckinFormat = true;
1065 isRealCheckin = true;
1066 } else if ("--history".equals(arg)) {
1067 flags |= BatteryStats.DUMP_HISTORY_ONLY;
1068 } else if ("--history-start".equals(arg)) {
1069 flags |= BatteryStats.DUMP_HISTORY_ONLY;
1071 if (i >= args.length) {
1072 pw.println("Missing time argument for --history-since");
1076 historyStart = Long.parseLong(args[i]);
1078 } else if ("-c".equals(arg)) {
1079 useCheckinFormat = true;
1080 flags |= BatteryStats.DUMP_INCLUDE_HISTORY;
1081 } else if ("--charged".equals(arg)) {
1082 flags |= BatteryStats.DUMP_CHARGED_ONLY;
1083 } else if ("--daily".equals(arg)) {
1084 flags |= BatteryStats.DUMP_DAILY_ONLY;
1085 } else if ("--reset".equals(arg)) {
1086 synchronized (mStats) {
1087 mStats.resetAllStatsCmdLocked();
1088 pw.println("Battery stats reset.");
1091 updateExternalStats("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
1092 } else if ("--write".equals(arg)) {
1093 updateExternalStats("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
1094 synchronized (mStats) {
1095 mStats.writeSyncLocked();
1096 pw.println("Battery stats written.");
1099 } else if ("--new-daily".equals(arg)) {
1100 synchronized (mStats) {
1101 mStats.recordDailyStatsLocked();
1102 pw.println("New daily stats written.");
1105 } else if ("--read-daily".equals(arg)) {
1106 synchronized (mStats) {
1107 mStats.readDailyStatsLocked();
1108 pw.println("Last daily stats read.");
1111 } else if ("--enable".equals(arg) || "enable".equals(arg)) {
1112 i = doEnableOrDisable(pw, i, args, true);
1116 pw.println("Enabled: " + args[i]);
1118 } else if ("--disable".equals(arg) || "disable".equals(arg)) {
1119 i = doEnableOrDisable(pw, i, args, false);
1123 pw.println("Disabled: " + args[i]);
1125 } else if ("-h".equals(arg)) {
1128 } else if ("-a".equals(arg)) {
1129 flags |= BatteryStats.DUMP_VERBOSE;
1130 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
1131 pw.println("Unknown option: " + arg);
1135 // Not an option, last argument must be a package name.
1137 reqUid = mContext.getPackageManager().getPackageUidAsUser(arg,
1138 UserHandle.getCallingUserId());
1139 } catch (PackageManager.NameNotFoundException e) {
1140 pw.println("Unknown package: " + arg);
1151 long ident = Binder.clearCallingIdentity();
1153 if (BatteryStatsHelper.checkWifiOnly(mContext)) {
1154 flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY;
1156 // Fetch data from external sources and update the BatteryStatsImpl object with them.
1157 updateExternalStats("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
1159 Binder.restoreCallingIdentity(ident);
1163 // By default, if the caller is only interested in a specific package, then
1164 // we only dump the aggregated data since charged.
1165 if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_CHARGED_ONLY)) == 0) {
1166 flags |= BatteryStats.DUMP_CHARGED_ONLY;
1167 // Also if they are doing -c, we don't want history.
1168 flags &= ~BatteryStats.DUMP_INCLUDE_HISTORY;
1172 if (useCheckinFormat) {
1173 List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
1174 PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_ALL);
1175 if (isRealCheckin) {
1176 // For a real checkin, first we want to prefer to use the last complete checkin
1177 // file if there is one.
1178 synchronized (mStats.mCheckinFile) {
1179 if (mStats.mCheckinFile.exists()) {
1181 byte[] raw = mStats.mCheckinFile.readFully();
1183 Parcel in = Parcel.obtain();
1184 in.unmarshall(raw, 0, raw.length);
1185 in.setDataPosition(0);
1186 BatteryStatsImpl checkinStats = new BatteryStatsImpl(
1187 null, mStats.mHandler, null);
1188 checkinStats.readSummaryFromParcel(in);
1190 checkinStats.dumpCheckinLocked(mContext, pw, apps, flags,
1192 mStats.mCheckinFile.delete();
1195 } catch (IOException | ParcelFormatException e) {
1196 Slog.w(TAG, "Failure reading checkin file "
1197 + mStats.mCheckinFile.getBaseFile(), e);
1202 synchronized (mStats) {
1203 mStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart);
1205 mStats.writeAsyncLocked();
1209 synchronized (mStats) {
1210 mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart);
1212 mStats.writeAsyncLocked();
1218 // Objects for extracting data from external sources.
1219 private final Object mExternalStatsLock = new Object();
1221 @GuardedBy("mExternalStatsLock")
1222 private IWifiManager mWifiManager;
1224 // WiFi keeps an accumulated total of stats, unlike Bluetooth.
1225 // Keep the last WiFi stats so we can compute a delta.
1226 @GuardedBy("mExternalStatsLock")
1227 private WifiActivityEnergyInfo mLastInfo =
1228 new WifiActivityEnergyInfo(0, 0, 0, new long[]{0}, 0, 0, 0);
1230 @GuardedBy("mExternalStatsLock")
1231 private WifiActivityEnergyInfo pullWifiEnergyInfoLocked() {
1232 if (mWifiManager == null) {
1233 mWifiManager = IWifiManager.Stub.asInterface(
1234 ServiceManager.getService(Context.WIFI_SERVICE));
1235 if (mWifiManager == null) {
1241 // We read the data even if we are not on battery. This is so that we keep the
1242 // correct delta from when we should start reading (aka when we are on battery).
1243 WifiActivityEnergyInfo info = mWifiManager.reportActivityInfo();
1244 if (info != null && info.isValid()) {
1245 if (info.mControllerEnergyUsed < 0 || info.mControllerIdleTimeMs < 0 ||
1246 info.mControllerRxTimeMs < 0 || info.mControllerTxTimeMs < 0) {
1247 Slog.wtf(TAG, "Reported WiFi energy data is invalid: " + info);
1251 final long timePeriodMs = info.mTimestamp - mLastInfo.mTimestamp;
1252 final long lastIdleMs = mLastInfo.mControllerIdleTimeMs;
1253 final long lastTxMs = mLastInfo.mControllerTxTimeMs;
1254 final long lastRxMs = mLastInfo.mControllerRxTimeMs;
1255 final long lastEnergy = mLastInfo.mControllerEnergyUsed;
1257 // We will modify the last info object to be the delta, and store the new
1258 // WifiActivityEnergyInfo object as our last one.
1259 final WifiActivityEnergyInfo result = mLastInfo;
1260 result.mTimestamp = info.getTimeStamp();
1261 result.mStackState = info.getStackState();
1263 // These times seem to be the most reliable.
1264 result.mControllerTxTimeMs = info.mControllerTxTimeMs - lastTxMs;
1265 result.mControllerRxTimeMs = info.mControllerRxTimeMs - lastRxMs;
1267 // WiFi calculates the idle time as a difference from the on time and the various
1268 // Rx + Tx times. There seems to be some missing time there because this sometimes
1269 // becomes negative. Just cap it at 0 and move on.
1271 result.mControllerIdleTimeMs = Math.max(0, info.mControllerIdleTimeMs - lastIdleMs);
1272 result.mControllerEnergyUsed =
1273 Math.max(0, info.mControllerEnergyUsed - lastEnergy);
1275 if (result.mControllerTxTimeMs < 0 ||
1276 result.mControllerRxTimeMs < 0) {
1277 // The stats were reset by the WiFi system (which is why our delta is negative).
1278 // Returns the unaltered stats.
1279 result.mControllerEnergyUsed = info.mControllerEnergyUsed;
1280 result.mControllerRxTimeMs = info.mControllerRxTimeMs;
1281 result.mControllerTxTimeMs = info.mControllerTxTimeMs;
1282 result.mControllerIdleTimeMs = info.mControllerIdleTimeMs;
1284 Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + result);
1287 // There is some accuracy error in reports so allow some slop in the results.
1288 final long SAMPLE_ERROR_MILLIS = 750;
1289 final long totalTimeMs = result.mControllerIdleTimeMs + result.mControllerRxTimeMs +
1290 result.mControllerTxTimeMs;
1291 if (totalTimeMs > timePeriodMs + SAMPLE_ERROR_MILLIS) {
1292 StringBuilder sb = new StringBuilder();
1293 sb.append("Total time ");
1294 TimeUtils.formatDuration(totalTimeMs, sb);
1295 sb.append(" is longer than sample period ");
1296 TimeUtils.formatDuration(timePeriodMs, sb);
1298 sb.append("Previous WiFi snapshot: ").append("idle=");
1299 TimeUtils.formatDuration(lastIdleMs, sb);
1301 TimeUtils.formatDuration(lastRxMs, sb);
1303 TimeUtils.formatDuration(lastTxMs, sb);
1304 sb.append(" e=").append(lastEnergy);
1306 sb.append("Current WiFi snapshot: ").append("idle=");
1307 TimeUtils.formatDuration(info.mControllerIdleTimeMs, sb);
1309 TimeUtils.formatDuration(info.mControllerRxTimeMs, sb);
1311 TimeUtils.formatDuration(info.mControllerTxTimeMs, sb);
1312 sb.append(" e=").append(info.mControllerEnergyUsed);
1313 Slog.wtf(TAG, sb.toString());
1319 } catch (RemoteException e) {
1320 // Nothing to report, WiFi is dead.
1325 @GuardedBy("mExternalStatsLock")
1326 private BluetoothActivityEnergyInfo pullBluetoothEnergyInfoLocked() {
1327 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1328 if (adapter != null) {
1329 BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo(
1330 BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED);
1331 if (info != null && info.isValid()) {
1332 if (info.getControllerEnergyUsed() < 0 || info.getControllerIdleTimeMillis() < 0 ||
1333 info.getControllerRxTimeMillis() < 0 || info.getControllerTxTimeMillis() < 0) {
1334 Slog.wtf(TAG, "Bluetooth energy data is invalid: " + info);
1342 @GuardedBy("mExternalStatsLock")
1343 private ModemActivityInfo pullModemActivityInfoLocked() {
1344 ITelephony tm = ITelephony.Stub.asInterface(ServiceManager.getService(
1345 Context.TELEPHONY_SERVICE));
1348 ModemActivityInfo info = tm.getModemActivityInfo();
1349 if (info == null || info.isValid()) {
1352 Slog.wtf(TAG, "Modem activity info is invalid: " + info);
1354 } catch (RemoteException e) {
1361 * Fetches data from external sources (WiFi controller, bluetooth chipset) and updates
1362 * batterystats with that information.
1364 * We first grab a lock specific to this method, then once all the data has been collected,
1365 * we grab the mStats lock and update the data.
1367 * @param reason The reason why this collection was requested. Useful for debugging.
1368 * @param updateFlags Which external stats to update. Can be a combination of
1369 * {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_CPU},
1370 * {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_RADIO},
1371 * {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_WIFI},
1372 * and {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_BT}.
1374 void updateExternalStats(final String reason, final int updateFlags) {
1375 synchronized (mExternalStatsLock) {
1376 if (mContext == null) {
1377 // We haven't started yet (which means the BatteryStatsImpl object has
1378 // no power profile. Don't consume data we can't compute yet.
1382 if (BatteryStatsImpl.DEBUG_ENERGY) {
1383 Slog.d(TAG, "Updating external stats: reason=" + reason);
1386 WifiActivityEnergyInfo wifiEnergyInfo = null;
1387 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
1388 wifiEnergyInfo = pullWifiEnergyInfoLocked();
1391 ModemActivityInfo modemActivityInfo = null;
1392 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) {
1393 modemActivityInfo = pullModemActivityInfoLocked();
1396 BluetoothActivityEnergyInfo bluetoothEnergyInfo = null;
1397 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_BT) != 0) {
1398 // We only pull bluetooth stats when we have to, as we are not distributing its
1399 // use amongst apps and the sampling frequency does not matter.
1400 bluetoothEnergyInfo = pullBluetoothEnergyInfoLocked();
1403 synchronized (mStats) {
1404 final long elapsedRealtime = SystemClock.elapsedRealtime();
1405 final long uptime = SystemClock.uptimeMillis();
1406 if (mStats.mRecordAllHistory) {
1407 mStats.addHistoryEventLocked(elapsedRealtime, uptime,
1408 BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS, reason, 0);
1411 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_CPU) != 0) {
1412 mStats.updateCpuTimeLocked();
1413 mStats.updateKernelWakelocksLocked();
1416 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) {
1417 mStats.updateMobileRadioStateLocked(elapsedRealtime, modemActivityInfo);
1420 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
1421 mStats.updateWifiStateLocked(wifiEnergyInfo);
1424 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_BT) != 0) {
1425 mStats.updateBluetoothStateLocked(bluetoothEnergyInfo);
1432 * Gets a snapshot of the system health for a particular uid.
1435 public HealthStatsParceler takeUidSnapshot(int requestUid) {
1436 if (requestUid != Binder.getCallingUid()) {
1437 mContext.enforceCallingOrSelfPermission(
1438 android.Manifest.permission.BATTERY_STATS, null);
1440 long ident = Binder.clearCallingIdentity();
1442 updateExternalStats("get-health-stats-for-uid",
1443 BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
1444 synchronized (mStats) {
1445 return getHealthStatsForUidLocked(requestUid);
1447 } catch (Exception ex) {
1448 Slog.d(TAG, "Crashed while writing for takeUidSnapshot(" + requestUid + ")", ex);
1451 Binder.restoreCallingIdentity(ident);
1456 * Gets a snapshot of the system health for a number of uids.
1459 public HealthStatsParceler[] takeUidSnapshots(int[] requestUids) {
1460 if (!onlyCaller(requestUids)) {
1461 mContext.enforceCallingOrSelfPermission(
1462 android.Manifest.permission.BATTERY_STATS, null);
1464 long ident = Binder.clearCallingIdentity();
1467 updateExternalStats("get-health-stats-for-uids",
1468 BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
1469 synchronized (mStats) {
1470 final int N = requestUids.length;
1471 final HealthStatsParceler[] results = new HealthStatsParceler[N];
1472 for (i=0; i<N; i++) {
1473 results[i] = getHealthStatsForUidLocked(requestUids[i]);
1477 } catch (Exception ex) {
1478 Slog.d(TAG, "Crashed while writing for takeUidSnapshots("
1479 + Arrays.toString(requestUids) + ") i=" + i, ex);
1482 Binder.restoreCallingIdentity(ident);
1487 * Returns whether the Binder.getCallingUid is the only thing in requestUids.
1489 private static boolean onlyCaller(int[] requestUids) {
1490 final int caller = Binder.getCallingUid();
1491 final int N = requestUids.length;
1492 for (int i=0; i<N; i++) {
1493 if (requestUids[i] != caller) {
1501 * Gets a HealthStatsParceler for the given uid. You should probably call
1502 * updateExternalStats first.
1504 HealthStatsParceler getHealthStatsForUidLocked(int requestUid) {
1505 final HealthStatsBatteryStatsWriter writer = new HealthStatsBatteryStatsWriter();
1506 final HealthStatsWriter uidWriter = new HealthStatsWriter(UidHealthStats.CONSTANTS);
1507 final BatteryStats.Uid uid = mStats.getUidStats().get(requestUid);
1509 writer.writeUid(uidWriter, mStats, uid);
1511 return new HealthStatsParceler(uidWriter);