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