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