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