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