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