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