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 
BatteryStatsHandler(Looper looper)118         public BatteryStatsHandler(Looper looper) {
119             super(looper);
120         }
121 
122         @Override
handleMessage(Message msg)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
scheduleSync(String reason, int updateFlags)158         public void scheduleSync(String reason, int updateFlags) {
159             synchronized (this) {
160                 scheduleSyncLocked(reason, updateFlags);
161             }
162         }
163 
164         @Override
scheduleCpuSyncDueToRemovedUid(int uid)165         public void scheduleCpuSyncDueToRemovedUid(int uid) {
166             synchronized (this) {
167                 scheduleSyncLocked("remove-uid", UPDATE_CPU);
168                 mUidsToRemove.add(uid);
169             }
170         }
171 
scheduleSyncLocked(String reason, int updateFlags)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 
getPlatformLowPowerStats(ByteBuffer outBuffer)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
getPlatformLowPowerStats()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 
BatteryStatsService(File systemDir, Handler handler)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 
publish(Context context)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      */
initPowerManagement()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 
shutdown()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 
getService()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
onLowPowerModeChanged(boolean enabled)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      */
getActiveStatistics()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      */
scheduleWriteToDisk()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      */
removeUid(int uid)289     void removeUid(int uid) {
290         synchronized (mStats) {
291             mStats.removeUidStatsLocked(uid);
292         }
293     }
294 
addIsolatedUid(int isolatedUid, int appUid)295     void addIsolatedUid(int isolatedUid, int appUid) {
296         synchronized (mStats) {
297             mStats.addIsolatedUidLocked(isolatedUid, appUid);
298         }
299     }
300 
removeIsolatedUid(int isolatedUid, int appUid)301     void removeIsolatedUid(int isolatedUid, int appUid) {
302         synchronized (mStats) {
303             mStats.scheduleRemoveIsolatedUidLocked(isolatedUid, appUid);
304         }
305     }
306 
noteProcessStart(String name, int uid)307     void noteProcessStart(String name, int uid) {
308         synchronized (mStats) {
309             mStats.noteProcessStartLocked(name, uid);
310         }
311     }
312 
noteProcessCrash(String name, int uid)313     void noteProcessCrash(String name, int uid) {
314         synchronized (mStats) {
315             mStats.noteProcessCrashLocked(name, uid);
316         }
317     }
318 
noteProcessAnr(String name, int uid)319     void noteProcessAnr(String name, int uid) {
320         synchronized (mStats) {
321             mStats.noteProcessAnrLocked(name, uid);
322         }
323     }
324 
noteProcessFinish(String name, int uid)325     void noteProcessFinish(String name, int uid) {
326         synchronized (mStats) {
327             mStats.noteProcessFinishLocked(name, uid);
328         }
329     }
330 
noteUidProcessState(int uid, int state)331     void noteUidProcessState(int uid, int state) {
332         synchronized (mStats) {
333             mStats.noteUidProcessStateLocked(uid, state);
334         }
335     }
336 
337     // Public interface...
338 
getStatistics()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 
getStatisticsStream()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 
isCharging()374     public boolean isCharging() {
375         synchronized (mStats) {
376             return mStats.isCharging();
377         }
378     }
379 
computeBatteryTimeRemaining()380     public long computeBatteryTimeRemaining() {
381         synchronized (mStats) {
382             long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
383             return time >= 0 ? (time/1000) : time;
384         }
385     }
386 
computeChargeTimeRemaining()387     public long computeChargeTimeRemaining() {
388         synchronized (mStats) {
389             long time = mStats.computeChargeTimeRemaining(SystemClock.elapsedRealtime());
390             return time >= 0 ? (time/1000) : time;
391         }
392     }
393 
noteEvent(int code, String name, int uid)394     public void noteEvent(int code, String name, int uid) {
395         enforceCallingPermission();
396         synchronized (mStats) {
397             mStats.noteEventLocked(code, name, uid);
398         }
399     }
400 
noteSyncStart(String name, int uid)401     public void noteSyncStart(String name, int uid) {
402         enforceCallingPermission();
403         synchronized (mStats) {
404             mStats.noteSyncStartLocked(name, uid);
405         }
406     }
407 
noteSyncFinish(String name, int uid)408     public void noteSyncFinish(String name, int uid) {
409         enforceCallingPermission();
410         synchronized (mStats) {
411             mStats.noteSyncFinishLocked(name, uid);
412         }
413     }
414 
noteJobStart(String name, int uid)415     public void noteJobStart(String name, int uid) {
416         enforceCallingPermission();
417         synchronized (mStats) {
418             mStats.noteJobStartLocked(name, uid);
419         }
420     }
421 
noteJobFinish(String name, int uid)422     public void noteJobFinish(String name, int uid) {
423         enforceCallingPermission();
424         synchronized (mStats) {
425             mStats.noteJobFinishLocked(name, uid);
426         }
427     }
428 
noteAlarmStart(String name, int uid)429     public void noteAlarmStart(String name, int uid) {
430         enforceCallingPermission();
431         synchronized (mStats) {
432             mStats.noteAlarmStartLocked(name, uid);
433         }
434     }
435 
noteAlarmFinish(String name, int uid)436     public void noteAlarmFinish(String name, int uid) {
437         enforceCallingPermission();
438         synchronized (mStats) {
439             mStats.noteAlarmFinishLocked(name, uid);
440         }
441     }
442 
noteStartWakelock(int uid, int pid, String name, String historyName, int type, boolean unimportantForLogging)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 
noteStopWakelock(int uid, int pid, String name, String historyName, int type)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 
noteStartWakelockFromSource(WorkSource ws, int pid, String name, String historyName, int type, boolean unimportantForLogging)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 
noteChangeWakelockFromSource(WorkSource ws, int pid, String name, String historyName, int type, WorkSource newWs, int newPid, String newName, String newHistoryName, int newType, boolean newUnimportantForLogging)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 
noteStopWakelockFromSource(WorkSource ws, int pid, String name, String historyName, int type)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 
noteStartSensor(int uid, int sensor)487     public void noteStartSensor(int uid, int sensor) {
488         enforceCallingPermission();
489         synchronized (mStats) {
490             mStats.noteStartSensorLocked(uid, sensor);
491         }
492     }
493 
noteStopSensor(int uid, int sensor)494     public void noteStopSensor(int uid, int sensor) {
495         enforceCallingPermission();
496         synchronized (mStats) {
497             mStats.noteStopSensorLocked(uid, sensor);
498         }
499     }
500 
noteVibratorOn(int uid, long durationMillis)501     public void noteVibratorOn(int uid, long durationMillis) {
502         enforceCallingPermission();
503         synchronized (mStats) {
504             mStats.noteVibratorOnLocked(uid, durationMillis);
505         }
506     }
507 
noteVibratorOff(int uid)508     public void noteVibratorOff(int uid) {
509         enforceCallingPermission();
510         synchronized (mStats) {
511             mStats.noteVibratorOffLocked(uid);
512         }
513     }
514 
noteStartGps(int uid)515     public void noteStartGps(int uid) {
516         enforceCallingPermission();
517         synchronized (mStats) {
518             mStats.noteStartGpsLocked(uid);
519         }
520     }
521 
noteStopGps(int uid)522     public void noteStopGps(int uid) {
523         enforceCallingPermission();
524         synchronized (mStats) {
525             mStats.noteStopGpsLocked(uid);
526         }
527     }
528 
noteScreenState(int state)529     public void noteScreenState(int state) {
530         enforceCallingPermission();
531         synchronized (mStats) {
532             mStats.noteScreenStateLocked(state);
533         }
534     }
535 
noteScreenBrightness(int brightness)536     public void noteScreenBrightness(int brightness) {
537         enforceCallingPermission();
538         synchronized (mStats) {
539             mStats.noteScreenBrightnessLocked(brightness);
540         }
541     }
542 
noteUserActivity(int uid, int event)543     public void noteUserActivity(int uid, int event) {
544         enforceCallingPermission();
545         synchronized (mStats) {
546             mStats.noteUserActivityLocked(uid, event);
547         }
548     }
549 
noteWakeUp(String reason, int reasonUid)550     public void noteWakeUp(String reason, int reasonUid) {
551         enforceCallingPermission();
552         synchronized (mStats) {
553             mStats.noteWakeUpLocked(reason, reasonUid);
554         }
555     }
556 
noteInteractive(boolean interactive)557     public void noteInteractive(boolean interactive) {
558         enforceCallingPermission();
559         synchronized (mStats) {
560             mStats.noteInteractiveLocked(interactive);
561         }
562     }
563 
noteConnectivityChanged(int type, String extra)564     public void noteConnectivityChanged(int type, String extra) {
565         enforceCallingPermission();
566         synchronized (mStats) {
567             mStats.noteConnectivityChangedLocked(type, extra);
568         }
569     }
570 
noteMobileRadioPowerState(int powerState, long timestampNs, int uid)571     public void noteMobileRadioPowerState(int powerState, long timestampNs, int uid) {
572         enforceCallingPermission();
573         synchronized (mStats) {
574             mStats.noteMobileRadioPowerState(powerState, timestampNs, uid);
575         }
576     }
577 
notePhoneOn()578     public void notePhoneOn() {
579         enforceCallingPermission();
580         synchronized (mStats) {
581             mStats.notePhoneOnLocked();
582         }
583     }
584 
notePhoneOff()585     public void notePhoneOff() {
586         enforceCallingPermission();
587         synchronized (mStats) {
588             mStats.notePhoneOffLocked();
589         }
590     }
591 
notePhoneSignalStrength(SignalStrength signalStrength)592     public void notePhoneSignalStrength(SignalStrength signalStrength) {
593         enforceCallingPermission();
594         synchronized (mStats) {
595             mStats.notePhoneSignalStrengthLocked(signalStrength);
596         }
597     }
598 
notePhoneDataConnectionState(int dataType, boolean hasData)599     public void notePhoneDataConnectionState(int dataType, boolean hasData) {
600         enforceCallingPermission();
601         synchronized (mStats) {
602             mStats.notePhoneDataConnectionStateLocked(dataType, hasData);
603         }
604     }
605 
notePhoneState(int state)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 
noteWifiOn()614     public void noteWifiOn() {
615         enforceCallingPermission();
616         synchronized (mStats) {
617             mStats.noteWifiOnLocked();
618         }
619     }
620 
noteWifiOff()621     public void noteWifiOff() {
622         enforceCallingPermission();
623         synchronized (mStats) {
624             mStats.noteWifiOffLocked();
625         }
626     }
627 
noteStartAudio(int uid)628     public void noteStartAudio(int uid) {
629         enforceCallingPermission();
630         synchronized (mStats) {
631             mStats.noteAudioOnLocked(uid);
632         }
633     }
634 
noteStopAudio(int uid)635     public void noteStopAudio(int uid) {
636         enforceCallingPermission();
637         synchronized (mStats) {
638             mStats.noteAudioOffLocked(uid);
639         }
640     }
641 
noteStartVideo(int uid)642     public void noteStartVideo(int uid) {
643         enforceCallingPermission();
644         synchronized (mStats) {
645             mStats.noteVideoOnLocked(uid);
646         }
647     }
648 
noteStopVideo(int uid)649     public void noteStopVideo(int uid) {
650         enforceCallingPermission();
651         synchronized (mStats) {
652             mStats.noteVideoOffLocked(uid);
653         }
654     }
655 
noteResetAudio()656     public void noteResetAudio() {
657         enforceCallingPermission();
658         synchronized (mStats) {
659             mStats.noteResetAudioLocked();
660         }
661     }
662 
noteResetVideo()663     public void noteResetVideo() {
664         enforceCallingPermission();
665         synchronized (mStats) {
666             mStats.noteResetVideoLocked();
667         }
668     }
669 
noteFlashlightOn(int uid)670     public void noteFlashlightOn(int uid) {
671         enforceCallingPermission();
672         synchronized (mStats) {
673             mStats.noteFlashlightOnLocked(uid);
674         }
675     }
676 
noteFlashlightOff(int uid)677     public void noteFlashlightOff(int uid) {
678         enforceCallingPermission();
679         synchronized (mStats) {
680             mStats.noteFlashlightOffLocked(uid);
681         }
682     }
683 
noteStartCamera(int uid)684     public void noteStartCamera(int uid) {
685         enforceCallingPermission();
686         synchronized (mStats) {
687             mStats.noteCameraOnLocked(uid);
688         }
689     }
690 
noteStopCamera(int uid)691     public void noteStopCamera(int uid) {
692         enforceCallingPermission();
693         synchronized (mStats) {
694             mStats.noteCameraOffLocked(uid);
695         }
696     }
697 
noteResetCamera()698     public void noteResetCamera() {
699         enforceCallingPermission();
700         synchronized (mStats) {
701             mStats.noteResetCameraLocked();
702         }
703     }
704 
noteResetFlashlight()705     public void noteResetFlashlight() {
706         enforceCallingPermission();
707         synchronized (mStats) {
708             mStats.noteResetFlashlightLocked();
709         }
710     }
711 
712     @Override
noteWifiRadioPowerState(int powerState, long tsNanos)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 
noteWifiRunning(WorkSource ws)730     public void noteWifiRunning(WorkSource ws) {
731         enforceCallingPermission();
732         synchronized (mStats) {
733             mStats.noteWifiRunningLocked(ws);
734         }
735     }
736 
noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs)737     public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) {
738         enforceCallingPermission();
739         synchronized (mStats) {
740             mStats.noteWifiRunningChangedLocked(oldWs, newWs);
741         }
742     }
743 
noteWifiStopped(WorkSource ws)744     public void noteWifiStopped(WorkSource ws) {
745         enforceCallingPermission();
746         synchronized (mStats) {
747             mStats.noteWifiStoppedLocked(ws);
748         }
749     }
750 
noteWifiState(int wifiState, String accessPoint)751     public void noteWifiState(int wifiState, String accessPoint) {
752         enforceCallingPermission();
753         synchronized (mStats) {
754             mStats.noteWifiStateLocked(wifiState, accessPoint);
755         }
756     }
757 
noteWifiSupplicantStateChanged(int supplState, boolean failedAuth)758     public void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth) {
759         enforceCallingPermission();
760         synchronized (mStats) {
761             mStats.noteWifiSupplicantStateChangedLocked(supplState, failedAuth);
762         }
763     }
764 
noteWifiRssiChanged(int newRssi)765     public void noteWifiRssiChanged(int newRssi) {
766         enforceCallingPermission();
767         synchronized (mStats) {
768             mStats.noteWifiRssiChangedLocked(newRssi);
769         }
770     }
771 
noteFullWifiLockAcquired(int uid)772     public void noteFullWifiLockAcquired(int uid) {
773         enforceCallingPermission();
774         synchronized (mStats) {
775             mStats.noteFullWifiLockAcquiredLocked(uid);
776         }
777     }
778 
noteFullWifiLockReleased(int uid)779     public void noteFullWifiLockReleased(int uid) {
780         enforceCallingPermission();
781         synchronized (mStats) {
782             mStats.noteFullWifiLockReleasedLocked(uid);
783         }
784     }
785 
noteWifiScanStarted(int uid)786     public void noteWifiScanStarted(int uid) {
787         enforceCallingPermission();
788         synchronized (mStats) {
789             mStats.noteWifiScanStartedLocked(uid);
790         }
791     }
792 
noteWifiScanStopped(int uid)793     public void noteWifiScanStopped(int uid) {
794         enforceCallingPermission();
795         synchronized (mStats) {
796             mStats.noteWifiScanStoppedLocked(uid);
797         }
798     }
799 
noteWifiMulticastEnabled(int uid)800     public void noteWifiMulticastEnabled(int uid) {
801         enforceCallingPermission();
802         synchronized (mStats) {
803             mStats.noteWifiMulticastEnabledLocked(uid);
804         }
805     }
806 
noteWifiMulticastDisabled(int uid)807     public void noteWifiMulticastDisabled(int uid) {
808         enforceCallingPermission();
809         synchronized (mStats) {
810             mStats.noteWifiMulticastDisabledLocked(uid);
811         }
812     }
813 
noteFullWifiLockAcquiredFromSource(WorkSource ws)814     public void noteFullWifiLockAcquiredFromSource(WorkSource ws) {
815         enforceCallingPermission();
816         synchronized (mStats) {
817             mStats.noteFullWifiLockAcquiredFromSourceLocked(ws);
818         }
819     }
820 
noteFullWifiLockReleasedFromSource(WorkSource ws)821     public void noteFullWifiLockReleasedFromSource(WorkSource ws) {
822         enforceCallingPermission();
823         synchronized (mStats) {
824             mStats.noteFullWifiLockReleasedFromSourceLocked(ws);
825         }
826     }
827 
noteWifiScanStartedFromSource(WorkSource ws)828     public void noteWifiScanStartedFromSource(WorkSource ws) {
829         enforceCallingPermission();
830         synchronized (mStats) {
831             mStats.noteWifiScanStartedFromSourceLocked(ws);
832         }
833     }
834 
noteWifiScanStoppedFromSource(WorkSource ws)835     public void noteWifiScanStoppedFromSource(WorkSource ws) {
836         enforceCallingPermission();
837         synchronized (mStats) {
838             mStats.noteWifiScanStoppedFromSourceLocked(ws);
839         }
840     }
841 
noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph)842     public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) {
843         enforceCallingPermission();
844         synchronized (mStats) {
845             mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph);
846         }
847     }
848 
noteWifiBatchedScanStoppedFromSource(WorkSource ws)849     public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) {
850         enforceCallingPermission();
851         synchronized (mStats) {
852             mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws);
853         }
854     }
855 
noteWifiMulticastEnabledFromSource(WorkSource ws)856     public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
857         enforceCallingPermission();
858         synchronized (mStats) {
859             mStats.noteWifiMulticastEnabledFromSourceLocked(ws);
860         }
861     }
862 
863     @Override
noteWifiMulticastDisabledFromSource(WorkSource ws)864     public void noteWifiMulticastDisabledFromSource(WorkSource ws) {
865         enforceCallingPermission();
866         synchronized (mStats) {
867             mStats.noteWifiMulticastDisabledFromSourceLocked(ws);
868         }
869     }
870 
871     @Override
noteNetworkInterfaceType(String iface, int networkType)872     public void noteNetworkInterfaceType(String iface, int networkType) {
873         enforceCallingPermission();
874         synchronized (mStats) {
875             mStats.noteNetworkInterfaceTypeLocked(iface, networkType);
876         }
877     }
878 
879     @Override
noteNetworkStatsEnabled()880     public void noteNetworkStatsEnabled() {
881         enforceCallingPermission();
882         synchronized (mStats) {
883             mStats.noteNetworkStatsEnabledLocked();
884         }
885     }
886 
887     @Override
noteDeviceIdleMode(int mode, String activeReason, int activeUid)888     public void noteDeviceIdleMode(int mode, String activeReason, int activeUid) {
889         enforceCallingPermission();
890         synchronized (mStats) {
891             mStats.noteDeviceIdleModeLocked(mode, activeReason, activeUid);
892         }
893     }
894 
notePackageInstalled(String pkgName, int versionCode)895     public void notePackageInstalled(String pkgName, int versionCode) {
896         enforceCallingPermission();
897         synchronized (mStats) {
898             mStats.notePackageInstalledLocked(pkgName, versionCode);
899         }
900     }
901 
notePackageUninstalled(String pkgName)902     public void notePackageUninstalled(String pkgName) {
903         enforceCallingPermission();
904         synchronized (mStats) {
905             mStats.notePackageUninstalledLocked(pkgName);
906         }
907     }
908 
909     @Override
noteBleScanStarted(WorkSource ws)910     public void noteBleScanStarted(WorkSource ws) {
911         enforceCallingPermission();
912         synchronized (mStats) {
913             mStats.noteBluetoothScanStartedFromSourceLocked(ws);
914         }
915     }
916 
917     @Override
noteBleScanStopped(WorkSource ws)918     public void noteBleScanStopped(WorkSource ws) {
919         enforceCallingPermission();
920         synchronized (mStats) {
921             mStats.noteBluetoothScanStoppedFromSourceLocked(ws);
922         }
923     }
924 
925     @Override
noteResetBleScan()926     public void noteResetBleScan() {
927         enforceCallingPermission();
928         synchronized (mStats) {
929             mStats.noteResetBluetoothScanLocked();
930         }
931     }
932 
933     @Override
noteWifiControllerActivity(WifiActivityEnergyInfo info)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
noteBluetoothControllerActivity(BluetoothActivityEnergyInfo info)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
noteModemControllerActivity(ModemActivityInfo info)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 
isOnBattery()974     public boolean isOnBattery() {
975         return mStats.isOnBattery();
976     }
977 
978     @Override
setBatteryState(final int status, final int health, final int plugType, final int level, final int temp, final int volt, final int chargeUAh)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 
getAwakeTimeBattery()1010     public long getAwakeTimeBattery() {
1011         mContext.enforceCallingOrSelfPermission(
1012                 android.Manifest.permission.BATTERY_STATS, null);
1013         return mStats.getAwakeTimeBattery();
1014     }
1015 
getAwakeTimePlugged()1016     public long getAwakeTimePlugged() {
1017         mContext.enforceCallingOrSelfPermission(
1018                 android.Manifest.permission.BATTERY_STATS, null);
1019         return mStats.getAwakeTimePlugged();
1020     }
1021 
enforceCallingPermission()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 
WakeupReasonThread()1036         WakeupReasonThread() {
1037             super("BatteryStats_wakeupReason");
1038         }
1039 
run()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 
waitWakeup()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 
nativeWaitWakeup(ByteBuffer outBuffer)1089     private static native int nativeWaitWakeup(ByteBuffer outBuffer);
1090 
dumpHelp(PrintWriter pw)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 
doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable)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
dump(FileDescriptor fd, PrintWriter pw, String[] args)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 
extractDelta(WifiActivityEnergyInfo latest)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      */
awaitControllerInfo( @ullable SynchronousResultReceiver receiver)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      */
updateExternalStatsSync(final String reason, int updateFlags)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
takeUidSnapshot(int requestUid)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
takeUidSnapshots(int[] requestUids)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      */
onlyCaller(int[] requestUids)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      */
getHealthStatsForUidLocked(int requestUid)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 }
1618