• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
noteLongPartialWakelockStart(String name, String historyName, int uid)487     public void noteLongPartialWakelockStart(String name, String historyName, int uid) {
488         enforceCallingPermission();
489         synchronized (mStats) {
490             mStats.noteLongPartialWakelockStart(name, historyName, uid);
491         }
492     }
493 
noteLongPartialWakelockFinish(String name, String historyName, int uid)494     public void noteLongPartialWakelockFinish(String name, String historyName, int uid) {
495         enforceCallingPermission();
496         synchronized (mStats) {
497             mStats.noteLongPartialWakelockFinish(name, historyName, uid);
498         }
499     }
500 
noteStartSensor(int uid, int sensor)501     public void noteStartSensor(int uid, int sensor) {
502         enforceCallingPermission();
503         synchronized (mStats) {
504             mStats.noteStartSensorLocked(uid, sensor);
505         }
506     }
507 
noteStopSensor(int uid, int sensor)508     public void noteStopSensor(int uid, int sensor) {
509         enforceCallingPermission();
510         synchronized (mStats) {
511             mStats.noteStopSensorLocked(uid, sensor);
512         }
513     }
514 
noteVibratorOn(int uid, long durationMillis)515     public void noteVibratorOn(int uid, long durationMillis) {
516         enforceCallingPermission();
517         synchronized (mStats) {
518             mStats.noteVibratorOnLocked(uid, durationMillis);
519         }
520     }
521 
noteVibratorOff(int uid)522     public void noteVibratorOff(int uid) {
523         enforceCallingPermission();
524         synchronized (mStats) {
525             mStats.noteVibratorOffLocked(uid);
526         }
527     }
528 
noteStartGps(int uid)529     public void noteStartGps(int uid) {
530         enforceCallingPermission();
531         synchronized (mStats) {
532             mStats.noteStartGpsLocked(uid);
533         }
534     }
535 
noteStopGps(int uid)536     public void noteStopGps(int uid) {
537         enforceCallingPermission();
538         synchronized (mStats) {
539             mStats.noteStopGpsLocked(uid);
540         }
541     }
542 
noteScreenState(int state)543     public void noteScreenState(int state) {
544         enforceCallingPermission();
545         synchronized (mStats) {
546             mStats.noteScreenStateLocked(state);
547         }
548     }
549 
noteScreenBrightness(int brightness)550     public void noteScreenBrightness(int brightness) {
551         enforceCallingPermission();
552         synchronized (mStats) {
553             mStats.noteScreenBrightnessLocked(brightness);
554         }
555     }
556 
noteUserActivity(int uid, int event)557     public void noteUserActivity(int uid, int event) {
558         enforceCallingPermission();
559         synchronized (mStats) {
560             mStats.noteUserActivityLocked(uid, event);
561         }
562     }
563 
noteWakeUp(String reason, int reasonUid)564     public void noteWakeUp(String reason, int reasonUid) {
565         enforceCallingPermission();
566         synchronized (mStats) {
567             mStats.noteWakeUpLocked(reason, reasonUid);
568         }
569     }
570 
noteInteractive(boolean interactive)571     public void noteInteractive(boolean interactive) {
572         enforceCallingPermission();
573         synchronized (mStats) {
574             mStats.noteInteractiveLocked(interactive);
575         }
576     }
577 
noteConnectivityChanged(int type, String extra)578     public void noteConnectivityChanged(int type, String extra) {
579         enforceCallingPermission();
580         synchronized (mStats) {
581             mStats.noteConnectivityChangedLocked(type, extra);
582         }
583     }
584 
noteMobileRadioPowerState(int powerState, long timestampNs, int uid)585     public void noteMobileRadioPowerState(int powerState, long timestampNs, int uid) {
586         enforceCallingPermission();
587         synchronized (mStats) {
588             mStats.noteMobileRadioPowerState(powerState, timestampNs, uid);
589         }
590     }
591 
notePhoneOn()592     public void notePhoneOn() {
593         enforceCallingPermission();
594         synchronized (mStats) {
595             mStats.notePhoneOnLocked();
596         }
597     }
598 
notePhoneOff()599     public void notePhoneOff() {
600         enforceCallingPermission();
601         synchronized (mStats) {
602             mStats.notePhoneOffLocked();
603         }
604     }
605 
notePhoneSignalStrength(SignalStrength signalStrength)606     public void notePhoneSignalStrength(SignalStrength signalStrength) {
607         enforceCallingPermission();
608         synchronized (mStats) {
609             mStats.notePhoneSignalStrengthLocked(signalStrength);
610         }
611     }
612 
notePhoneDataConnectionState(int dataType, boolean hasData)613     public void notePhoneDataConnectionState(int dataType, boolean hasData) {
614         enforceCallingPermission();
615         synchronized (mStats) {
616             mStats.notePhoneDataConnectionStateLocked(dataType, hasData);
617         }
618     }
619 
notePhoneState(int state)620     public void notePhoneState(int state) {
621         enforceCallingPermission();
622         int simState = TelephonyManager.getDefault().getSimState();
623         synchronized (mStats) {
624             mStats.notePhoneStateLocked(state, simState);
625         }
626     }
627 
noteWifiOn()628     public void noteWifiOn() {
629         enforceCallingPermission();
630         synchronized (mStats) {
631             mStats.noteWifiOnLocked();
632         }
633     }
634 
noteWifiOff()635     public void noteWifiOff() {
636         enforceCallingPermission();
637         synchronized (mStats) {
638             mStats.noteWifiOffLocked();
639         }
640     }
641 
noteStartAudio(int uid)642     public void noteStartAudio(int uid) {
643         enforceCallingPermission();
644         synchronized (mStats) {
645             mStats.noteAudioOnLocked(uid);
646         }
647     }
648 
noteStopAudio(int uid)649     public void noteStopAudio(int uid) {
650         enforceCallingPermission();
651         synchronized (mStats) {
652             mStats.noteAudioOffLocked(uid);
653         }
654     }
655 
noteStartVideo(int uid)656     public void noteStartVideo(int uid) {
657         enforceCallingPermission();
658         synchronized (mStats) {
659             mStats.noteVideoOnLocked(uid);
660         }
661     }
662 
noteStopVideo(int uid)663     public void noteStopVideo(int uid) {
664         enforceCallingPermission();
665         synchronized (mStats) {
666             mStats.noteVideoOffLocked(uid);
667         }
668     }
669 
noteResetAudio()670     public void noteResetAudio() {
671         enforceCallingPermission();
672         synchronized (mStats) {
673             mStats.noteResetAudioLocked();
674         }
675     }
676 
noteResetVideo()677     public void noteResetVideo() {
678         enforceCallingPermission();
679         synchronized (mStats) {
680             mStats.noteResetVideoLocked();
681         }
682     }
683 
noteFlashlightOn(int uid)684     public void noteFlashlightOn(int uid) {
685         enforceCallingPermission();
686         synchronized (mStats) {
687             mStats.noteFlashlightOnLocked(uid);
688         }
689     }
690 
noteFlashlightOff(int uid)691     public void noteFlashlightOff(int uid) {
692         enforceCallingPermission();
693         synchronized (mStats) {
694             mStats.noteFlashlightOffLocked(uid);
695         }
696     }
697 
noteStartCamera(int uid)698     public void noteStartCamera(int uid) {
699         enforceCallingPermission();
700         synchronized (mStats) {
701             mStats.noteCameraOnLocked(uid);
702         }
703     }
704 
noteStopCamera(int uid)705     public void noteStopCamera(int uid) {
706         enforceCallingPermission();
707         synchronized (mStats) {
708             mStats.noteCameraOffLocked(uid);
709         }
710     }
711 
noteResetCamera()712     public void noteResetCamera() {
713         enforceCallingPermission();
714         synchronized (mStats) {
715             mStats.noteResetCameraLocked();
716         }
717     }
718 
noteResetFlashlight()719     public void noteResetFlashlight() {
720         enforceCallingPermission();
721         synchronized (mStats) {
722             mStats.noteResetFlashlightLocked();
723         }
724     }
725 
726     @Override
noteWifiRadioPowerState(int powerState, long tsNanos, int uid)727     public void noteWifiRadioPowerState(int powerState, long tsNanos, int uid) {
728         enforceCallingPermission();
729 
730         // There was a change in WiFi power state.
731         // Collect data now for the past activity.
732         synchronized (mStats) {
733             if (mStats.isOnBattery()) {
734                 final String type = (powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH ||
735                         powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM) ? "active"
736                         : "inactive";
737                 mHandler.scheduleSync("wifi-data: " + type,
738                         BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI);
739             }
740             mStats.noteWifiRadioPowerState(powerState, tsNanos, uid);
741         }
742     }
743 
noteWifiRunning(WorkSource ws)744     public void noteWifiRunning(WorkSource ws) {
745         enforceCallingPermission();
746         synchronized (mStats) {
747             mStats.noteWifiRunningLocked(ws);
748         }
749     }
750 
noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs)751     public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) {
752         enforceCallingPermission();
753         synchronized (mStats) {
754             mStats.noteWifiRunningChangedLocked(oldWs, newWs);
755         }
756     }
757 
noteWifiStopped(WorkSource ws)758     public void noteWifiStopped(WorkSource ws) {
759         enforceCallingPermission();
760         synchronized (mStats) {
761             mStats.noteWifiStoppedLocked(ws);
762         }
763     }
764 
noteWifiState(int wifiState, String accessPoint)765     public void noteWifiState(int wifiState, String accessPoint) {
766         enforceCallingPermission();
767         synchronized (mStats) {
768             mStats.noteWifiStateLocked(wifiState, accessPoint);
769         }
770     }
771 
noteWifiSupplicantStateChanged(int supplState, boolean failedAuth)772     public void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth) {
773         enforceCallingPermission();
774         synchronized (mStats) {
775             mStats.noteWifiSupplicantStateChangedLocked(supplState, failedAuth);
776         }
777     }
778 
noteWifiRssiChanged(int newRssi)779     public void noteWifiRssiChanged(int newRssi) {
780         enforceCallingPermission();
781         synchronized (mStats) {
782             mStats.noteWifiRssiChangedLocked(newRssi);
783         }
784     }
785 
noteFullWifiLockAcquired(int uid)786     public void noteFullWifiLockAcquired(int uid) {
787         enforceCallingPermission();
788         synchronized (mStats) {
789             mStats.noteFullWifiLockAcquiredLocked(uid);
790         }
791     }
792 
noteFullWifiLockReleased(int uid)793     public void noteFullWifiLockReleased(int uid) {
794         enforceCallingPermission();
795         synchronized (mStats) {
796             mStats.noteFullWifiLockReleasedLocked(uid);
797         }
798     }
799 
noteWifiScanStarted(int uid)800     public void noteWifiScanStarted(int uid) {
801         enforceCallingPermission();
802         synchronized (mStats) {
803             mStats.noteWifiScanStartedLocked(uid);
804         }
805     }
806 
noteWifiScanStopped(int uid)807     public void noteWifiScanStopped(int uid) {
808         enforceCallingPermission();
809         synchronized (mStats) {
810             mStats.noteWifiScanStoppedLocked(uid);
811         }
812     }
813 
noteWifiMulticastEnabled(int uid)814     public void noteWifiMulticastEnabled(int uid) {
815         enforceCallingPermission();
816         synchronized (mStats) {
817             mStats.noteWifiMulticastEnabledLocked(uid);
818         }
819     }
820 
noteWifiMulticastDisabled(int uid)821     public void noteWifiMulticastDisabled(int uid) {
822         enforceCallingPermission();
823         synchronized (mStats) {
824             mStats.noteWifiMulticastDisabledLocked(uid);
825         }
826     }
827 
noteFullWifiLockAcquiredFromSource(WorkSource ws)828     public void noteFullWifiLockAcquiredFromSource(WorkSource ws) {
829         enforceCallingPermission();
830         synchronized (mStats) {
831             mStats.noteFullWifiLockAcquiredFromSourceLocked(ws);
832         }
833     }
834 
noteFullWifiLockReleasedFromSource(WorkSource ws)835     public void noteFullWifiLockReleasedFromSource(WorkSource ws) {
836         enforceCallingPermission();
837         synchronized (mStats) {
838             mStats.noteFullWifiLockReleasedFromSourceLocked(ws);
839         }
840     }
841 
noteWifiScanStartedFromSource(WorkSource ws)842     public void noteWifiScanStartedFromSource(WorkSource ws) {
843         enforceCallingPermission();
844         synchronized (mStats) {
845             mStats.noteWifiScanStartedFromSourceLocked(ws);
846         }
847     }
848 
noteWifiScanStoppedFromSource(WorkSource ws)849     public void noteWifiScanStoppedFromSource(WorkSource ws) {
850         enforceCallingPermission();
851         synchronized (mStats) {
852             mStats.noteWifiScanStoppedFromSourceLocked(ws);
853         }
854     }
855 
noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph)856     public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) {
857         enforceCallingPermission();
858         synchronized (mStats) {
859             mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph);
860         }
861     }
862 
noteWifiBatchedScanStoppedFromSource(WorkSource ws)863     public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) {
864         enforceCallingPermission();
865         synchronized (mStats) {
866             mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws);
867         }
868     }
869 
noteWifiMulticastEnabledFromSource(WorkSource ws)870     public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
871         enforceCallingPermission();
872         synchronized (mStats) {
873             mStats.noteWifiMulticastEnabledFromSourceLocked(ws);
874         }
875     }
876 
877     @Override
noteWifiMulticastDisabledFromSource(WorkSource ws)878     public void noteWifiMulticastDisabledFromSource(WorkSource ws) {
879         enforceCallingPermission();
880         synchronized (mStats) {
881             mStats.noteWifiMulticastDisabledFromSourceLocked(ws);
882         }
883     }
884 
885     @Override
noteNetworkInterfaceType(String iface, int networkType)886     public void noteNetworkInterfaceType(String iface, int networkType) {
887         enforceCallingPermission();
888         synchronized (mStats) {
889             mStats.noteNetworkInterfaceTypeLocked(iface, networkType);
890         }
891     }
892 
893     @Override
noteNetworkStatsEnabled()894     public void noteNetworkStatsEnabled() {
895         enforceCallingPermission();
896         synchronized (mStats) {
897             mStats.noteNetworkStatsEnabledLocked();
898         }
899     }
900 
901     @Override
noteDeviceIdleMode(int mode, String activeReason, int activeUid)902     public void noteDeviceIdleMode(int mode, String activeReason, int activeUid) {
903         enforceCallingPermission();
904         synchronized (mStats) {
905             mStats.noteDeviceIdleModeLocked(mode, activeReason, activeUid);
906         }
907     }
908 
notePackageInstalled(String pkgName, int versionCode)909     public void notePackageInstalled(String pkgName, int versionCode) {
910         enforceCallingPermission();
911         synchronized (mStats) {
912             mStats.notePackageInstalledLocked(pkgName, versionCode);
913         }
914     }
915 
notePackageUninstalled(String pkgName)916     public void notePackageUninstalled(String pkgName) {
917         enforceCallingPermission();
918         synchronized (mStats) {
919             mStats.notePackageUninstalledLocked(pkgName);
920         }
921     }
922 
923     @Override
noteBleScanStarted(WorkSource ws)924     public void noteBleScanStarted(WorkSource ws) {
925         enforceCallingPermission();
926         synchronized (mStats) {
927             mStats.noteBluetoothScanStartedFromSourceLocked(ws);
928         }
929     }
930 
931     @Override
noteBleScanStopped(WorkSource ws)932     public void noteBleScanStopped(WorkSource ws) {
933         enforceCallingPermission();
934         synchronized (mStats) {
935             mStats.noteBluetoothScanStoppedFromSourceLocked(ws);
936         }
937     }
938 
939     @Override
noteResetBleScan()940     public void noteResetBleScan() {
941         enforceCallingPermission();
942         synchronized (mStats) {
943             mStats.noteResetBluetoothScanLocked();
944         }
945     }
946 
947     @Override
noteWifiControllerActivity(WifiActivityEnergyInfo info)948     public void noteWifiControllerActivity(WifiActivityEnergyInfo info) {
949         enforceCallingPermission();
950 
951         if (info == null || !info.isValid()) {
952             Slog.e(TAG, "invalid wifi data given: " + info);
953             return;
954         }
955 
956         synchronized (mStats) {
957             mStats.updateWifiStateLocked(info);
958         }
959     }
960 
961     @Override
noteBluetoothControllerActivity(BluetoothActivityEnergyInfo info)962     public void noteBluetoothControllerActivity(BluetoothActivityEnergyInfo info) {
963         enforceCallingPermission();
964         if (info == null || !info.isValid()) {
965             Slog.e(TAG, "invalid bluetooth data given: " + info);
966             return;
967         }
968 
969         synchronized (mStats) {
970             mStats.updateBluetoothStateLocked(info);
971         }
972     }
973 
974     @Override
noteModemControllerActivity(ModemActivityInfo info)975     public void noteModemControllerActivity(ModemActivityInfo info) {
976         enforceCallingPermission();
977 
978         if (info == null || !info.isValid()) {
979             Slog.e(TAG, "invalid modem data given: " + info);
980             return;
981         }
982 
983         synchronized (mStats) {
984             mStats.updateMobileRadioStateLocked(SystemClock.elapsedRealtime(), info);
985         }
986     }
987 
isOnBattery()988     public boolean isOnBattery() {
989         return mStats.isOnBattery();
990     }
991 
992     @Override
setBatteryState(final int status, final int health, final int plugType, final int level, final int temp, final int volt, final int chargeUAh)993     public void setBatteryState(final int status, final int health, final int plugType,
994             final int level, final int temp, final int volt, final int chargeUAh) {
995         enforceCallingPermission();
996 
997         // BatteryService calls us here and we may update external state. It would be wrong
998         // to block such a low level service like BatteryService on external stats like WiFi.
999         mHandler.post(new Runnable() {
1000             @Override
1001             public void run() {
1002                 synchronized (mStats) {
1003                     final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
1004                     if (mStats.isOnBattery() == onBattery) {
1005                         // The battery state has not changed, so we don't need to sync external
1006                         // stats immediately.
1007                         mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
1008                                 chargeUAh);
1009                         return;
1010                     }
1011                 }
1012 
1013                 // Sync external stats first as the battery has changed states. If we don't sync
1014                 // immediately here, we may not collect the relevant data later.
1015                 updateExternalStatsSync("battery-state", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
1016                 synchronized (mStats) {
1017                     mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
1018                             chargeUAh);
1019                 }
1020             }
1021         });
1022     }
1023 
getAwakeTimeBattery()1024     public long getAwakeTimeBattery() {
1025         mContext.enforceCallingOrSelfPermission(
1026                 android.Manifest.permission.BATTERY_STATS, null);
1027         return mStats.getAwakeTimeBattery();
1028     }
1029 
getAwakeTimePlugged()1030     public long getAwakeTimePlugged() {
1031         mContext.enforceCallingOrSelfPermission(
1032                 android.Manifest.permission.BATTERY_STATS, null);
1033         return mStats.getAwakeTimePlugged();
1034     }
1035 
enforceCallingPermission()1036     public void enforceCallingPermission() {
1037         if (Binder.getCallingPid() == Process.myPid()) {
1038             return;
1039         }
1040         mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
1041                 Binder.getCallingPid(), Binder.getCallingUid(), null);
1042     }
1043 
1044     final class WakeupReasonThread extends Thread {
1045         private static final int MAX_REASON_SIZE = 512;
1046         private CharsetDecoder mDecoder;
1047         private ByteBuffer mUtf8Buffer;
1048         private CharBuffer mUtf16Buffer;
1049 
WakeupReasonThread()1050         WakeupReasonThread() {
1051             super("BatteryStats_wakeupReason");
1052         }
1053 
run()1054         public void run() {
1055             Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
1056 
1057             mDecoder = StandardCharsets.UTF_8
1058                     .newDecoder()
1059                     .onMalformedInput(CodingErrorAction.REPLACE)
1060                     .onUnmappableCharacter(CodingErrorAction.REPLACE)
1061                     .replaceWith("?");
1062 
1063             mUtf8Buffer = ByteBuffer.allocateDirect(MAX_REASON_SIZE);
1064             mUtf16Buffer = CharBuffer.allocate(MAX_REASON_SIZE);
1065 
1066             try {
1067                 String reason;
1068                 while ((reason = waitWakeup()) != null) {
1069                     synchronized (mStats) {
1070                         mStats.noteWakeupReasonLocked(reason);
1071                     }
1072                 }
1073             } catch (RuntimeException e) {
1074                 Slog.e(TAG, "Failure reading wakeup reasons", e);
1075             }
1076         }
1077 
waitWakeup()1078         private String waitWakeup() {
1079             mUtf8Buffer.clear();
1080             mUtf16Buffer.clear();
1081             mDecoder.reset();
1082 
1083             int bytesWritten = nativeWaitWakeup(mUtf8Buffer);
1084             if (bytesWritten < 0) {
1085                 return null;
1086             } else if (bytesWritten == 0) {
1087                 return "unknown";
1088             }
1089 
1090             // Set the buffer's limit to the number of bytes written.
1091             mUtf8Buffer.limit(bytesWritten);
1092 
1093             // Decode the buffer from UTF-8 to UTF-16.
1094             // Unmappable characters will be replaced.
1095             mDecoder.decode(mUtf8Buffer, mUtf16Buffer, true);
1096             mUtf16Buffer.flip();
1097 
1098             // Create a String from the UTF-16 buffer.
1099             return mUtf16Buffer.toString();
1100         }
1101     }
1102 
nativeWaitWakeup(ByteBuffer outBuffer)1103     private static native int nativeWaitWakeup(ByteBuffer outBuffer);
1104 
dumpHelp(PrintWriter pw)1105     private void dumpHelp(PrintWriter pw) {
1106         pw.println("Battery stats (batterystats) dump options:");
1107         pw.println("  [--checkin] [--history] [--history-start] [--charged] [-c]");
1108         pw.println("  [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]");
1109         pw.println("  --checkin: generate output for a checkin report; will write (and clear) the");
1110         pw.println("             last old completed stats when they had been reset.");
1111         pw.println("  -c: write the current stats in checkin format.");
1112         pw.println("  --history: show only history data.");
1113         pw.println("  --history-start <num>: show only history data starting at given time offset.");
1114         pw.println("  --charged: only output data since last charged.");
1115         pw.println("  --daily: only output full daily data.");
1116         pw.println("  --reset: reset the stats, clearing all current data.");
1117         pw.println("  --write: force write current collected stats to disk.");
1118         pw.println("  --new-daily: immediately create and write new daily stats record.");
1119         pw.println("  --read-daily: read-load last written daily stats.");
1120         pw.println("  <package.name>: optional name of package to filter output by.");
1121         pw.println("  -h: print this help text.");
1122         pw.println("Battery stats (batterystats) commands:");
1123         pw.println("  enable|disable <option>");
1124         pw.println("    Enable or disable a running option.  Option state is not saved across boots.");
1125         pw.println("    Options are:");
1126         pw.println("      full-history: include additional detailed events in battery history:");
1127         pw.println("          wake_lock_in, alarms and proc events");
1128         pw.println("      no-auto-reset: don't automatically reset stats when unplugged");
1129     }
1130 
doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable)1131     private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
1132         i++;
1133         if (i >= args.length) {
1134             pw.println("Missing option argument for " + (enable ? "--enable" : "--disable"));
1135             dumpHelp(pw);
1136             return -1;
1137         }
1138         if ("full-wake-history".equals(args[i]) || "full-history".equals(args[i])) {
1139             synchronized (mStats) {
1140                 mStats.setRecordAllHistoryLocked(enable);
1141             }
1142         } else if ("no-auto-reset".equals(args[i])) {
1143             synchronized (mStats) {
1144                 mStats.setNoAutoReset(enable);
1145             }
1146         } else {
1147             pw.println("Unknown enable/disable option: " + args[i]);
1148             dumpHelp(pw);
1149             return -1;
1150         }
1151         return i;
1152     }
1153 
1154 
1155     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1156     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1157         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1158                 != PackageManager.PERMISSION_GRANTED) {
1159             pw.println("Permission Denial: can't dump BatteryStats from from pid="
1160                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
1161                     + " without permission " + android.Manifest.permission.DUMP);
1162             return;
1163         }
1164 
1165         int flags = 0;
1166         boolean useCheckinFormat = false;
1167         boolean isRealCheckin = false;
1168         boolean noOutput = false;
1169         boolean writeData = false;
1170         long historyStart = -1;
1171         int reqUid = -1;
1172         if (args != null) {
1173             for (int i=0; i<args.length; i++) {
1174                 String arg = args[i];
1175                 if ("--checkin".equals(arg)) {
1176                     useCheckinFormat = true;
1177                     isRealCheckin = true;
1178                 } else if ("--history".equals(arg)) {
1179                     flags |= BatteryStats.DUMP_HISTORY_ONLY;
1180                 } else if ("--history-start".equals(arg)) {
1181                     flags |= BatteryStats.DUMP_HISTORY_ONLY;
1182                     i++;
1183                     if (i >= args.length) {
1184                         pw.println("Missing time argument for --history-since");
1185                         dumpHelp(pw);
1186                         return;
1187                     }
1188                     historyStart = Long.parseLong(args[i]);
1189                     writeData = true;
1190                 } else if ("-c".equals(arg)) {
1191                     useCheckinFormat = true;
1192                     flags |= BatteryStats.DUMP_INCLUDE_HISTORY;
1193                 } else if ("--charged".equals(arg)) {
1194                     flags |= BatteryStats.DUMP_CHARGED_ONLY;
1195                 } else if ("--daily".equals(arg)) {
1196                     flags |= BatteryStats.DUMP_DAILY_ONLY;
1197                 } else if ("--reset".equals(arg)) {
1198                     synchronized (mStats) {
1199                         mStats.resetAllStatsCmdLocked();
1200                         pw.println("Battery stats reset.");
1201                         noOutput = true;
1202                     }
1203                     updateExternalStatsSync("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
1204                 } else if ("--write".equals(arg)) {
1205                     updateExternalStatsSync("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
1206                     synchronized (mStats) {
1207                         mStats.writeSyncLocked();
1208                         pw.println("Battery stats written.");
1209                         noOutput = true;
1210                     }
1211                 } else if ("--new-daily".equals(arg)) {
1212                     synchronized (mStats) {
1213                         mStats.recordDailyStatsLocked();
1214                         pw.println("New daily stats written.");
1215                         noOutput = true;
1216                     }
1217                 } else if ("--read-daily".equals(arg)) {
1218                     synchronized (mStats) {
1219                         mStats.readDailyStatsLocked();
1220                         pw.println("Last daily stats read.");
1221                         noOutput = true;
1222                     }
1223                 } else if ("--enable".equals(arg) || "enable".equals(arg)) {
1224                     i = doEnableOrDisable(pw, i, args, true);
1225                     if (i < 0) {
1226                         return;
1227                     }
1228                     pw.println("Enabled: " + args[i]);
1229                     return;
1230                 } else if ("--disable".equals(arg) || "disable".equals(arg)) {
1231                     i = doEnableOrDisable(pw, i, args, false);
1232                     if (i < 0) {
1233                         return;
1234                     }
1235                     pw.println("Disabled: " + args[i]);
1236                     return;
1237                 } else if ("-h".equals(arg)) {
1238                     dumpHelp(pw);
1239                     return;
1240                 } else if ("-a".equals(arg)) {
1241                     flags |= BatteryStats.DUMP_VERBOSE;
1242                 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
1243                     pw.println("Unknown option: " + arg);
1244                     dumpHelp(pw);
1245                     return;
1246                 } else {
1247                     // Not an option, last argument must be a package name.
1248                     try {
1249                         reqUid = mContext.getPackageManager().getPackageUidAsUser(arg,
1250                                 UserHandle.getCallingUserId());
1251                     } catch (PackageManager.NameNotFoundException e) {
1252                         pw.println("Unknown package: " + arg);
1253                         dumpHelp(pw);
1254                         return;
1255                     }
1256                 }
1257             }
1258         }
1259         if (noOutput) {
1260             return;
1261         }
1262 
1263         long ident = Binder.clearCallingIdentity();
1264         try {
1265             if (BatteryStatsHelper.checkWifiOnly(mContext)) {
1266                 flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY;
1267             }
1268             // Fetch data from external sources and update the BatteryStatsImpl object with them.
1269             updateExternalStatsSync("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
1270         } finally {
1271             Binder.restoreCallingIdentity(ident);
1272         }
1273 
1274         if (reqUid >= 0) {
1275             // By default, if the caller is only interested in a specific package, then
1276             // we only dump the aggregated data since charged.
1277             if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_CHARGED_ONLY)) == 0) {
1278                 flags |= BatteryStats.DUMP_CHARGED_ONLY;
1279                 // Also if they are doing -c, we don't want history.
1280                 flags &= ~BatteryStats.DUMP_INCLUDE_HISTORY;
1281             }
1282         }
1283 
1284         if (useCheckinFormat) {
1285             List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
1286                     PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_ALL);
1287             if (isRealCheckin) {
1288                 // For a real checkin, first we want to prefer to use the last complete checkin
1289                 // file if there is one.
1290                 synchronized (mStats.mCheckinFile) {
1291                     if (mStats.mCheckinFile.exists()) {
1292                         try {
1293                             byte[] raw = mStats.mCheckinFile.readFully();
1294                             if (raw != null) {
1295                                 Parcel in = Parcel.obtain();
1296                                 in.unmarshall(raw, 0, raw.length);
1297                                 in.setDataPosition(0);
1298                                 BatteryStatsImpl checkinStats = new BatteryStatsImpl(
1299                                         null, mStats.mHandler, null);
1300                                 checkinStats.readSummaryFromParcel(in);
1301                                 in.recycle();
1302                                 checkinStats.dumpCheckinLocked(mContext, pw, apps, flags,
1303                                         historyStart);
1304                                 mStats.mCheckinFile.delete();
1305                                 return;
1306                             }
1307                         } catch (IOException | ParcelFormatException e) {
1308                             Slog.w(TAG, "Failure reading checkin file "
1309                                     + mStats.mCheckinFile.getBaseFile(), e);
1310                         }
1311                     }
1312                 }
1313             }
1314             synchronized (mStats) {
1315                 mStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart);
1316                 if (writeData) {
1317                     mStats.writeAsyncLocked();
1318                 }
1319             }
1320         } else {
1321             synchronized (mStats) {
1322                 mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart);
1323                 if (writeData) {
1324                     mStats.writeAsyncLocked();
1325                 }
1326             }
1327         }
1328     }
1329 
extractDelta(WifiActivityEnergyInfo latest)1330     private WifiActivityEnergyInfo extractDelta(WifiActivityEnergyInfo latest) {
1331         final long timePeriodMs = latest.mTimestamp - mLastInfo.mTimestamp;
1332         final long lastIdleMs = mLastInfo.mControllerIdleTimeMs;
1333         final long lastTxMs = mLastInfo.mControllerTxTimeMs;
1334         final long lastRxMs = mLastInfo.mControllerRxTimeMs;
1335         final long lastEnergy = mLastInfo.mControllerEnergyUsed;
1336 
1337         // We will modify the last info object to be the delta, and store the new
1338         // WifiActivityEnergyInfo object as our last one.
1339         final WifiActivityEnergyInfo delta = mLastInfo;
1340         delta.mTimestamp = latest.getTimeStamp();
1341         delta.mStackState = latest.getStackState();
1342 
1343         final long txTimeMs = latest.mControllerTxTimeMs - lastTxMs;
1344         final long rxTimeMs = latest.mControllerRxTimeMs - lastRxMs;
1345         final long idleTimeMs = latest.mControllerIdleTimeMs - lastIdleMs;
1346 
1347         if (txTimeMs < 0 || rxTimeMs < 0) {
1348             // The stats were reset by the WiFi system (which is why our delta is negative).
1349             // Returns the unaltered stats.
1350             delta.mControllerEnergyUsed = latest.mControllerEnergyUsed;
1351             delta.mControllerRxTimeMs = latest.mControllerRxTimeMs;
1352             delta.mControllerTxTimeMs = latest.mControllerTxTimeMs;
1353             delta.mControllerIdleTimeMs = latest.mControllerIdleTimeMs;
1354             Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + delta);
1355         } else {
1356             final long totalActiveTimeMs = txTimeMs + rxTimeMs;
1357             long maxExpectedIdleTimeMs;
1358             if (totalActiveTimeMs > timePeriodMs) {
1359                 // Cap the max idle time at zero since the active time consumed the whole time
1360                 maxExpectedIdleTimeMs = 0;
1361                 if (totalActiveTimeMs > timePeriodMs + MAX_WIFI_STATS_SAMPLE_ERROR_MILLIS) {
1362                     StringBuilder sb = new StringBuilder();
1363                     sb.append("Total Active time ");
1364                     TimeUtils.formatDuration(totalActiveTimeMs, sb);
1365                     sb.append(" is longer than sample period ");
1366                     TimeUtils.formatDuration(timePeriodMs, sb);
1367                     sb.append(".\n");
1368                     sb.append("Previous WiFi snapshot: ").append("idle=");
1369                     TimeUtils.formatDuration(lastIdleMs, sb);
1370                     sb.append(" rx=");
1371                     TimeUtils.formatDuration(lastRxMs, sb);
1372                     sb.append(" tx=");
1373                     TimeUtils.formatDuration(lastTxMs, sb);
1374                     sb.append(" e=").append(lastEnergy);
1375                     sb.append("\n");
1376                     sb.append("Current WiFi snapshot: ").append("idle=");
1377                     TimeUtils.formatDuration(latest.mControllerIdleTimeMs, sb);
1378                     sb.append(" rx=");
1379                     TimeUtils.formatDuration(latest.mControllerRxTimeMs, sb);
1380                     sb.append(" tx=");
1381                     TimeUtils.formatDuration(latest.mControllerTxTimeMs, sb);
1382                     sb.append(" e=").append(latest.mControllerEnergyUsed);
1383                     Slog.wtf(TAG, sb.toString());
1384                 }
1385             } else {
1386                 maxExpectedIdleTimeMs = timePeriodMs - totalActiveTimeMs;
1387             }
1388             // These times seem to be the most reliable.
1389             delta.mControllerTxTimeMs = txTimeMs;
1390             delta.mControllerRxTimeMs = rxTimeMs;
1391             // WiFi calculates the idle time as a difference from the on time and the various
1392             // Rx + Tx times. There seems to be some missing time there because this sometimes
1393             // becomes negative. Just cap it at 0 and ensure that it is less than the expected idle
1394             // time from the difference in timestamps.
1395             // b/21613534
1396             delta.mControllerIdleTimeMs = Math.min(maxExpectedIdleTimeMs, Math.max(0, idleTimeMs));
1397             delta.mControllerEnergyUsed = Math.max(0, latest.mControllerEnergyUsed - lastEnergy);
1398         }
1399 
1400         mLastInfo = latest;
1401         return delta;
1402     }
1403 
1404     /**
1405      * Helper method to extract the Parcelable controller info from a
1406      * SynchronousResultReceiver.
1407      */
awaitControllerInfo( @ullable SynchronousResultReceiver receiver)1408     private static <T extends Parcelable> T awaitControllerInfo(
1409             @Nullable SynchronousResultReceiver receiver) throws TimeoutException {
1410         if (receiver == null) {
1411             return null;
1412         }
1413 
1414         final SynchronousResultReceiver.Result result =
1415                 receiver.awaitResult(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS);
1416         if (result.bundle != null) {
1417             // This is the final destination for the Bundle.
1418             result.bundle.setDefusable(true);
1419 
1420             final T data = result.bundle.getParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY);
1421             if (data != null) {
1422                 return data;
1423             }
1424         }
1425         Slog.e(TAG, "no controller energy info supplied");
1426         return null;
1427     }
1428 
1429     /**
1430      * Fetches data from external sources (WiFi controller, bluetooth chipset) and updates
1431      * batterystats with that information.
1432      *
1433      * We first grab a lock specific to this method, then once all the data has been collected,
1434      * we grab the mStats lock and update the data.
1435      *
1436      * @param reason The reason why this collection was requested. Useful for debugging.
1437      * @param updateFlags Which external stats to update. Can be a combination of
1438      *                    {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_CPU},
1439      *                    {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_RADIO},
1440      *                    {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_WIFI},
1441      *                    and {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_BT}.
1442      */
updateExternalStatsSync(final String reason, int updateFlags)1443     void updateExternalStatsSync(final String reason, int updateFlags) {
1444         SynchronousResultReceiver wifiReceiver = null;
1445         SynchronousResultReceiver bluetoothReceiver = null;
1446         SynchronousResultReceiver modemReceiver = null;
1447 
1448         synchronized (mExternalStatsLock) {
1449             if (mContext == null) {
1450                 // Don't do any work yet.
1451                 return;
1452             }
1453 
1454             if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
1455                 if (mWifiManager == null) {
1456                     mWifiManager = IWifiManager.Stub.asInterface(
1457                             ServiceManager.getService(Context.WIFI_SERVICE));
1458                 }
1459 
1460                 if (mWifiManager != null) {
1461                     try {
1462                         wifiReceiver = new SynchronousResultReceiver();
1463                         mWifiManager.requestActivityInfo(wifiReceiver);
1464                     } catch (RemoteException e) {
1465                         // Oh well.
1466                     }
1467                 }
1468             }
1469 
1470             if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_BT) != 0) {
1471                 final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1472                 if (adapter != null) {
1473                     bluetoothReceiver = new SynchronousResultReceiver();
1474                     adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
1475                 }
1476             }
1477 
1478             if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) {
1479                 if (mTelephony == null) {
1480                     mTelephony = TelephonyManager.from(mContext);
1481                 }
1482 
1483                 if (mTelephony != null) {
1484                     modemReceiver = new SynchronousResultReceiver();
1485                     mTelephony.requestModemActivityInfo(modemReceiver);
1486                 }
1487             }
1488 
1489             WifiActivityEnergyInfo wifiInfo = null;
1490             BluetoothActivityEnergyInfo bluetoothInfo = null;
1491             ModemActivityInfo modemInfo = null;
1492             try {
1493                 wifiInfo = awaitControllerInfo(wifiReceiver);
1494             } catch (TimeoutException e) {
1495                 Slog.w(TAG, "Timeout reading wifi stats");
1496             }
1497 
1498             try {
1499                 bluetoothInfo = awaitControllerInfo(bluetoothReceiver);
1500             } catch (TimeoutException e) {
1501                 Slog.w(TAG, "Timeout reading bt stats");
1502             }
1503 
1504             try {
1505                 modemInfo = awaitControllerInfo(modemReceiver);
1506             } catch (TimeoutException e) {
1507                 Slog.w(TAG, "Timeout reading modem stats");
1508             }
1509 
1510             synchronized (mStats) {
1511                 mStats.addHistoryEventLocked(
1512                         SystemClock.elapsedRealtime(),
1513                         SystemClock.uptimeMillis(),
1514                         BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS,
1515                         reason, 0);
1516 
1517                 mStats.updateCpuTimeLocked();
1518                 mStats.updateKernelWakelocksLocked();
1519 
1520                 if (wifiInfo != null) {
1521                     if (wifiInfo.isValid()) {
1522                         mStats.updateWifiStateLocked(extractDelta(wifiInfo));
1523                     } else {
1524                         Slog.e(TAG, "wifi info is invalid: " + wifiInfo);
1525                     }
1526                 }
1527 
1528                 if (bluetoothInfo != null) {
1529                     if (bluetoothInfo.isValid()) {
1530                         mStats.updateBluetoothStateLocked(bluetoothInfo);
1531                     } else {
1532                         Slog.e(TAG, "bluetooth info is invalid: " + bluetoothInfo);
1533                     }
1534                 }
1535 
1536                 if (modemInfo != null) {
1537                     if (modemInfo.isValid()) {
1538                         mStats.updateMobileRadioStateLocked(SystemClock.elapsedRealtime(),
1539                                 modemInfo);
1540                     } else {
1541                         Slog.e(TAG, "modem info is invalid: " + modemInfo);
1542                     }
1543                 }
1544             }
1545         }
1546     }
1547 
1548     /**
1549      * Gets a snapshot of the system health for a particular uid.
1550      */
1551     @Override
takeUidSnapshot(int requestUid)1552     public HealthStatsParceler takeUidSnapshot(int requestUid) {
1553         if (requestUid != Binder.getCallingUid()) {
1554             mContext.enforceCallingOrSelfPermission(
1555                     android.Manifest.permission.BATTERY_STATS, null);
1556         }
1557         long ident = Binder.clearCallingIdentity();
1558         try {
1559             updateExternalStatsSync("get-health-stats-for-uid",
1560                     BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
1561             synchronized (mStats) {
1562                 return getHealthStatsForUidLocked(requestUid);
1563             }
1564         } catch (Exception ex) {
1565             Slog.d(TAG, "Crashed while writing for takeUidSnapshot(" + requestUid + ")", ex);
1566             throw ex;
1567         } finally {
1568             Binder.restoreCallingIdentity(ident);
1569         }
1570     }
1571 
1572     /**
1573      * Gets a snapshot of the system health for a number of uids.
1574      */
1575     @Override
takeUidSnapshots(int[] requestUids)1576     public HealthStatsParceler[] takeUidSnapshots(int[] requestUids) {
1577         if (!onlyCaller(requestUids)) {
1578             mContext.enforceCallingOrSelfPermission(
1579                     android.Manifest.permission.BATTERY_STATS, null);
1580         }
1581         long ident = Binder.clearCallingIdentity();
1582         int i=-1;
1583         try {
1584             updateExternalStatsSync("get-health-stats-for-uids",
1585                     BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
1586             synchronized (mStats) {
1587                 final int N = requestUids.length;
1588                 final HealthStatsParceler[] results = new HealthStatsParceler[N];
1589                 for (i=0; i<N; i++) {
1590                     results[i] = getHealthStatsForUidLocked(requestUids[i]);
1591                 }
1592                 return results;
1593             }
1594         } catch (Exception ex) {
1595             Slog.d(TAG, "Crashed while writing for takeUidSnapshots("
1596                     + Arrays.toString(requestUids) + ") i=" + i, ex);
1597             throw ex;
1598         } finally {
1599             Binder.restoreCallingIdentity(ident);
1600         }
1601     }
1602 
1603     /**
1604      * Returns whether the Binder.getCallingUid is the only thing in requestUids.
1605      */
onlyCaller(int[] requestUids)1606     private static boolean onlyCaller(int[] requestUids) {
1607         final int caller = Binder.getCallingUid();
1608         final int N = requestUids.length;
1609         for (int i=0; i<N; i++) {
1610             if (requestUids[i] != caller) {
1611                 return false;
1612             }
1613         }
1614         return true;
1615     }
1616 
1617     /**
1618      * Gets a HealthStatsParceler for the given uid. You should probably call
1619      * updateExternalStatsSync first.
1620      */
getHealthStatsForUidLocked(int requestUid)1621     HealthStatsParceler getHealthStatsForUidLocked(int requestUid) {
1622         final HealthStatsBatteryStatsWriter writer = new HealthStatsBatteryStatsWriter();
1623         final HealthStatsWriter uidWriter = new HealthStatsWriter(UidHealthStats.CONSTANTS);
1624         final BatteryStats.Uid uid = mStats.getUidStats().get(requestUid);
1625         if (uid != null) {
1626             writer.writeUid(uidWriter, mStats, uid);
1627         }
1628         return new HealthStatsParceler(uidWriter);
1629     }
1630 
1631 }
1632