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 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 
    126         public BatteryStatsHandler(Looper looper) {
    127             super(looper);
    128         }
    129 
    130         @Override
    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
    168         public void scheduleSync(String reason, int updateFlags) {
    169             synchronized (this) {
    170                 scheduleSyncLocked(reason, updateFlags);
    171             }
    172         }
    173 
    174         @Override
    175         public void scheduleCpuSyncDueToRemovedUid(int uid) {
    176             synchronized (this) {
    177                 scheduleSyncLocked("remove-uid", UPDATE_CPU);
    178                 mUidsToRemove.add(uid);
    179             }
    180         }
    181 
    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 
    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
    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 
    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 
    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      */
    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 
    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 
    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
    282     public int getServiceType() {
    283         return ServiceType.BATTERY_STATS;
    284     }
    285 
    286     @Override
    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      */
    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      */
    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      */
    315     void removeUid(int uid) {
    316         synchronized (mStats) {
    317             mStats.removeUidStatsLocked(uid);
    318         }
    319     }
    320 
    321     void addIsolatedUid(int isolatedUid, int appUid) {
    322         synchronized (mStats) {
    323             mStats.addIsolatedUidLocked(isolatedUid, appUid);
    324         }
    325     }
    326 
    327     void removeIsolatedUid(int isolatedUid, int appUid) {
    328         synchronized (mStats) {
    329             mStats.scheduleRemoveIsolatedUidLocked(isolatedUid, appUid);
    330         }
    331     }
    332 
    333     void noteProcessStart(String name, int uid) {
    334         synchronized (mStats) {
    335             mStats.noteProcessStartLocked(name, uid);
    336         }
    337     }
    338 
    339     void noteProcessCrash(String name, int uid) {
    340         synchronized (mStats) {
    341             mStats.noteProcessCrashLocked(name, uid);
    342         }
    343     }
    344 
    345     void noteProcessAnr(String name, int uid) {
    346         synchronized (mStats) {
    347             mStats.noteProcessAnrLocked(name, uid);
    348         }
    349     }
    350 
    351     void noteProcessFinish(String name, int uid) {
    352         synchronized (mStats) {
    353             mStats.noteProcessFinishLocked(name, uid);
    354         }
    355     }
    356 
    357     void noteUidProcessState(int uid, int state) {
    358         synchronized (mStats) {
    359             mStats.noteUidProcessStateLocked(uid, state);
    360         }
    361     }
    362 
    363     // Public interface...
    364 
    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 
    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 
    400     public boolean isCharging() {
    401         synchronized (mStats) {
    402             return mStats.isCharging();
    403         }
    404     }
    405 
    406     public long computeBatteryTimeRemaining() {
    407         synchronized (mStats) {
    408             long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
    409             return time >= 0 ? (time/1000) : time;
    410         }
    411     }
    412 
    413     public long computeChargeTimeRemaining() {
    414         synchronized (mStats) {
    415             long time = mStats.computeChargeTimeRemaining(SystemClock.elapsedRealtime());
    416             return time >= 0 ? (time/1000) : time;
    417         }
    418     }
    419 
    420     public void noteEvent(int code, String name, int uid) {
    421         enforceCallingPermission();
    422         synchronized (mStats) {
    423             mStats.noteEventLocked(code, name, uid);
    424         }
    425     }
    426 
    427     public void noteSyncStart(String name, int uid) {
    428         enforceCallingPermission();
    429         synchronized (mStats) {
    430             mStats.noteSyncStartLocked(name, uid);
    431         }
    432     }
    433 
    434     public void noteSyncFinish(String name, int uid) {
    435         enforceCallingPermission();
    436         synchronized (mStats) {
    437             mStats.noteSyncFinishLocked(name, uid);
    438         }
    439     }
    440 
    441     public void noteJobStart(String name, int uid) {
    442         enforceCallingPermission();
    443         synchronized (mStats) {
    444             mStats.noteJobStartLocked(name, uid);
    445         }
    446     }
    447 
    448     public void noteJobFinish(String name, int uid) {
    449         enforceCallingPermission();
    450         synchronized (mStats) {
    451             mStats.noteJobFinishLocked(name, uid);
    452         }
    453     }
    454 
    455     public void noteAlarmStart(String name, int uid) {
    456         enforceCallingPermission();
    457         synchronized (mStats) {
    458             mStats.noteAlarmStartLocked(name, uid);
    459         }
    460     }
    461 
    462     public void noteAlarmFinish(String name, int uid) {
    463         enforceCallingPermission();
    464         synchronized (mStats) {
    465             mStats.noteAlarmFinishLocked(name, uid);
    466         }
    467     }
    468 
    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 
    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 
    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 
    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 
    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 
    513     public void noteLongPartialWakelockStart(String name, String historyName, int uid) {
    514         enforceCallingPermission();
    515         synchronized (mStats) {
    516             mStats.noteLongPartialWakelockStart(name, historyName, uid);
    517         }
    518     }
    519 
    520     public void noteLongPartialWakelockFinish(String name, String historyName, int uid) {
    521         enforceCallingPermission();
    522         synchronized (mStats) {
    523             mStats.noteLongPartialWakelockFinish(name, historyName, uid);
    524         }
    525     }
    526 
    527     public void noteStartSensor(int uid, int sensor) {
    528         enforceCallingPermission();
    529         synchronized (mStats) {
    530             mStats.noteStartSensorLocked(uid, sensor);
    531         }
    532     }
    533 
    534     public void noteStopSensor(int uid, int sensor) {
    535         enforceCallingPermission();
    536         synchronized (mStats) {
    537             mStats.noteStopSensorLocked(uid, sensor);
    538         }
    539     }
    540 
    541     public void noteVibratorOn(int uid, long durationMillis) {
    542         enforceCallingPermission();
    543         synchronized (mStats) {
    544             mStats.noteVibratorOnLocked(uid, durationMillis);
    545         }
    546     }
    547 
    548     public void noteVibratorOff(int uid) {
    549         enforceCallingPermission();
    550         synchronized (mStats) {
    551             mStats.noteVibratorOffLocked(uid);
    552         }
    553     }
    554 
    555     public void noteStartGps(int uid) {
    556         enforceCallingPermission();
    557         synchronized (mStats) {
    558             mStats.noteStartGpsLocked(uid);
    559         }
    560     }
    561 
    562     public void noteStopGps(int uid) {
    563         enforceCallingPermission();
    564         synchronized (mStats) {
    565             mStats.noteStopGpsLocked(uid);
    566         }
    567     }
    568 
    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 
    578     public void noteScreenBrightness(int brightness) {
    579         enforceCallingPermission();
    580         synchronized (mStats) {
    581             mStats.noteScreenBrightnessLocked(brightness);
    582         }
    583     }
    584 
    585     public void noteUserActivity(int uid, int event) {
    586         enforceCallingPermission();
    587         synchronized (mStats) {
    588             mStats.noteUserActivityLocked(uid, event);
    589         }
    590     }
    591 
    592     public void noteWakeUp(String reason, int reasonUid) {
    593         enforceCallingPermission();
    594         synchronized (mStats) {
    595             mStats.noteWakeUpLocked(reason, reasonUid);
    596         }
    597     }
    598 
    599     public void noteInteractive(boolean interactive) {
    600         enforceCallingPermission();
    601         synchronized (mStats) {
    602             mStats.noteInteractiveLocked(interactive);
    603         }
    604     }
    605 
    606     public void noteConnectivityChanged(int type, String extra) {
    607         enforceCallingPermission();
    608         synchronized (mStats) {
    609             mStats.noteConnectivityChangedLocked(type, extra);
    610         }
    611     }
    612 
    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 
    625     public void notePhoneOn() {
    626         enforceCallingPermission();
    627         synchronized (mStats) {
    628             mStats.notePhoneOnLocked();
    629         }
    630     }
    631 
    632     public void notePhoneOff() {
    633         enforceCallingPermission();
    634         synchronized (mStats) {
    635             mStats.notePhoneOffLocked();
    636         }
    637     }
    638 
    639     public void notePhoneSignalStrength(SignalStrength signalStrength) {
    640         enforceCallingPermission();
    641         synchronized (mStats) {
    642             mStats.notePhoneSignalStrengthLocked(signalStrength);
    643         }
    644     }
    645 
    646     public void notePhoneDataConnectionState(int dataType, boolean hasData) {
    647         enforceCallingPermission();
    648         synchronized (mStats) {
    649             mStats.notePhoneDataConnectionStateLocked(dataType, hasData);
    650         }
    651     }
    652 
    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 
    661     public void noteWifiOn() {
    662         enforceCallingPermission();
    663         synchronized (mStats) {
    664             mStats.noteWifiOnLocked();
    665         }
    666     }
    667 
    668     public void noteWifiOff() {
    669         enforceCallingPermission();
    670         synchronized (mStats) {
    671             mStats.noteWifiOffLocked();
    672         }
    673     }
    674 
    675     public void noteStartAudio(int uid) {
    676         enforceCallingPermission();
    677         synchronized (mStats) {
    678             mStats.noteAudioOnLocked(uid);
    679         }
    680     }
    681 
    682     public void noteStopAudio(int uid) {
    683         enforceCallingPermission();
    684         synchronized (mStats) {
    685             mStats.noteAudioOffLocked(uid);
    686         }
    687     }
    688 
    689     public void noteStartVideo(int uid) {
    690         enforceCallingPermission();
    691         synchronized (mStats) {
    692             mStats.noteVideoOnLocked(uid);
    693         }
    694     }
    695 
    696     public void noteStopVideo(int uid) {
    697         enforceCallingPermission();
    698         synchronized (mStats) {
    699             mStats.noteVideoOffLocked(uid);
    700         }
    701     }
    702 
    703     public void noteResetAudio() {
    704         enforceCallingPermission();
    705         synchronized (mStats) {
    706             mStats.noteResetAudioLocked();
    707         }
    708     }
    709 
    710     public void noteResetVideo() {
    711         enforceCallingPermission();
    712         synchronized (mStats) {
    713             mStats.noteResetVideoLocked();
    714         }
    715     }
    716 
    717     public void noteFlashlightOn(int uid) {
    718         enforceCallingPermission();
    719         synchronized (mStats) {
    720             mStats.noteFlashlightOnLocked(uid);
    721         }
    722     }
    723 
    724     public void noteFlashlightOff(int uid) {
    725         enforceCallingPermission();
    726         synchronized (mStats) {
    727             mStats.noteFlashlightOffLocked(uid);
    728         }
    729     }
    730 
    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 
    740     public void noteStopCamera(int uid) {
    741         enforceCallingPermission();
    742         synchronized (mStats) {
    743             mStats.noteCameraOffLocked(uid);
    744         }
    745     }
    746 
    747     public void noteResetCamera() {
    748         enforceCallingPermission();
    749         synchronized (mStats) {
    750             mStats.noteResetCameraLocked();
    751         }
    752     }
    753 
    754     public void noteResetFlashlight() {
    755         enforceCallingPermission();
    756         synchronized (mStats) {
    757             mStats.noteResetFlashlightLocked();
    758         }
    759     }
    760 
    761     @Override
    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 
    779     public void noteWifiRunning(WorkSource ws) {
    780         enforceCallingPermission();
    781         synchronized (mStats) {
    782             mStats.noteWifiRunningLocked(ws);
    783         }
    784     }
    785 
    786     public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) {
    787         enforceCallingPermission();
    788         synchronized (mStats) {
    789             mStats.noteWifiRunningChangedLocked(oldWs, newWs);
    790         }
    791     }
    792 
    793     public void noteWifiStopped(WorkSource ws) {
    794         enforceCallingPermission();
    795         synchronized (mStats) {
    796             mStats.noteWifiStoppedLocked(ws);
    797         }
    798     }
    799 
    800     public void noteWifiState(int wifiState, String accessPoint) {
    801         enforceCallingPermission();
    802         synchronized (mStats) {
    803             mStats.noteWifiStateLocked(wifiState, accessPoint);
    804         }
    805     }
    806 
    807     public void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth) {
    808         enforceCallingPermission();
    809         synchronized (mStats) {
    810             mStats.noteWifiSupplicantStateChangedLocked(supplState, failedAuth);
    811         }
    812     }
    813 
    814     public void noteWifiRssiChanged(int newRssi) {
    815         enforceCallingPermission();
    816         synchronized (mStats) {
    817             mStats.noteWifiRssiChangedLocked(newRssi);
    818         }
    819     }
    820 
    821     public void noteFullWifiLockAcquired(int uid) {
    822         enforceCallingPermission();
    823         synchronized (mStats) {
    824             mStats.noteFullWifiLockAcquiredLocked(uid);
    825         }
    826     }
    827 
    828     public void noteFullWifiLockReleased(int uid) {
    829         enforceCallingPermission();
    830         synchronized (mStats) {
    831             mStats.noteFullWifiLockReleasedLocked(uid);
    832         }
    833     }
    834 
    835     public void noteWifiScanStarted(int uid) {
    836         enforceCallingPermission();
    837         synchronized (mStats) {
    838             mStats.noteWifiScanStartedLocked(uid);
    839         }
    840     }
    841 
    842     public void noteWifiScanStopped(int uid) {
    843         enforceCallingPermission();
    844         synchronized (mStats) {
    845             mStats.noteWifiScanStoppedLocked(uid);
    846         }
    847     }
    848 
    849     public void noteWifiMulticastEnabled(int uid) {
    850         enforceCallingPermission();
    851         synchronized (mStats) {
    852             mStats.noteWifiMulticastEnabledLocked(uid);
    853         }
    854     }
    855 
    856     public void noteWifiMulticastDisabled(int uid) {
    857         enforceCallingPermission();
    858         synchronized (mStats) {
    859             mStats.noteWifiMulticastDisabledLocked(uid);
    860         }
    861     }
    862 
    863     public void noteFullWifiLockAcquiredFromSource(WorkSource ws) {
    864         enforceCallingPermission();
    865         synchronized (mStats) {
    866             mStats.noteFullWifiLockAcquiredFromSourceLocked(ws);
    867         }
    868     }
    869 
    870     public void noteFullWifiLockReleasedFromSource(WorkSource ws) {
    871         enforceCallingPermission();
    872         synchronized (mStats) {
    873             mStats.noteFullWifiLockReleasedFromSourceLocked(ws);
    874         }
    875     }
    876 
    877     public void noteWifiScanStartedFromSource(WorkSource ws) {
    878         enforceCallingPermission();
    879         synchronized (mStats) {
    880             mStats.noteWifiScanStartedFromSourceLocked(ws);
    881         }
    882     }
    883 
    884     public void noteWifiScanStoppedFromSource(WorkSource ws) {
    885         enforceCallingPermission();
    886         synchronized (mStats) {
    887             mStats.noteWifiScanStoppedFromSourceLocked(ws);
    888         }
    889     }
    890 
    891     public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) {
    892         enforceCallingPermission();
    893         synchronized (mStats) {
    894             mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph);
    895         }
    896     }
    897 
    898     public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) {
    899         enforceCallingPermission();
    900         synchronized (mStats) {
    901             mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws);
    902         }
    903     }
    904 
    905     public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
    906         enforceCallingPermission();
    907         synchronized (mStats) {
    908             mStats.noteWifiMulticastEnabledFromSourceLocked(ws);
    909         }
    910     }
    911 
    912     @Override
    913     public void noteWifiMulticastDisabledFromSource(WorkSource ws) {
    914         enforceCallingPermission();
    915         synchronized (mStats) {
    916             mStats.noteWifiMulticastDisabledFromSourceLocked(ws);
    917         }
    918     }
    919 
    920     @Override
    921     public void noteNetworkInterfaceType(String iface, int networkType) {
    922         enforceCallingPermission();
    923         synchronized (mStats) {
    924             mStats.noteNetworkInterfaceTypeLocked(iface, networkType);
    925         }
    926     }
    927 
    928     @Override
    929     public void noteNetworkStatsEnabled() {
    930         enforceCallingPermission();
    931         mHandler.scheduleSync("network-stats-enabled", UPDATE_RADIO | UPDATE_WIFI);
    932     }
    933 
    934     @Override
    935     public void noteDeviceIdleMode(int mode, String activeReason, int activeUid) {
    936         enforceCallingPermission();
    937         synchronized (mStats) {
    938             mStats.noteDeviceIdleModeLocked(mode, activeReason, activeUid);
    939         }
    940     }
    941 
    942     public void notePackageInstalled(String pkgName, int versionCode) {
    943         enforceCallingPermission();
    944         synchronized (mStats) {
    945             mStats.notePackageInstalledLocked(pkgName, versionCode);
    946         }
    947     }
    948 
    949     public void notePackageUninstalled(String pkgName) {
    950         enforceCallingPermission();
    951         synchronized (mStats) {
    952             mStats.notePackageUninstalledLocked(pkgName);
    953         }
    954     }
    955 
    956     @Override
    957     public void noteBleScanStarted(WorkSource ws, boolean isUnoptimized) {
    958         enforceCallingPermission();
    959         synchronized (mStats) {
    960             mStats.noteBluetoothScanStartedFromSourceLocked(ws, isUnoptimized);
    961         }
    962     }
    963 
    964     @Override
    965     public void noteBleScanStopped(WorkSource ws) {
    966         enforceCallingPermission();
    967         synchronized (mStats) {
    968             mStats.noteBluetoothScanStoppedFromSourceLocked(ws);
    969         }
    970     }
    971 
    972     @Override
    973     public void noteResetBleScan() {
    974         enforceCallingPermission();
    975         synchronized (mStats) {
    976             mStats.noteResetBluetoothScanLocked();
    977         }
    978     }
    979 
    980     @Override
    981     public void noteBleScanResults(WorkSource ws, int numNewResults) {
    982         enforceCallingPermission();
    983         synchronized (mStats) {
    984             mStats.noteBluetoothScanResultsFromSourceLocked(ws, numNewResults);
    985         }
    986     }
    987 
    988     @Override
    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
   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
   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 
   1025     public boolean isOnBattery() {
   1026         return mStats.isOnBattery();
   1027     }
   1028 
   1029     @Override
   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 
   1062     public long getAwakeTimeBattery() {
   1063         mContext.enforceCallingOrSelfPermission(
   1064                 android.Manifest.permission.BATTERY_STATS, null);
   1065         return mStats.getAwakeTimeBattery();
   1066     }
   1067 
   1068     public long getAwakeTimePlugged() {
   1069         mContext.enforceCallingOrSelfPermission(
   1070                 android.Manifest.permission.BATTERY_STATS, null);
   1071         return mStats.getAwakeTimePlugged();
   1072     }
   1073 
   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 
   1088         WakeupReasonThread() {
   1089             super("BatteryStats_wakeupReason");
   1090         }
   1091 
   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 
   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 
   1141     private static native int nativeWaitWakeup(ByteBuffer outBuffer);
   1142 
   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 
   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
   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 
   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      */
   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      */
   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
   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
   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      */
   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      */
   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