OSDN Git Service

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