OSDN Git Service

Merge changes from topic 'wifi_tx_power_levels' into nyc-dev
[android-x86/frameworks-base.git] / services / core / java / com / android / server / am / BatteryStatsService.java
1 /*
2  * Copyright (C) 2006-2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.server.am;
18
19 import android.bluetooth.BluetoothActivityEnergyInfo;
20 import android.bluetooth.BluetoothAdapter;
21 import android.content.Context;
22 import android.content.pm.ApplicationInfo;
23 import android.content.pm.PackageManager;
24 import android.net.wifi.IWifiManager;
25 import android.net.wifi.WifiActivityEnergyInfo;
26 import android.os.BatteryStats;
27 import android.os.Binder;
28 import android.os.Handler;
29 import android.os.IBinder;
30 import android.os.Looper;
31 import android.os.Message;
32 import android.os.Parcel;
33 import android.os.ParcelFileDescriptor;
34 import android.os.ParcelFormatException;
35 import android.os.PowerManager;
36 import android.os.PowerManagerInternal;
37 import android.os.Process;
38 import android.os.RemoteException;
39 import android.os.ServiceManager;
40 import android.os.SystemClock;
41 import android.os.UserHandle;
42 import android.os.WorkSource;
43 import android.os.health.HealthStatsParceler;
44 import android.os.health.HealthStatsWriter;
45 import android.os.health.UidHealthStats;
46 import android.telephony.DataConnectionRealTimeInfo;
47 import android.telephony.ModemActivityInfo;
48 import android.telephony.SignalStrength;
49 import android.telephony.TelephonyManager;
50 import android.util.IntArray;
51 import android.util.Slog;
52
53 import android.util.TimeUtils;
54 import com.android.internal.annotations.GuardedBy;
55 import com.android.internal.app.IBatteryStats;
56 import com.android.internal.os.BatteryStatsHelper;
57 import com.android.internal.os.BatteryStatsImpl;
58 import com.android.internal.os.PowerProfile;
59 import com.android.internal.telephony.ITelephony;
60 import com.android.server.FgThread;
61 import com.android.server.LocalServices;
62
63 import java.io.File;
64 import java.io.FileDescriptor;
65 import java.io.IOException;
66 import java.io.PrintWriter;
67 import java.nio.ByteBuffer;
68 import java.nio.CharBuffer;
69 import java.nio.charset.CharsetDecoder;
70 import java.nio.charset.CodingErrorAction;
71 import java.nio.charset.StandardCharsets;
72 import java.util.Arrays;
73 import java.util.List;
74 import java.util.Map;
75
76 /**
77  * All information we are collecting about things that can happen that impact
78  * battery life.
79  */
80 public 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 =
1228             new WifiActivityEnergyInfo(0, 0, 0, new long[]{0}, 0, 0, 0);
1229
1230     @GuardedBy("mExternalStatsLock")
1231     private WifiActivityEnergyInfo pullWifiEnergyInfoLocked() {
1232         if (mWifiManager == null) {
1233             mWifiManager = IWifiManager.Stub.asInterface(
1234                     ServiceManager.getService(Context.WIFI_SERVICE));
1235             if (mWifiManager == null) {
1236                 return null;
1237             }
1238         }
1239
1240         try {
1241             // We read the data even if we are not on battery. This is so that we keep the
1242             // correct delta from when we should start reading (aka when we are on battery).
1243             WifiActivityEnergyInfo info = mWifiManager.reportActivityInfo();
1244             if (info != null && info.isValid()) {
1245                 if (info.mControllerEnergyUsed < 0 || info.mControllerIdleTimeMs < 0 ||
1246                         info.mControllerRxTimeMs < 0 || info.mControllerTxTimeMs < 0) {
1247                     Slog.wtf(TAG, "Reported WiFi energy data is invalid: " + info);
1248                     return null;
1249                 }
1250
1251                 final long timePeriodMs = info.mTimestamp - mLastInfo.mTimestamp;
1252                 final long lastIdleMs = mLastInfo.mControllerIdleTimeMs;
1253                 final long lastTxMs = mLastInfo.mControllerTxTimeMs;
1254                 final long lastRxMs = mLastInfo.mControllerRxTimeMs;
1255                 final long lastEnergy = mLastInfo.mControllerEnergyUsed;
1256
1257                 // We will modify the last info object to be the delta, and store the new
1258                 // WifiActivityEnergyInfo object as our last one.
1259                 final WifiActivityEnergyInfo result = mLastInfo;
1260                 result.mTimestamp = info.getTimeStamp();
1261                 result.mStackState = info.getStackState();
1262
1263                 // These times seem to be the most reliable.
1264                 result.mControllerTxTimeMs = info.mControllerTxTimeMs - lastTxMs;
1265                 result.mControllerRxTimeMs = info.mControllerRxTimeMs - lastRxMs;
1266
1267                 // WiFi calculates the idle time as a difference from the on time and the various
1268                 // Rx + Tx times. There seems to be some missing time there because this sometimes
1269                 // becomes negative. Just cap it at 0 and move on.
1270                 // b/21613534
1271                 result.mControllerIdleTimeMs = Math.max(0, info.mControllerIdleTimeMs - lastIdleMs);
1272                 result.mControllerEnergyUsed =
1273                         Math.max(0, info.mControllerEnergyUsed - lastEnergy);
1274
1275                 if (result.mControllerTxTimeMs < 0 ||
1276                         result.mControllerRxTimeMs < 0) {
1277                     // The stats were reset by the WiFi system (which is why our delta is negative).
1278                     // Returns the unaltered stats.
1279                     result.mControllerEnergyUsed = info.mControllerEnergyUsed;
1280                     result.mControllerRxTimeMs = info.mControllerRxTimeMs;
1281                     result.mControllerTxTimeMs = info.mControllerTxTimeMs;
1282                     result.mControllerIdleTimeMs = info.mControllerIdleTimeMs;
1283
1284                     Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + result);
1285                 }
1286
1287                 // There is some accuracy error in reports so allow some slop in the results.
1288                 final long SAMPLE_ERROR_MILLIS = 750;
1289                 final long totalTimeMs = result.mControllerIdleTimeMs + result.mControllerRxTimeMs +
1290                         result.mControllerTxTimeMs;
1291                 if (totalTimeMs > timePeriodMs + SAMPLE_ERROR_MILLIS) {
1292                     StringBuilder sb = new StringBuilder();
1293                     sb.append("Total time ");
1294                     TimeUtils.formatDuration(totalTimeMs, sb);
1295                     sb.append(" is longer than sample period ");
1296                     TimeUtils.formatDuration(timePeriodMs, sb);
1297                     sb.append(".\n");
1298                     sb.append("Previous WiFi snapshot: ").append("idle=");
1299                     TimeUtils.formatDuration(lastIdleMs, sb);
1300                     sb.append(" rx=");
1301                     TimeUtils.formatDuration(lastRxMs, sb);
1302                     sb.append(" tx=");
1303                     TimeUtils.formatDuration(lastTxMs, sb);
1304                     sb.append(" e=").append(lastEnergy);
1305                     sb.append("\n");
1306                     sb.append("Current WiFi snapshot: ").append("idle=");
1307                     TimeUtils.formatDuration(info.mControllerIdleTimeMs, sb);
1308                     sb.append(" rx=");
1309                     TimeUtils.formatDuration(info.mControllerRxTimeMs, sb);
1310                     sb.append(" tx=");
1311                     TimeUtils.formatDuration(info.mControllerTxTimeMs, sb);
1312                     sb.append(" e=").append(info.mControllerEnergyUsed);
1313                     Slog.wtf(TAG, sb.toString());
1314                 }
1315
1316                 mLastInfo = info;
1317                 return result;
1318             }
1319         } catch (RemoteException e) {
1320             // Nothing to report, WiFi is dead.
1321         }
1322         return null;
1323     }
1324
1325     @GuardedBy("mExternalStatsLock")
1326     private BluetoothActivityEnergyInfo pullBluetoothEnergyInfoLocked() {
1327         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1328         if (adapter != null) {
1329             BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo(
1330                     BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED);
1331             if (info != null && info.isValid()) {
1332                 if (info.getControllerEnergyUsed() < 0 || info.getControllerIdleTimeMillis() < 0 ||
1333                         info.getControllerRxTimeMillis() < 0 || info.getControllerTxTimeMillis() < 0) {
1334                     Slog.wtf(TAG, "Bluetooth energy data is invalid: " + info);
1335                 }
1336                 return info;
1337             }
1338         }
1339         return null;
1340     }
1341
1342     @GuardedBy("mExternalStatsLock")
1343     private ModemActivityInfo pullModemActivityInfoLocked() {
1344         ITelephony tm = ITelephony.Stub.asInterface(ServiceManager.getService(
1345                 Context.TELEPHONY_SERVICE));
1346         try {
1347             if (tm != null) {
1348                 ModemActivityInfo info = tm.getModemActivityInfo();
1349                 if (info == null || info.isValid()) {
1350                     return info;
1351                 }
1352                 Slog.wtf(TAG, "Modem activity info is invalid: " + info);
1353             }
1354         } catch (RemoteException e) {
1355             // Nothing to do.
1356         }
1357         return null;
1358     }
1359
1360     /**
1361      * Fetches data from external sources (WiFi controller, bluetooth chipset) and updates
1362      * batterystats with that information.
1363      *
1364      * We first grab a lock specific to this method, then once all the data has been collected,
1365      * we grab the mStats lock and update the data.
1366      *
1367      * @param reason The reason why this collection was requested. Useful for debugging.
1368      * @param updateFlags Which external stats to update. Can be a combination of
1369      *                    {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_CPU},
1370      *                    {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_RADIO},
1371      *                    {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_WIFI},
1372      *                    and {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_BT}.
1373      */
1374     void updateExternalStats(final String reason, final int updateFlags) {
1375         synchronized (mExternalStatsLock) {
1376             if (mContext == null) {
1377                 // We haven't started yet (which means the BatteryStatsImpl object has
1378                 // no power profile. Don't consume data we can't compute yet.
1379                 return;
1380             }
1381
1382             if (BatteryStatsImpl.DEBUG_ENERGY) {
1383                 Slog.d(TAG, "Updating external stats: reason=" + reason);
1384             }
1385
1386             WifiActivityEnergyInfo wifiEnergyInfo = null;
1387             if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
1388                 wifiEnergyInfo = pullWifiEnergyInfoLocked();
1389             }
1390
1391             ModemActivityInfo modemActivityInfo = null;
1392             if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) {
1393                 modemActivityInfo = pullModemActivityInfoLocked();
1394             }
1395
1396             BluetoothActivityEnergyInfo bluetoothEnergyInfo = null;
1397             if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_BT) != 0) {
1398                 // We only pull bluetooth stats when we have to, as we are not distributing its
1399                 // use amongst apps and the sampling frequency does not matter.
1400                 bluetoothEnergyInfo = pullBluetoothEnergyInfoLocked();
1401             }
1402
1403             synchronized (mStats) {
1404                 final long elapsedRealtime = SystemClock.elapsedRealtime();
1405                 final long uptime = SystemClock.uptimeMillis();
1406                 if (mStats.mRecordAllHistory) {
1407                     mStats.addHistoryEventLocked(elapsedRealtime, uptime,
1408                             BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS, reason, 0);
1409                 }
1410
1411                 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_CPU) != 0) {
1412                     mStats.updateCpuTimeLocked();
1413                     mStats.updateKernelWakelocksLocked();
1414                 }
1415
1416                 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) {
1417                     mStats.updateMobileRadioStateLocked(elapsedRealtime, modemActivityInfo);
1418                 }
1419
1420                 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
1421                     mStats.updateWifiStateLocked(wifiEnergyInfo);
1422                 }
1423
1424                 if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_BT) != 0) {
1425                     mStats.updateBluetoothStateLocked(bluetoothEnergyInfo);
1426                 }
1427             }
1428         }
1429     }
1430
1431     /**
1432      * Gets a snapshot of the system health for a particular uid.
1433      */
1434     @Override
1435     public HealthStatsParceler takeUidSnapshot(int requestUid) {
1436         if (requestUid != Binder.getCallingUid()) {
1437             mContext.enforceCallingOrSelfPermission(
1438                     android.Manifest.permission.BATTERY_STATS, null);
1439         }
1440         long ident = Binder.clearCallingIdentity();
1441         try {
1442             updateExternalStats("get-health-stats-for-uid",
1443                     BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
1444             synchronized (mStats) {
1445                 return getHealthStatsForUidLocked(requestUid);
1446             }
1447         } catch (Exception ex) {
1448             Slog.d(TAG, "Crashed while writing for takeUidSnapshot(" + requestUid + ")", ex);
1449             throw ex;
1450         } finally {
1451             Binder.restoreCallingIdentity(ident);
1452         }
1453     }
1454
1455     /**
1456      * Gets a snapshot of the system health for a number of uids.
1457      */
1458     @Override
1459     public HealthStatsParceler[] takeUidSnapshots(int[] requestUids) {
1460         if (!onlyCaller(requestUids)) {
1461             mContext.enforceCallingOrSelfPermission(
1462                     android.Manifest.permission.BATTERY_STATS, null);
1463         }
1464         long ident = Binder.clearCallingIdentity();
1465         int i=-1;
1466         try {
1467             updateExternalStats("get-health-stats-for-uids",
1468                     BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
1469             synchronized (mStats) {
1470                 final int N = requestUids.length;
1471                 final HealthStatsParceler[] results = new HealthStatsParceler[N];
1472                 for (i=0; i<N; i++) {
1473                     results[i] = getHealthStatsForUidLocked(requestUids[i]);
1474                 }
1475                 return results;
1476             }
1477         } catch (Exception ex) {
1478             Slog.d(TAG, "Crashed while writing for takeUidSnapshots("
1479                     + Arrays.toString(requestUids) + ") i=" + i, ex);
1480             throw ex;
1481         } finally {
1482             Binder.restoreCallingIdentity(ident);
1483         }
1484     }
1485
1486     /**
1487      * Returns whether the Binder.getCallingUid is the only thing in requestUids.
1488      */
1489     private static boolean onlyCaller(int[] requestUids) {
1490         final int caller = Binder.getCallingUid();
1491         final int N = requestUids.length;
1492         for (int i=0; i<N; i++) {
1493             if (requestUids[i] != caller) {
1494                 return false;
1495             }
1496         }
1497         return true;
1498     }
1499
1500     /**
1501      * Gets a HealthStatsParceler for the given uid. You should probably call
1502      * updateExternalStats first.
1503      */
1504     HealthStatsParceler getHealthStatsForUidLocked(int requestUid) {
1505         final HealthStatsBatteryStatsWriter writer = new HealthStatsBatteryStatsWriter();
1506         final HealthStatsWriter uidWriter = new HealthStatsWriter(UidHealthStats.CONSTANTS);
1507         final BatteryStats.Uid uid = mStats.getUidStats().get(requestUid);
1508         if (uid != null) {
1509             writer.writeUid(uidWriter, mStats, uid);
1510         }
1511         return new HealthStatsParceler(uidWriter);
1512     }
1513
1514 }