Home | History | Annotate | Download | only in os
      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.internal.os;
     18 
     19 import static android.net.NetworkStats.IFACE_ALL;
     20 import static android.net.NetworkStats.UID_ALL;
     21 import static android.text.format.DateUtils.SECOND_IN_MILLIS;
     22 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
     23 
     24 import android.bluetooth.BluetoothDevice;
     25 import android.bluetooth.BluetoothHeadset;
     26 import android.content.res.Resources;
     27 import android.net.ConnectivityManager;
     28 import android.net.NetworkStats;
     29 import android.os.BatteryManager;
     30 import android.os.BatteryStats;
     31 import android.os.FileUtils;
     32 import android.os.Handler;
     33 import android.os.Message;
     34 import android.os.Parcel;
     35 import android.os.ParcelFormatException;
     36 import android.os.Parcelable;
     37 import android.os.Process;
     38 import android.os.SystemClock;
     39 import android.os.SystemProperties;
     40 import android.os.WorkSource;
     41 import android.telephony.ServiceState;
     42 import android.telephony.SignalStrength;
     43 import android.telephony.TelephonyManager;
     44 import android.util.Log;
     45 import android.util.LogWriter;
     46 import android.util.PrintWriterPrinter;
     47 import android.util.Printer;
     48 import android.util.Slog;
     49 import android.util.SparseArray;
     50 import android.util.TimeUtils;
     51 
     52 import com.android.internal.R;
     53 import com.android.internal.net.NetworkStatsFactory;
     54 import com.android.internal.util.JournaledFile;
     55 import com.google.android.collect.Sets;
     56 
     57 import java.io.BufferedReader;
     58 import java.io.File;
     59 import java.io.FileInputStream;
     60 import java.io.FileOutputStream;
     61 import java.io.FileReader;
     62 import java.io.IOException;
     63 import java.io.PrintWriter;
     64 import java.util.ArrayList;
     65 import java.util.HashMap;
     66 import java.util.HashSet;
     67 import java.util.Iterator;
     68 import java.util.List;
     69 import java.util.Map;
     70 import java.util.concurrent.atomic.AtomicInteger;
     71 import java.util.concurrent.locks.ReentrantLock;
     72 
     73 /**
     74  * All information we are collecting about things that can happen that impact
     75  * battery life.  All times are represented in microseconds except where indicated
     76  * otherwise.
     77  */
     78 public final class BatteryStatsImpl extends BatteryStats {
     79     private static final String TAG = "BatteryStatsImpl";
     80     private static final boolean DEBUG = false;
     81     private static final boolean DEBUG_HISTORY = false;
     82     private static final boolean USE_OLD_HISTORY = false;   // for debugging.
     83 
     84     // TODO: remove "tcp" from network methods, since we measure total stats.
     85 
     86     // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
     87     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
     88 
     89     // Current on-disk Parcel version
     90     private static final int VERSION = 61 + (USE_OLD_HISTORY ? 1000 : 0);
     91 
     92     // Maximum number of items we will record in the history.
     93     private static final int MAX_HISTORY_ITEMS = 2000;
     94 
     95     // No, really, THIS is the maximum number of items we will record in the history.
     96     private static final int MAX_MAX_HISTORY_ITEMS = 3000;
     97 
     98     // The maximum number of names wakelocks we will keep track of
     99     // per uid; once the limit is reached, we batch the remaining wakelocks
    100     // in to one common name.
    101     private static final int MAX_WAKELOCKS_PER_UID = 30;
    102 
    103     // The system process gets more.  It is special.  Oh so special.
    104     // With, you know, special needs.  Like this.
    105     private static final int MAX_WAKELOCKS_PER_UID_IN_SYSTEM = 50;
    106 
    107     private static final String BATCHED_WAKELOCK_NAME = "*overflow*";
    108 
    109     private static int sNumSpeedSteps;
    110 
    111     private final JournaledFile mFile;
    112 
    113     static final int MSG_UPDATE_WAKELOCKS = 1;
    114     static final int MSG_REPORT_POWER_CHANGE = 2;
    115     static final long DELAY_UPDATE_WAKELOCKS = 5*1000;
    116 
    117     public interface BatteryCallback {
    118         public void batteryNeedsCpuUpdate();
    119         public void batteryPowerChanged(boolean onBattery);
    120     }
    121 
    122     final class MyHandler extends Handler {
    123         @Override
    124         public void handleMessage(Message msg) {
    125             BatteryCallback cb = mCallback;
    126             switch (msg.what) {
    127                 case MSG_UPDATE_WAKELOCKS:
    128                     if (cb != null) {
    129                         cb.batteryNeedsCpuUpdate();
    130                     }
    131                     break;
    132                 case MSG_REPORT_POWER_CHANGE:
    133                     if (cb != null) {
    134                         cb.batteryPowerChanged(msg.arg1 != 0);
    135                     }
    136                     break;
    137             }
    138         }
    139     }
    140 
    141     private final MyHandler mHandler;
    142 
    143     private BatteryCallback mCallback;
    144 
    145     /**
    146      * The statistics we have collected organized by uids.
    147      */
    148     final SparseArray<BatteryStatsImpl.Uid> mUidStats =
    149         new SparseArray<BatteryStatsImpl.Uid>();
    150 
    151     // A set of pools of currently active timers.  When a timer is queried, we will divide the
    152     // elapsed time by the number of active timers to arrive at that timer's share of the time.
    153     // In order to do this, we must refresh each timer whenever the number of active timers
    154     // changes.
    155     final ArrayList<StopwatchTimer> mPartialTimers = new ArrayList<StopwatchTimer>();
    156     final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<StopwatchTimer>();
    157     final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<StopwatchTimer>();
    158     final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers
    159             = new SparseArray<ArrayList<StopwatchTimer>>();
    160     final ArrayList<StopwatchTimer> mWifiRunningTimers = new ArrayList<StopwatchTimer>();
    161     final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<StopwatchTimer>();
    162     final ArrayList<StopwatchTimer> mScanWifiLockTimers = new ArrayList<StopwatchTimer>();
    163     final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<StopwatchTimer>();
    164 
    165     // Last partial timers we use for distributing CPU usage.
    166     final ArrayList<StopwatchTimer> mLastPartialTimers = new ArrayList<StopwatchTimer>();
    167 
    168     // These are the objects that will want to do something when the device
    169     // is unplugged from power.
    170     final ArrayList<Unpluggable> mUnpluggables = new ArrayList<Unpluggable>();
    171 
    172     boolean mShuttingDown;
    173 
    174     long mHistoryBaseTime;
    175     boolean mHaveBatteryLevel = false;
    176     boolean mRecordingHistory = true;
    177     int mNumHistoryItems;
    178 
    179     static final int MAX_HISTORY_BUFFER = 128*1024; // 128KB
    180     static final int MAX_MAX_HISTORY_BUFFER = 144*1024; // 144KB
    181     final Parcel mHistoryBuffer = Parcel.obtain();
    182     final HistoryItem mHistoryLastWritten = new HistoryItem();
    183     final HistoryItem mHistoryLastLastWritten = new HistoryItem();
    184     final HistoryItem mHistoryReadTmp = new HistoryItem();
    185     int mHistoryBufferLastPos = -1;
    186     boolean mHistoryOverflow = false;
    187     long mLastHistoryTime = 0;
    188 
    189     final HistoryItem mHistoryCur = new HistoryItem();
    190 
    191     HistoryItem mHistory;
    192     HistoryItem mHistoryEnd;
    193     HistoryItem mHistoryLastEnd;
    194     HistoryItem mHistoryCache;
    195 
    196     private HistoryItem mHistoryIterator;
    197     private boolean mReadOverflow;
    198     private boolean mIteratingHistory;
    199 
    200     int mStartCount;
    201 
    202     long mBatteryUptime;
    203     long mBatteryLastUptime;
    204     long mBatteryRealtime;
    205     long mBatteryLastRealtime;
    206 
    207     long mUptime;
    208     long mUptimeStart;
    209     long mLastUptime;
    210     long mRealtime;
    211     long mRealtimeStart;
    212     long mLastRealtime;
    213 
    214     boolean mScreenOn;
    215     StopwatchTimer mScreenOnTimer;
    216 
    217     int mScreenBrightnessBin = -1;
    218     final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
    219 
    220     Counter mInputEventCounter;
    221 
    222     boolean mPhoneOn;
    223     StopwatchTimer mPhoneOnTimer;
    224 
    225     boolean mAudioOn;
    226     StopwatchTimer mAudioOnTimer;
    227 
    228     boolean mVideoOn;
    229     StopwatchTimer mVideoOnTimer;
    230 
    231     int mPhoneSignalStrengthBin = -1;
    232     int mPhoneSignalStrengthBinRaw = -1;
    233     final StopwatchTimer[] mPhoneSignalStrengthsTimer =
    234             new StopwatchTimer[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
    235 
    236     StopwatchTimer mPhoneSignalScanningTimer;
    237 
    238     int mPhoneDataConnectionType = -1;
    239     final StopwatchTimer[] mPhoneDataConnectionsTimer =
    240             new StopwatchTimer[NUM_DATA_CONNECTION_TYPES];
    241 
    242     boolean mWifiOn;
    243     StopwatchTimer mWifiOnTimer;
    244     int mWifiOnUid = -1;
    245 
    246     boolean mGlobalWifiRunning;
    247     StopwatchTimer mGlobalWifiRunningTimer;
    248 
    249     boolean mBluetoothOn;
    250     StopwatchTimer mBluetoothOnTimer;
    251 
    252     /** Bluetooth headset object */
    253     BluetoothHeadset mBtHeadset;
    254 
    255     /**
    256      * These provide time bases that discount the time the device is plugged
    257      * in to power.
    258      */
    259     boolean mOnBattery;
    260     boolean mOnBatteryInternal;
    261     long mTrackBatteryPastUptime;
    262     long mTrackBatteryUptimeStart;
    263     long mTrackBatteryPastRealtime;
    264     long mTrackBatteryRealtimeStart;
    265 
    266     long mUnpluggedBatteryUptime;
    267     long mUnpluggedBatteryRealtime;
    268 
    269     /*
    270      * These keep track of battery levels (1-100) at the last plug event and the last unplug event.
    271      */
    272     int mDischargeStartLevel;
    273     int mDischargeUnplugLevel;
    274     int mDischargeCurrentLevel;
    275     int mLowDischargeAmountSinceCharge;
    276     int mHighDischargeAmountSinceCharge;
    277     int mDischargeScreenOnUnplugLevel;
    278     int mDischargeScreenOffUnplugLevel;
    279     int mDischargeAmountScreenOn;
    280     int mDischargeAmountScreenOnSinceCharge;
    281     int mDischargeAmountScreenOff;
    282     int mDischargeAmountScreenOffSinceCharge;
    283 
    284     long mLastWriteTime = 0; // Milliseconds
    285 
    286     // Mobile data transferred while on battery
    287     private long[] mMobileDataTx = new long[4];
    288     private long[] mMobileDataRx = new long[4];
    289     private long[] mTotalDataTx = new long[4];
    290     private long[] mTotalDataRx = new long[4];
    291 
    292     private long mRadioDataUptime;
    293     private long mRadioDataStart;
    294 
    295     private int mBluetoothPingCount;
    296     private int mBluetoothPingStart = -1;
    297 
    298     private int mPhoneServiceState = -1;
    299     private int mPhoneServiceStateRaw = -1;
    300     private int mPhoneSimStateRaw = -1;
    301 
    302     /*
    303      * Holds a SamplingTimer associated with each kernel wakelock name being tracked.
    304      */
    305     private final HashMap<String, SamplingTimer> mKernelWakelockStats =
    306             new HashMap<String, SamplingTimer>();
    307 
    308     public Map<String, ? extends SamplingTimer> getKernelWakelockStats() {
    309         return mKernelWakelockStats;
    310     }
    311 
    312     private static int sKernelWakelockUpdateVersion = 0;
    313 
    314     private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
    315         Process.PROC_TAB_TERM|Process.PROC_OUT_STRING,                // 0: name
    316         Process.PROC_TAB_TERM|Process.PROC_OUT_LONG,                  // 1: count
    317         Process.PROC_TAB_TERM,
    318         Process.PROC_TAB_TERM,
    319         Process.PROC_TAB_TERM,
    320         Process.PROC_TAB_TERM|Process.PROC_OUT_LONG,                  // 5: totalTime
    321     };
    322 
    323     private final String[] mProcWakelocksName = new String[3];
    324     private final long[] mProcWakelocksData = new long[3];
    325 
    326     /*
    327      * Used as a buffer for reading in data from /proc/wakelocks before it is processed and added
    328      * to mKernelWakelockStats.
    329      */
    330     private final Map<String, KernelWakelockStats> mProcWakelockFileStats =
    331             new HashMap<String, KernelWakelockStats>();
    332 
    333     private HashMap<String, Integer> mUidCache = new HashMap<String, Integer>();
    334 
    335     private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
    336 
    337     /** Network ifaces that {@link ConnectivityManager} has claimed as mobile. */
    338     private HashSet<String> mMobileIfaces = Sets.newHashSet();
    339 
    340     // For debugging
    341     public BatteryStatsImpl() {
    342         mFile = null;
    343         mHandler = null;
    344     }
    345 
    346     public static interface Unpluggable {
    347         void unplug(long batteryUptime, long batteryRealtime);
    348         void plug(long batteryUptime, long batteryRealtime);
    349     }
    350 
    351     /**
    352      * State for keeping track of counting information.
    353      */
    354     public static class Counter extends BatteryStats.Counter implements Unpluggable {
    355         final AtomicInteger mCount = new AtomicInteger();
    356         final ArrayList<Unpluggable> mUnpluggables;
    357         int mLoadedCount;
    358         int mLastCount;
    359         int mUnpluggedCount;
    360         int mPluggedCount;
    361 
    362         Counter(ArrayList<Unpluggable> unpluggables, Parcel in) {
    363             mUnpluggables = unpluggables;
    364             mPluggedCount = in.readInt();
    365             mCount.set(mPluggedCount);
    366             mLoadedCount = in.readInt();
    367             mLastCount = 0;
    368             mUnpluggedCount = in.readInt();
    369             unpluggables.add(this);
    370         }
    371 
    372         Counter(ArrayList<Unpluggable> unpluggables) {
    373             mUnpluggables = unpluggables;
    374             unpluggables.add(this);
    375         }
    376 
    377         public void writeToParcel(Parcel out) {
    378             out.writeInt(mCount.get());
    379             out.writeInt(mLoadedCount);
    380             out.writeInt(mUnpluggedCount);
    381         }
    382 
    383         public void unplug(long batteryUptime, long batteryRealtime) {
    384             mUnpluggedCount = mPluggedCount;
    385             mCount.set(mPluggedCount);
    386         }
    387 
    388         public void plug(long batteryUptime, long batteryRealtime) {
    389             mPluggedCount = mCount.get();
    390         }
    391 
    392         /**
    393          * Writes a possibly null Counter to a Parcel.
    394          *
    395          * @param out the Parcel to be written to.
    396          * @param counter a Counter, or null.
    397          */
    398         public static void writeCounterToParcel(Parcel out, Counter counter) {
    399             if (counter == null) {
    400                 out.writeInt(0); // indicates null
    401                 return;
    402             }
    403             out.writeInt(1); // indicates non-null
    404 
    405             counter.writeToParcel(out);
    406         }
    407 
    408         @Override
    409         public int getCountLocked(int which) {
    410             int val;
    411             if (which == STATS_LAST) {
    412                 val = mLastCount;
    413             } else {
    414                 val = mCount.get();
    415                 if (which == STATS_SINCE_UNPLUGGED) {
    416                     val -= mUnpluggedCount;
    417                 } else if (which != STATS_SINCE_CHARGED) {
    418                     val -= mLoadedCount;
    419                 }
    420             }
    421 
    422             return val;
    423         }
    424 
    425         public void logState(Printer pw, String prefix) {
    426             pw.println(prefix + "mCount=" + mCount.get()
    427                     + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
    428                     + " mUnpluggedCount=" + mUnpluggedCount
    429                     + " mPluggedCount=" + mPluggedCount);
    430         }
    431 
    432         void stepAtomic() {
    433             mCount.incrementAndGet();
    434         }
    435 
    436         /**
    437          * Clear state of this counter.
    438          */
    439         void reset(boolean detachIfReset) {
    440             mCount.set(0);
    441             mLoadedCount = mLastCount = mPluggedCount = mUnpluggedCount = 0;
    442             if (detachIfReset) {
    443                 detach();
    444             }
    445         }
    446 
    447         void detach() {
    448             mUnpluggables.remove(this);
    449         }
    450 
    451         void writeSummaryFromParcelLocked(Parcel out) {
    452             int count = mCount.get();
    453             out.writeInt(count);
    454         }
    455 
    456         void readSummaryFromParcelLocked(Parcel in) {
    457             mLoadedCount = in.readInt();
    458             mCount.set(mLoadedCount);
    459             mLastCount = 0;
    460             mUnpluggedCount = mPluggedCount = mLoadedCount;
    461         }
    462     }
    463 
    464     public static class SamplingCounter extends Counter {
    465 
    466         SamplingCounter(ArrayList<Unpluggable> unpluggables, Parcel in) {
    467             super(unpluggables, in);
    468         }
    469 
    470         SamplingCounter(ArrayList<Unpluggable> unpluggables) {
    471             super(unpluggables);
    472         }
    473 
    474         public void addCountAtomic(long count) {
    475             mCount.addAndGet((int)count);
    476         }
    477     }
    478 
    479     /**
    480      * State for keeping track of timing information.
    481      */
    482     public static abstract class Timer extends BatteryStats.Timer implements Unpluggable {
    483         final int mType;
    484         final ArrayList<Unpluggable> mUnpluggables;
    485 
    486         int mCount;
    487         int mLoadedCount;
    488         int mLastCount;
    489         int mUnpluggedCount;
    490 
    491         // Times are in microseconds for better accuracy when dividing by the
    492         // lock count, and are in "battery realtime" units.
    493 
    494         /**
    495          * The total time we have accumulated since the start of the original
    496          * boot, to the last time something interesting happened in the
    497          * current run.
    498          */
    499         long mTotalTime;
    500 
    501         /**
    502          * The total time we loaded for the previous runs.  Subtract this from
    503          * mTotalTime to find the time for the current run of the system.
    504          */
    505         long mLoadedTime;
    506 
    507         /**
    508          * The run time of the last run of the system, as loaded from the
    509          * saved data.
    510          */
    511         long mLastTime;
    512 
    513         /**
    514          * The value of mTotalTime when unplug() was last called.  Subtract
    515          * this from mTotalTime to find the time since the last unplug from
    516          * power.
    517          */
    518         long mUnpluggedTime;
    519 
    520         /**
    521          * Constructs from a parcel.
    522          * @param type
    523          * @param unpluggables
    524          * @param powerType
    525          * @param in
    526          */
    527         Timer(int type, ArrayList<Unpluggable> unpluggables, Parcel in) {
    528             mType = type;
    529             mUnpluggables = unpluggables;
    530 
    531             mCount = in.readInt();
    532             mLoadedCount = in.readInt();
    533             mLastCount = 0;
    534             mUnpluggedCount = in.readInt();
    535             mTotalTime = in.readLong();
    536             mLoadedTime = in.readLong();
    537             mLastTime = 0;
    538             mUnpluggedTime = in.readLong();
    539             unpluggables.add(this);
    540         }
    541 
    542         Timer(int type, ArrayList<Unpluggable> unpluggables) {
    543             mType = type;
    544             mUnpluggables = unpluggables;
    545             unpluggables.add(this);
    546         }
    547 
    548         protected abstract long computeRunTimeLocked(long curBatteryRealtime);
    549 
    550         protected abstract int computeCurrentCountLocked();
    551 
    552         /**
    553          * Clear state of this timer.  Returns true if the timer is inactive
    554          * so can be completely dropped.
    555          */
    556         boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
    557             mTotalTime = mLoadedTime = mLastTime = 0;
    558             mCount = mLoadedCount = mLastCount = 0;
    559             if (detachIfReset) {
    560                 detach();
    561             }
    562             return true;
    563         }
    564 
    565         void detach() {
    566             mUnpluggables.remove(this);
    567         }
    568 
    569         public void writeToParcel(Parcel out, long batteryRealtime) {
    570             out.writeInt(mCount);
    571             out.writeInt(mLoadedCount);
    572             out.writeInt(mUnpluggedCount);
    573             out.writeLong(computeRunTimeLocked(batteryRealtime));
    574             out.writeLong(mLoadedTime);
    575             out.writeLong(mUnpluggedTime);
    576         }
    577 
    578         public void unplug(long batteryUptime, long batteryRealtime) {
    579             if (DEBUG && mType < 0) {
    580                 Log.v(TAG, "unplug #" + mType + ": realtime=" + batteryRealtime
    581                         + " old mUnpluggedTime=" + mUnpluggedTime
    582                         + " old mUnpluggedCount=" + mUnpluggedCount);
    583             }
    584             mUnpluggedTime = computeRunTimeLocked(batteryRealtime);
    585             mUnpluggedCount = mCount;
    586             if (DEBUG && mType < 0) {
    587                 Log.v(TAG, "unplug #" + mType
    588                         + ": new mUnpluggedTime=" + mUnpluggedTime
    589                         + " new mUnpluggedCount=" + mUnpluggedCount);
    590             }
    591         }
    592 
    593         public void plug(long batteryUptime, long batteryRealtime) {
    594             if (DEBUG && mType < 0) {
    595                 Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime
    596                         + " old mTotalTime=" + mTotalTime);
    597             }
    598             mTotalTime = computeRunTimeLocked(batteryRealtime);
    599             mCount = computeCurrentCountLocked();
    600             if (DEBUG && mType < 0) {
    601                 Log.v(TAG, "plug #" + mType
    602                         + ": new mTotalTime=" + mTotalTime);
    603             }
    604         }
    605 
    606         /**
    607          * Writes a possibly null Timer to a Parcel.
    608          *
    609          * @param out the Parcel to be written to.
    610          * @param timer a Timer, or null.
    611          */
    612         public static void writeTimerToParcel(Parcel out, Timer timer,
    613                 long batteryRealtime) {
    614             if (timer == null) {
    615                 out.writeInt(0); // indicates null
    616                 return;
    617             }
    618             out.writeInt(1); // indicates non-null
    619 
    620             timer.writeToParcel(out, batteryRealtime);
    621         }
    622 
    623         @Override
    624         public long getTotalTimeLocked(long batteryRealtime, int which) {
    625             long val;
    626             if (which == STATS_LAST) {
    627                 val = mLastTime;
    628             } else {
    629                 val = computeRunTimeLocked(batteryRealtime);
    630                 if (which == STATS_SINCE_UNPLUGGED) {
    631                     val -= mUnpluggedTime;
    632                 } else if (which != STATS_SINCE_CHARGED) {
    633                     val -= mLoadedTime;
    634                 }
    635             }
    636 
    637             return val;
    638         }
    639 
    640         @Override
    641         public int getCountLocked(int which) {
    642             int val;
    643             if (which == STATS_LAST) {
    644                 val = mLastCount;
    645             } else {
    646                 val = computeCurrentCountLocked();
    647                 if (which == STATS_SINCE_UNPLUGGED) {
    648                     val -= mUnpluggedCount;
    649                 } else if (which != STATS_SINCE_CHARGED) {
    650                     val -= mLoadedCount;
    651                 }
    652             }
    653 
    654             return val;
    655         }
    656 
    657         public void logState(Printer pw, String prefix) {
    658             pw.println(prefix + " mCount=" + mCount
    659                     + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
    660                     + " mUnpluggedCount=" + mUnpluggedCount);
    661             pw.println(prefix + "mTotalTime=" + mTotalTime
    662                     + " mLoadedTime=" + mLoadedTime);
    663             pw.println(prefix + "mLastTime=" + mLastTime
    664                     + " mUnpluggedTime=" + mUnpluggedTime);
    665         }
    666 
    667 
    668         void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
    669             long runTime = computeRunTimeLocked(batteryRealtime);
    670             // Divide by 1000 for backwards compatibility
    671             out.writeLong((runTime + 500) / 1000);
    672             out.writeInt(mCount);
    673         }
    674 
    675         void readSummaryFromParcelLocked(Parcel in) {
    676             // Multiply by 1000 for backwards compatibility
    677             mTotalTime = mLoadedTime = in.readLong() * 1000;
    678             mLastTime = 0;
    679             mUnpluggedTime = mTotalTime;
    680             mCount = mLoadedCount = in.readInt();
    681             mLastCount = 0;
    682             mUnpluggedCount = mCount;
    683         }
    684     }
    685 
    686     public static final class SamplingTimer extends Timer {
    687 
    688         /**
    689          * The most recent reported count from /proc/wakelocks.
    690          */
    691         int mCurrentReportedCount;
    692 
    693         /**
    694          * The reported count from /proc/wakelocks when unplug() was last
    695          * called.
    696          */
    697         int mUnpluggedReportedCount;
    698 
    699         /**
    700          * The most recent reported total_time from /proc/wakelocks.
    701          */
    702         long mCurrentReportedTotalTime;
    703 
    704 
    705         /**
    706          * The reported total_time from /proc/wakelocks when unplug() was last
    707          * called.
    708          */
    709         long mUnpluggedReportedTotalTime;
    710 
    711         /**
    712          * Whether we are currently in a discharge cycle.
    713          */
    714         boolean mInDischarge;
    715 
    716         /**
    717          * Whether we are currently recording reported values.
    718          */
    719         boolean mTrackingReportedValues;
    720 
    721         /*
    722          * A sequnce counter, incremented once for each update of the stats.
    723          */
    724         int mUpdateVersion;
    725 
    726         SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge, Parcel in) {
    727             super(0, unpluggables, in);
    728             mCurrentReportedCount = in.readInt();
    729             mUnpluggedReportedCount = in.readInt();
    730             mCurrentReportedTotalTime = in.readLong();
    731             mUnpluggedReportedTotalTime = in.readLong();
    732             mTrackingReportedValues = in.readInt() == 1;
    733             mInDischarge = inDischarge;
    734         }
    735 
    736         SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge,
    737                 boolean trackReportedValues) {
    738             super(0, unpluggables);
    739             mTrackingReportedValues = trackReportedValues;
    740             mInDischarge = inDischarge;
    741         }
    742 
    743         public void setStale() {
    744             mTrackingReportedValues = false;
    745             mUnpluggedReportedTotalTime = 0;
    746             mUnpluggedReportedCount = 0;
    747         }
    748 
    749         public void setUpdateVersion(int version) {
    750             mUpdateVersion = version;
    751         }
    752 
    753         public int getUpdateVersion() {
    754             return mUpdateVersion;
    755         }
    756 
    757         public void updateCurrentReportedCount(int count) {
    758             if (mInDischarge && mUnpluggedReportedCount == 0) {
    759                 // Updating the reported value for the first time.
    760                 mUnpluggedReportedCount = count;
    761                 // If we are receiving an update update mTrackingReportedValues;
    762                 mTrackingReportedValues = true;
    763             }
    764             mCurrentReportedCount = count;
    765         }
    766 
    767         public void updateCurrentReportedTotalTime(long totalTime) {
    768             if (mInDischarge && mUnpluggedReportedTotalTime == 0) {
    769                 // Updating the reported value for the first time.
    770                 mUnpluggedReportedTotalTime = totalTime;
    771                 // If we are receiving an update update mTrackingReportedValues;
    772                 mTrackingReportedValues = true;
    773             }
    774             mCurrentReportedTotalTime = totalTime;
    775         }
    776 
    777         public void unplug(long batteryUptime, long batteryRealtime) {
    778             super.unplug(batteryUptime, batteryRealtime);
    779             if (mTrackingReportedValues) {
    780                 mUnpluggedReportedTotalTime = mCurrentReportedTotalTime;
    781                 mUnpluggedReportedCount = mCurrentReportedCount;
    782             }
    783             mInDischarge = true;
    784         }
    785 
    786         public void plug(long batteryUptime, long batteryRealtime) {
    787             super.plug(batteryUptime, batteryRealtime);
    788             mInDischarge = false;
    789         }
    790 
    791         public void logState(Printer pw, String prefix) {
    792             super.logState(pw, prefix);
    793             pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount
    794                     + " mUnpluggedReportedCount=" + mUnpluggedReportedCount
    795                     + " mCurrentReportedTotalTime=" + mCurrentReportedTotalTime
    796                     + " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTime);
    797         }
    798 
    799         protected long computeRunTimeLocked(long curBatteryRealtime) {
    800             return mTotalTime + (mInDischarge && mTrackingReportedValues
    801                     ? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0);
    802         }
    803 
    804         protected int computeCurrentCountLocked() {
    805             return mCount + (mInDischarge && mTrackingReportedValues
    806                     ? mCurrentReportedCount - mUnpluggedReportedCount : 0);
    807         }
    808 
    809         public void writeToParcel(Parcel out, long batteryRealtime) {
    810             super.writeToParcel(out, batteryRealtime);
    811             out.writeInt(mCurrentReportedCount);
    812             out.writeInt(mUnpluggedReportedCount);
    813             out.writeLong(mCurrentReportedTotalTime);
    814             out.writeLong(mUnpluggedReportedTotalTime);
    815             out.writeInt(mTrackingReportedValues ? 1 : 0);
    816         }
    817 
    818         boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
    819             super.reset(stats, detachIfReset);
    820             setStale();
    821             return true;
    822         }
    823 
    824         void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
    825             super.writeSummaryFromParcelLocked(out, batteryRealtime);
    826             out.writeLong(mCurrentReportedTotalTime);
    827             out.writeInt(mCurrentReportedCount);
    828             out.writeInt(mTrackingReportedValues ? 1 : 0);
    829         }
    830 
    831         void readSummaryFromParcelLocked(Parcel in) {
    832             super.readSummaryFromParcelLocked(in);
    833             mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong();
    834             mUnpluggedReportedCount = mCurrentReportedCount = in.readInt();
    835             mTrackingReportedValues = in.readInt() == 1;
    836         }
    837     }
    838 
    839     /**
    840      * State for keeping track of timing information.
    841      */
    842     public static final class StopwatchTimer extends Timer {
    843         final Uid mUid;
    844         final ArrayList<StopwatchTimer> mTimerPool;
    845 
    846         int mNesting;
    847 
    848         /**
    849          * The last time at which we updated the timer.  If mNesting is > 0,
    850          * subtract this from the current battery time to find the amount of
    851          * time we have been running since we last computed an update.
    852          */
    853         long mUpdateTime;
    854 
    855         /**
    856          * The total time at which the timer was acquired, to determine if it
    857          * was actually held for an interesting duration.
    858          */
    859         long mAcquireTime;
    860 
    861         long mTimeout;
    862 
    863         /**
    864          * For partial wake locks, keep track of whether we are in the list
    865          * to consume CPU cycles.
    866          */
    867         boolean mInList;
    868 
    869         StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
    870                 ArrayList<Unpluggable> unpluggables, Parcel in) {
    871             super(type, unpluggables, in);
    872             mUid = uid;
    873             mTimerPool = timerPool;
    874             mUpdateTime = in.readLong();
    875         }
    876 
    877         StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
    878                 ArrayList<Unpluggable> unpluggables) {
    879             super(type, unpluggables);
    880             mUid = uid;
    881             mTimerPool = timerPool;
    882         }
    883 
    884         void setTimeout(long timeout) {
    885             mTimeout = timeout;
    886         }
    887 
    888         public void writeToParcel(Parcel out, long batteryRealtime) {
    889             super.writeToParcel(out, batteryRealtime);
    890             out.writeLong(mUpdateTime);
    891         }
    892 
    893         public void plug(long batteryUptime, long batteryRealtime) {
    894             if (mNesting > 0) {
    895                 if (DEBUG && mType < 0) {
    896                     Log.v(TAG, "old mUpdateTime=" + mUpdateTime);
    897                 }
    898                 super.plug(batteryUptime, batteryRealtime);
    899                 mUpdateTime = batteryRealtime;
    900                 if (DEBUG && mType < 0) {
    901                     Log.v(TAG, "new mUpdateTime=" + mUpdateTime);
    902                 }
    903             }
    904         }
    905 
    906         public void logState(Printer pw, String prefix) {
    907             super.logState(pw, prefix);
    908             pw.println(prefix + "mNesting=" + mNesting + "mUpdateTime=" + mUpdateTime
    909                     + " mAcquireTime=" + mAcquireTime);
    910         }
    911 
    912         void startRunningLocked(BatteryStatsImpl stats) {
    913             if (mNesting++ == 0) {
    914                 mUpdateTime = stats.getBatteryRealtimeLocked(
    915                         SystemClock.elapsedRealtime() * 1000);
    916                 if (mTimerPool != null) {
    917                     // Accumulate time to all currently active timers before adding
    918                     // this new one to the pool.
    919                     refreshTimersLocked(stats, mTimerPool);
    920                     // Add this timer to the active pool
    921                     mTimerPool.add(this);
    922                 }
    923                 // Increment the count
    924                 mCount++;
    925                 mAcquireTime = mTotalTime;
    926                 if (DEBUG && mType < 0) {
    927                     Log.v(TAG, "start #" + mType + ": mUpdateTime=" + mUpdateTime
    928                             + " mTotalTime=" + mTotalTime + " mCount=" + mCount
    929                             + " mAcquireTime=" + mAcquireTime);
    930                 }
    931             }
    932         }
    933 
    934         boolean isRunningLocked() {
    935             return mNesting > 0;
    936         }
    937 
    938         void stopRunningLocked(BatteryStatsImpl stats) {
    939             // Ignore attempt to stop a timer that isn't running
    940             if (mNesting == 0) {
    941                 return;
    942             }
    943             if (--mNesting == 0) {
    944                 if (mTimerPool != null) {
    945                     // Accumulate time to all active counters, scaled by the total
    946                     // active in the pool, before taking this one out of the pool.
    947                     refreshTimersLocked(stats, mTimerPool);
    948                     // Remove this timer from the active pool
    949                     mTimerPool.remove(this);
    950                 } else {
    951                     final long realtime = SystemClock.elapsedRealtime() * 1000;
    952                     final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
    953                     mNesting = 1;
    954                     mTotalTime = computeRunTimeLocked(batteryRealtime);
    955                     mNesting = 0;
    956                 }
    957 
    958                 if (DEBUG && mType < 0) {
    959                     Log.v(TAG, "stop #" + mType + ": mUpdateTime=" + mUpdateTime
    960                             + " mTotalTime=" + mTotalTime + " mCount=" + mCount
    961                             + " mAcquireTime=" + mAcquireTime);
    962                 }
    963 
    964                 if (mTotalTime == mAcquireTime) {
    965                     // If there was no change in the time, then discard this
    966                     // count.  A somewhat cheezy strategy, but hey.
    967                     mCount--;
    968                 }
    969             }
    970         }
    971 
    972         // Update the total time for all other running Timers with the same type as this Timer
    973         // due to a change in timer count
    974         private static void refreshTimersLocked(final BatteryStatsImpl stats,
    975                 final ArrayList<StopwatchTimer> pool) {
    976             final long realtime = SystemClock.elapsedRealtime() * 1000;
    977             final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
    978             final int N = pool.size();
    979             for (int i=N-1; i>= 0; i--) {
    980                 final StopwatchTimer t = pool.get(i);
    981                 long heldTime = batteryRealtime - t.mUpdateTime;
    982                 if (heldTime > 0) {
    983                     t.mTotalTime += heldTime / N;
    984                 }
    985                 t.mUpdateTime = batteryRealtime;
    986             }
    987         }
    988 
    989         @Override
    990         protected long computeRunTimeLocked(long curBatteryRealtime) {
    991             if (mTimeout > 0 && curBatteryRealtime > mUpdateTime + mTimeout) {
    992                 curBatteryRealtime = mUpdateTime + mTimeout;
    993             }
    994             return mTotalTime + (mNesting > 0
    995                     ? (curBatteryRealtime - mUpdateTime)
    996                             / (mTimerPool != null ? mTimerPool.size() : 1)
    997                     : 0);
    998         }
    999 
   1000         @Override
   1001         protected int computeCurrentCountLocked() {
   1002             return mCount;
   1003         }
   1004 
   1005         boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
   1006             boolean canDetach = mNesting <= 0;
   1007             super.reset(stats, canDetach && detachIfReset);
   1008             if (mNesting > 0) {
   1009                 mUpdateTime = stats.getBatteryRealtimeLocked(
   1010                         SystemClock.elapsedRealtime() * 1000);
   1011             }
   1012             mAcquireTime = mTotalTime;
   1013             return canDetach;
   1014         }
   1015 
   1016         void detach() {
   1017             super.detach();
   1018             if (mTimerPool != null) {
   1019                 mTimerPool.remove(this);
   1020             }
   1021         }
   1022 
   1023         void readSummaryFromParcelLocked(Parcel in) {
   1024             super.readSummaryFromParcelLocked(in);
   1025             mNesting = 0;
   1026         }
   1027     }
   1028 
   1029     private final Map<String, KernelWakelockStats> readKernelWakelockStats() {
   1030 
   1031         byte[] buffer = new byte[8192];
   1032         int len;
   1033 
   1034         try {
   1035             FileInputStream is = new FileInputStream("/proc/wakelocks");
   1036             len = is.read(buffer);
   1037             is.close();
   1038 
   1039             if (len > 0) {
   1040                 int i;
   1041                 for (i=0; i<len; i++) {
   1042                     if (buffer[i] == '\0') {
   1043                         len = i;
   1044                         break;
   1045                     }
   1046                 }
   1047             }
   1048         } catch (java.io.FileNotFoundException e) {
   1049             return null;
   1050         } catch (java.io.IOException e) {
   1051             return null;
   1052         }
   1053 
   1054         return parseProcWakelocks(buffer, len);
   1055     }
   1056 
   1057     private final Map<String, KernelWakelockStats> parseProcWakelocks(
   1058             byte[] wlBuffer, int len) {
   1059         String name;
   1060         int count;
   1061         long totalTime;
   1062         int startIndex;
   1063         int endIndex;
   1064         int numUpdatedWlNames = 0;
   1065 
   1066         // Advance past the first line.
   1067         int i;
   1068         for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++);
   1069         startIndex = endIndex = i + 1;
   1070 
   1071         synchronized(this) {
   1072             Map<String, KernelWakelockStats> m = mProcWakelockFileStats;
   1073 
   1074             sKernelWakelockUpdateVersion++;
   1075             while (endIndex < len) {
   1076                 for (endIndex=startIndex;
   1077                         endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
   1078                         endIndex++);
   1079                 endIndex++; // endIndex is an exclusive upper bound.
   1080                 // Don't go over the end of the buffer, Process.parseProcLine might
   1081                 // write to wlBuffer[endIndex]
   1082                 if (endIndex >= (len - 1) ) {
   1083                     return m;
   1084                 }
   1085 
   1086                 String[] nameStringArray = mProcWakelocksName;
   1087                 long[] wlData = mProcWakelocksData;
   1088                 // Stomp out any bad characters since this is from a circular buffer
   1089                 // A corruption is seen sometimes that results in the vm crashing
   1090                 // This should prevent crashes and the line will probably fail to parse
   1091                 for (int j = startIndex; j < endIndex; j++) {
   1092                     if ((wlBuffer[j] & 0x80) != 0) wlBuffer[j] = (byte) '?';
   1093                 }
   1094                 boolean parsed = Process.parseProcLine(wlBuffer, startIndex, endIndex,
   1095                         PROC_WAKELOCKS_FORMAT, nameStringArray, wlData, null);
   1096 
   1097                 name = nameStringArray[0];
   1098                 count = (int) wlData[1];
   1099                 // convert nanoseconds to microseconds with rounding.
   1100                 totalTime = (wlData[2] + 500) / 1000;
   1101 
   1102                 if (parsed && name.length() > 0) {
   1103                     if (!m.containsKey(name)) {
   1104                         m.put(name, new KernelWakelockStats(count, totalTime,
   1105                                 sKernelWakelockUpdateVersion));
   1106                         numUpdatedWlNames++;
   1107                     } else {
   1108                         KernelWakelockStats kwlStats = m.get(name);
   1109                         if (kwlStats.mVersion == sKernelWakelockUpdateVersion) {
   1110                             kwlStats.mCount += count;
   1111                             kwlStats.mTotalTime += totalTime;
   1112                         } else {
   1113                             kwlStats.mCount = count;
   1114                             kwlStats.mTotalTime = totalTime;
   1115                             kwlStats.mVersion = sKernelWakelockUpdateVersion;
   1116                             numUpdatedWlNames++;
   1117                         }
   1118                     }
   1119                 }
   1120                 startIndex = endIndex;
   1121             }
   1122 
   1123             if (m.size() != numUpdatedWlNames) {
   1124                 // Don't report old data.
   1125                 Iterator<KernelWakelockStats> itr = m.values().iterator();
   1126                 while (itr.hasNext()) {
   1127                     if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
   1128                         itr.remove();
   1129                     }
   1130                 }
   1131             }
   1132             return m;
   1133         }
   1134     }
   1135 
   1136     private class KernelWakelockStats {
   1137         public int mCount;
   1138         public long mTotalTime;
   1139         public int mVersion;
   1140 
   1141         KernelWakelockStats(int count, long totalTime, int version) {
   1142             mCount = count;
   1143             mTotalTime = totalTime;
   1144             mVersion = version;
   1145         }
   1146     }
   1147 
   1148     /*
   1149      * Get the KernelWakelockTimer associated with name, and create a new one if one
   1150      * doesn't already exist.
   1151      */
   1152     public SamplingTimer getKernelWakelockTimerLocked(String name) {
   1153         SamplingTimer kwlt = mKernelWakelockStats.get(name);
   1154         if (kwlt == null) {
   1155             kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
   1156                     true /* track reported values */);
   1157             mKernelWakelockStats.put(name, kwlt);
   1158         }
   1159         return kwlt;
   1160     }
   1161 
   1162     private void doDataPlug(long[] dataTransfer, long currentBytes) {
   1163         dataTransfer[STATS_LAST] = dataTransfer[STATS_SINCE_UNPLUGGED];
   1164         dataTransfer[STATS_SINCE_UNPLUGGED] = -1;
   1165     }
   1166 
   1167     private void doDataUnplug(long[] dataTransfer, long currentBytes) {
   1168         dataTransfer[STATS_SINCE_UNPLUGGED] = currentBytes;
   1169     }
   1170 
   1171     /**
   1172      * Radio uptime in microseconds when transferring data. This value is very approximate.
   1173      * @return
   1174      */
   1175     private long getCurrentRadioDataUptime() {
   1176         try {
   1177             File awakeTimeFile = new File("/sys/devices/virtual/net/rmnet0/awake_time_ms");
   1178             if (!awakeTimeFile.exists()) return 0;
   1179             BufferedReader br = new BufferedReader(new FileReader(awakeTimeFile));
   1180             String line = br.readLine();
   1181             br.close();
   1182             return Long.parseLong(line) * 1000;
   1183         } catch (NumberFormatException nfe) {
   1184             // Nothing
   1185         } catch (IOException ioe) {
   1186             // Nothing
   1187         }
   1188         return 0;
   1189     }
   1190 
   1191     /**
   1192      * @deprecated use getRadioDataUptime
   1193      */
   1194     public long getRadioDataUptimeMs() {
   1195         return getRadioDataUptime() / 1000;
   1196     }
   1197 
   1198     /**
   1199      * Returns the duration that the cell radio was up for data transfers.
   1200      */
   1201     public long getRadioDataUptime() {
   1202         if (mRadioDataStart == -1) {
   1203             return mRadioDataUptime;
   1204         } else {
   1205             return getCurrentRadioDataUptime() - mRadioDataStart;
   1206         }
   1207     }
   1208 
   1209     private int getCurrentBluetoothPingCount() {
   1210         if (mBtHeadset != null) {
   1211             List<BluetoothDevice> deviceList = mBtHeadset.getConnectedDevices();
   1212             if (deviceList.size() > 0) {
   1213                 return mBtHeadset.getBatteryUsageHint(deviceList.get(0));
   1214             }
   1215         }
   1216         return -1;
   1217     }
   1218 
   1219     public int getBluetoothPingCount() {
   1220         if (mBluetoothPingStart == -1) {
   1221             return mBluetoothPingCount;
   1222         } else if (mBtHeadset != null) {
   1223             return getCurrentBluetoothPingCount() - mBluetoothPingStart;
   1224         }
   1225         return 0;
   1226     }
   1227 
   1228     public void setBtHeadset(BluetoothHeadset headset) {
   1229         if (headset != null && mBtHeadset == null && isOnBattery() && mBluetoothPingStart == -1) {
   1230             mBluetoothPingStart = getCurrentBluetoothPingCount();
   1231         }
   1232         mBtHeadset = headset;
   1233     }
   1234 
   1235     int mChangedBufferStates = 0;
   1236 
   1237     void addHistoryBufferLocked(long curTime) {
   1238         if (!mHaveBatteryLevel || !mRecordingHistory) {
   1239             return;
   1240         }
   1241 
   1242         final long timeDiff = (mHistoryBaseTime+curTime) - mHistoryLastWritten.time;
   1243         if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
   1244                 && timeDiff < 2000
   1245                 && ((mHistoryLastWritten.states^mHistoryCur.states)&mChangedBufferStates) == 0) {
   1246             // If the current is the same as the one before, then we no
   1247             // longer need the entry.
   1248             mHistoryBuffer.setDataSize(mHistoryBufferLastPos);
   1249             mHistoryBuffer.setDataPosition(mHistoryBufferLastPos);
   1250             mHistoryBufferLastPos = -1;
   1251             if (mHistoryLastLastWritten.cmd == HistoryItem.CMD_UPDATE
   1252                     && timeDiff < 500 && mHistoryLastLastWritten.same(mHistoryCur)) {
   1253                 // If this results in us returning to the state written
   1254                 // prior to the last one, then we can just delete the last
   1255                 // written one and drop the new one.  Nothing more to do.
   1256                 mHistoryLastWritten.setTo(mHistoryLastLastWritten);
   1257                 mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
   1258                 return;
   1259             }
   1260             mChangedBufferStates |= mHistoryLastWritten.states^mHistoryCur.states;
   1261             curTime = mHistoryLastWritten.time - mHistoryBaseTime;
   1262             mHistoryLastWritten.setTo(mHistoryLastLastWritten);
   1263         } else {
   1264             mChangedBufferStates = 0;
   1265         }
   1266 
   1267         final int dataSize = mHistoryBuffer.dataSize();
   1268         if (dataSize >= MAX_HISTORY_BUFFER) {
   1269             if (!mHistoryOverflow) {
   1270                 mHistoryOverflow = true;
   1271                 addHistoryBufferLocked(curTime, HistoryItem.CMD_OVERFLOW);
   1272             }
   1273 
   1274             // Once we've reached the maximum number of items, we only
   1275             // record changes to the battery level and the most interesting states.
   1276             // Once we've reached the maximum maximum number of items, we only
   1277             // record changes to the battery level.
   1278             if (mHistoryLastWritten.batteryLevel == mHistoryCur.batteryLevel &&
   1279                     (dataSize >= MAX_MAX_HISTORY_BUFFER
   1280                             || ((mHistoryLastWritten.states^mHistoryCur.states)
   1281                                     & HistoryItem.MOST_INTERESTING_STATES) == 0)) {
   1282                 return;
   1283             }
   1284         }
   1285 
   1286         addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
   1287     }
   1288 
   1289     void addHistoryBufferLocked(long curTime, byte cmd) {
   1290         int origPos = 0;
   1291         if (mIteratingHistory) {
   1292             origPos = mHistoryBuffer.dataPosition();
   1293             mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
   1294         }
   1295         mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
   1296         mHistoryLastLastWritten.setTo(mHistoryLastWritten);
   1297         mHistoryLastWritten.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
   1298         mHistoryLastWritten.writeDelta(mHistoryBuffer, mHistoryLastLastWritten);
   1299         mLastHistoryTime = curTime;
   1300         if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
   1301                 + " now " + mHistoryBuffer.dataPosition()
   1302                 + " size is now " + mHistoryBuffer.dataSize());
   1303         if (mIteratingHistory) {
   1304             mHistoryBuffer.setDataPosition(origPos);
   1305         }
   1306     }
   1307 
   1308     int mChangedStates = 0;
   1309 
   1310     void addHistoryRecordLocked(long curTime) {
   1311         addHistoryBufferLocked(curTime);
   1312 
   1313         if (!USE_OLD_HISTORY) {
   1314             return;
   1315         }
   1316 
   1317         if (!mHaveBatteryLevel || !mRecordingHistory) {
   1318             return;
   1319         }
   1320 
   1321         // If the current time is basically the same as the last time,
   1322         // and no states have since the last recorded entry changed and
   1323         // are now resetting back to their original value, then just collapse
   1324         // into one record.
   1325         if (mHistoryEnd != null && mHistoryEnd.cmd == HistoryItem.CMD_UPDATE
   1326                 && (mHistoryBaseTime+curTime) < (mHistoryEnd.time+2000)
   1327                 && ((mHistoryEnd.states^mHistoryCur.states)&mChangedStates) == 0) {
   1328             // If the current is the same as the one before, then we no
   1329             // longer need the entry.
   1330             if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE
   1331                     && (mHistoryBaseTime+curTime) < (mHistoryEnd.time+500)
   1332                     && mHistoryLastEnd.same(mHistoryCur)) {
   1333                 mHistoryLastEnd.next = null;
   1334                 mHistoryEnd.next = mHistoryCache;
   1335                 mHistoryCache = mHistoryEnd;
   1336                 mHistoryEnd = mHistoryLastEnd;
   1337                 mHistoryLastEnd = null;
   1338             } else {
   1339                 mChangedStates |= mHistoryEnd.states^mHistoryCur.states;
   1340                 mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, mHistoryCur);
   1341             }
   1342             return;
   1343         }
   1344 
   1345         mChangedStates = 0;
   1346 
   1347         if (mNumHistoryItems == MAX_HISTORY_ITEMS
   1348                 || mNumHistoryItems == MAX_MAX_HISTORY_ITEMS) {
   1349             addHistoryRecordLocked(curTime, HistoryItem.CMD_OVERFLOW);
   1350         }
   1351 
   1352         if (mNumHistoryItems >= MAX_HISTORY_ITEMS) {
   1353             // Once we've reached the maximum number of items, we only
   1354             // record changes to the battery level and the most interesting states.
   1355             // Once we've reached the maximum maximum number of items, we only
   1356             // record changes to the battery level.
   1357             if (mHistoryEnd != null && mHistoryEnd.batteryLevel
   1358                     == mHistoryCur.batteryLevel &&
   1359                     (mNumHistoryItems >= MAX_MAX_HISTORY_ITEMS
   1360                             || ((mHistoryEnd.states^mHistoryCur.states)
   1361                                     & HistoryItem.MOST_INTERESTING_STATES) == 0)) {
   1362                 return;
   1363             }
   1364         }
   1365 
   1366         addHistoryRecordLocked(curTime, HistoryItem.CMD_UPDATE);
   1367     }
   1368 
   1369     void addHistoryRecordLocked(long curTime, byte cmd) {
   1370         HistoryItem rec = mHistoryCache;
   1371         if (rec != null) {
   1372             mHistoryCache = rec.next;
   1373         } else {
   1374             rec = new HistoryItem();
   1375         }
   1376         rec.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
   1377 
   1378         addHistoryRecordLocked(rec);
   1379     }
   1380 
   1381     void addHistoryRecordLocked(HistoryItem rec) {
   1382         mNumHistoryItems++;
   1383         rec.next = null;
   1384         mHistoryLastEnd = mHistoryEnd;
   1385         if (mHistoryEnd != null) {
   1386             mHistoryEnd.next = rec;
   1387             mHistoryEnd = rec;
   1388         } else {
   1389             mHistory = mHistoryEnd = rec;
   1390         }
   1391     }
   1392 
   1393     void clearHistoryLocked() {
   1394         if (DEBUG_HISTORY) Slog.i(TAG, "********** CLEARING HISTORY!");
   1395         if (USE_OLD_HISTORY) {
   1396             if (mHistory != null) {
   1397                 mHistoryEnd.next = mHistoryCache;
   1398                 mHistoryCache = mHistory;
   1399                 mHistory = mHistoryLastEnd = mHistoryEnd = null;
   1400             }
   1401             mNumHistoryItems = 0;
   1402         }
   1403 
   1404         mHistoryBaseTime = 0;
   1405         mLastHistoryTime = 0;
   1406 
   1407         mHistoryBuffer.setDataSize(0);
   1408         mHistoryBuffer.setDataPosition(0);
   1409         mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER/2);
   1410         mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
   1411         mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
   1412         mHistoryBufferLastPos = -1;
   1413         mHistoryOverflow = false;
   1414     }
   1415 
   1416     public void doUnplugLocked(long batteryUptime, long batteryRealtime) {
   1417         NetworkStats.Entry entry = null;
   1418 
   1419         // Track UID data usage
   1420         final NetworkStats uidStats = getNetworkStatsDetailGroupedByUid();
   1421         final int size = uidStats.size();
   1422         for (int i = 0; i < size; i++) {
   1423             entry = uidStats.getValues(i, entry);
   1424 
   1425             final Uid u = mUidStats.get(entry.uid);
   1426             if (u == null) continue;
   1427 
   1428             u.mStartedTcpBytesReceived = entry.rxBytes;
   1429             u.mStartedTcpBytesSent = entry.txBytes;
   1430             u.mTcpBytesReceivedAtLastUnplug = u.mCurrentTcpBytesReceived;
   1431             u.mTcpBytesSentAtLastUnplug = u.mCurrentTcpBytesSent;
   1432         }
   1433 
   1434         for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
   1435             mUnpluggables.get(i).unplug(batteryUptime, batteryRealtime);
   1436         }
   1437 
   1438         // Track both mobile and total overall data
   1439         final NetworkStats ifaceStats = getNetworkStatsSummary();
   1440         entry = ifaceStats.getTotal(entry, mMobileIfaces);
   1441         doDataUnplug(mMobileDataRx, entry.rxBytes);
   1442         doDataUnplug(mMobileDataTx, entry.txBytes);
   1443         entry = ifaceStats.getTotal(entry);
   1444         doDataUnplug(mTotalDataRx, entry.rxBytes);
   1445         doDataUnplug(mTotalDataTx, entry.txBytes);
   1446 
   1447         // Track radio awake time
   1448         mRadioDataStart = getCurrentRadioDataUptime();
   1449         mRadioDataUptime = 0;
   1450 
   1451         // Track bt headset ping count
   1452         mBluetoothPingStart = getCurrentBluetoothPingCount();
   1453         mBluetoothPingCount = 0;
   1454     }
   1455 
   1456     public void doPlugLocked(long batteryUptime, long batteryRealtime) {
   1457         NetworkStats.Entry entry = null;
   1458 
   1459         for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
   1460             Uid u = mUidStats.valueAt(iu);
   1461             if (u.mStartedTcpBytesReceived >= 0) {
   1462                 u.mCurrentTcpBytesReceived = u.computeCurrentTcpBytesReceived();
   1463                 u.mStartedTcpBytesReceived = -1;
   1464             }
   1465             if (u.mStartedTcpBytesSent >= 0) {
   1466                 u.mCurrentTcpBytesSent = u.computeCurrentTcpBytesSent();
   1467                 u.mStartedTcpBytesSent = -1;
   1468             }
   1469         }
   1470         for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
   1471             mUnpluggables.get(i).plug(batteryUptime, batteryRealtime);
   1472         }
   1473 
   1474         // Track both mobile and total overall data
   1475         final NetworkStats ifaceStats = getNetworkStatsSummary();
   1476         entry = ifaceStats.getTotal(entry, mMobileIfaces);
   1477         doDataPlug(mMobileDataRx, entry.rxBytes);
   1478         doDataPlug(mMobileDataTx, entry.txBytes);
   1479         entry = ifaceStats.getTotal(entry);
   1480         doDataPlug(mTotalDataRx, entry.rxBytes);
   1481         doDataPlug(mTotalDataTx, entry.txBytes);
   1482 
   1483         // Track radio awake time
   1484         mRadioDataUptime = getRadioDataUptime();
   1485         mRadioDataStart = -1;
   1486 
   1487         // Track bt headset ping count
   1488         mBluetoothPingCount = getBluetoothPingCount();
   1489         mBluetoothPingStart = -1;
   1490     }
   1491 
   1492     int mWakeLockNesting;
   1493 
   1494     public void noteStartWakeLocked(int uid, int pid, String name, int type) {
   1495         if (type == WAKE_TYPE_PARTIAL) {
   1496             // Only care about partial wake locks, since full wake locks
   1497             // will be canceled when the user puts the screen to sleep.
   1498             if (mWakeLockNesting == 0) {
   1499                 mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG;
   1500                 if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
   1501                         + Integer.toHexString(mHistoryCur.states));
   1502                 addHistoryRecordLocked(SystemClock.elapsedRealtime());
   1503             }
   1504             mWakeLockNesting++;
   1505         }
   1506         if (uid >= 0) {
   1507             if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
   1508                 Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
   1509                 mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
   1510             }
   1511             getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type);
   1512         }
   1513     }
   1514 
   1515     public void noteStopWakeLocked(int uid, int pid, String name, int type) {
   1516         if (type == WAKE_TYPE_PARTIAL) {
   1517             mWakeLockNesting--;
   1518             if (mWakeLockNesting == 0) {
   1519                 mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
   1520                 if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
   1521                         + Integer.toHexString(mHistoryCur.states));
   1522                 addHistoryRecordLocked(SystemClock.elapsedRealtime());
   1523             }
   1524         }
   1525         if (uid >= 0) {
   1526             if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
   1527                 Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
   1528                 mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
   1529             }
   1530             getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type);
   1531         }
   1532     }
   1533 
   1534     public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
   1535         int N = ws.size();
   1536         for (int i=0; i<N; i++) {
   1537             noteStartWakeLocked(ws.get(i), pid, name, type);
   1538         }
   1539     }
   1540 
   1541     public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
   1542         int N = ws.size();
   1543         for (int i=0; i<N; i++) {
   1544             noteStopWakeLocked(ws.get(i), pid, name, type);
   1545         }
   1546     }
   1547 
   1548     public int startAddingCpuLocked() {
   1549         mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
   1550 
   1551         if (mScreenOn) {
   1552             return 0;
   1553         }
   1554 
   1555         final int N = mPartialTimers.size();
   1556         if (N == 0) {
   1557             mLastPartialTimers.clear();
   1558             return 0;
   1559         }
   1560 
   1561         // How many timers should consume CPU?  Only want to include ones
   1562         // that have already been in the list.
   1563         for (int i=0; i<N; i++) {
   1564             StopwatchTimer st = mPartialTimers.get(i);
   1565             if (st.mInList) {
   1566                 Uid uid = st.mUid;
   1567                 // We don't include the system UID, because it so often
   1568                 // holds wake locks at one request or another of an app.
   1569                 if (uid != null && uid.mUid != Process.SYSTEM_UID) {
   1570                     return 50;
   1571                 }
   1572             }
   1573         }
   1574 
   1575         return 0;
   1576     }
   1577 
   1578     public void finishAddingCpuLocked(int perc, int utime, int stime, long[] cpuSpeedTimes) {
   1579         final int N = mPartialTimers.size();
   1580         if (perc != 0) {
   1581             int num = 0;
   1582             for (int i=0; i<N; i++) {
   1583                 StopwatchTimer st = mPartialTimers.get(i);
   1584                 if (st.mInList) {
   1585                     Uid uid = st.mUid;
   1586                     // We don't include the system UID, because it so often
   1587                     // holds wake locks at one request or another of an app.
   1588                     if (uid != null && uid.mUid != Process.SYSTEM_UID) {
   1589                         num++;
   1590                     }
   1591                 }
   1592             }
   1593             if (num != 0) {
   1594                 for (int i=0; i<N; i++) {
   1595                     StopwatchTimer st = mPartialTimers.get(i);
   1596                     if (st.mInList) {
   1597                         Uid uid = st.mUid;
   1598                         if (uid != null && uid.mUid != Process.SYSTEM_UID) {
   1599                             int myUTime = utime/num;
   1600                             int mySTime = stime/num;
   1601                             utime -= myUTime;
   1602                             stime -= mySTime;
   1603                             num--;
   1604                             Uid.Proc proc = uid.getProcessStatsLocked("*wakelock*");
   1605                             proc.addCpuTimeLocked(myUTime, mySTime);
   1606                             proc.addSpeedStepTimes(cpuSpeedTimes);
   1607                         }
   1608                     }
   1609                 }
   1610             }
   1611 
   1612             // Just in case, collect any lost CPU time.
   1613             if (utime != 0 || stime != 0) {
   1614                 Uid uid = getUidStatsLocked(Process.SYSTEM_UID);
   1615                 if (uid != null) {
   1616                     Uid.Proc proc = uid.getProcessStatsLocked("*lost*");
   1617                     proc.addCpuTimeLocked(utime, stime);
   1618                     proc.addSpeedStepTimes(cpuSpeedTimes);
   1619                 }
   1620             }
   1621         }
   1622 
   1623         final int NL = mLastPartialTimers.size();
   1624         boolean diff = N != NL;
   1625         for (int i=0; i<NL && !diff; i++) {
   1626             diff |= mPartialTimers.get(i) != mLastPartialTimers.get(i);
   1627         }
   1628         if (!diff) {
   1629             for (int i=0; i<NL; i++) {
   1630                 mPartialTimers.get(i).mInList = true;
   1631             }
   1632             return;
   1633         }
   1634 
   1635         for (int i=0; i<NL; i++) {
   1636             mLastPartialTimers.get(i).mInList = false;
   1637         }
   1638         mLastPartialTimers.clear();
   1639         for (int i=0; i<N; i++) {
   1640             StopwatchTimer st = mPartialTimers.get(i);
   1641             st.mInList = true;
   1642             mLastPartialTimers.add(st);
   1643         }
   1644     }
   1645 
   1646     public void noteProcessDiedLocked(int uid, int pid) {
   1647         Uid u = mUidStats.get(uid);
   1648         if (u != null) {
   1649             u.mPids.remove(pid);
   1650         }
   1651     }
   1652 
   1653     public long getProcessWakeTime(int uid, int pid, long realtime) {
   1654         Uid u = mUidStats.get(uid);
   1655         if (u != null) {
   1656             Uid.Pid p = u.mPids.get(pid);
   1657             if (p != null) {
   1658                 return p.mWakeSum + (p.mWakeStart != 0 ? (realtime - p.mWakeStart) : 0);
   1659             }
   1660         }
   1661         return 0;
   1662     }
   1663 
   1664     public void reportExcessiveWakeLocked(int uid, String proc, long overTime, long usedTime) {
   1665         Uid u = mUidStats.get(uid);
   1666         if (u != null) {
   1667             u.reportExcessiveWakeLocked(proc, overTime, usedTime);
   1668         }
   1669     }
   1670 
   1671     public void reportExcessiveCpuLocked(int uid, String proc, long overTime, long usedTime) {
   1672         Uid u = mUidStats.get(uid);
   1673         if (u != null) {
   1674             u.reportExcessiveCpuLocked(proc, overTime, usedTime);
   1675         }
   1676     }
   1677 
   1678     int mSensorNesting;
   1679 
   1680     public void noteStartSensorLocked(int uid, int sensor) {
   1681         if (mSensorNesting == 0) {
   1682             mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
   1683             if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
   1684                     + Integer.toHexString(mHistoryCur.states));
   1685             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   1686         }
   1687         mSensorNesting++;
   1688         getUidStatsLocked(uid).noteStartSensor(sensor);
   1689     }
   1690 
   1691     public void noteStopSensorLocked(int uid, int sensor) {
   1692         mSensorNesting--;
   1693         if (mSensorNesting == 0) {
   1694             mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG;
   1695             if (DEBUG_HISTORY) Slog.v(TAG, "Stop sensor to: "
   1696                     + Integer.toHexString(mHistoryCur.states));
   1697             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   1698         }
   1699         getUidStatsLocked(uid).noteStopSensor(sensor);
   1700     }
   1701 
   1702     int mGpsNesting;
   1703 
   1704     public void noteStartGpsLocked(int uid) {
   1705         if (mGpsNesting == 0) {
   1706             mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
   1707             if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
   1708                     + Integer.toHexString(mHistoryCur.states));
   1709             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   1710         }
   1711         mGpsNesting++;
   1712         getUidStatsLocked(uid).noteStartGps();
   1713     }
   1714 
   1715     public void noteStopGpsLocked(int uid) {
   1716         mGpsNesting--;
   1717         if (mGpsNesting == 0) {
   1718             mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
   1719             if (DEBUG_HISTORY) Slog.v(TAG, "Stop GPS to: "
   1720                     + Integer.toHexString(mHistoryCur.states));
   1721             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   1722         }
   1723         getUidStatsLocked(uid).noteStopGps();
   1724     }
   1725 
   1726     public void noteScreenOnLocked() {
   1727         if (!mScreenOn) {
   1728             mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
   1729             if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
   1730                     + Integer.toHexString(mHistoryCur.states));
   1731             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   1732             mScreenOn = true;
   1733             mScreenOnTimer.startRunningLocked(this);
   1734             if (mScreenBrightnessBin >= 0) {
   1735                 mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
   1736             }
   1737 
   1738             // Fake a wake lock, so we consider the device waked as long
   1739             // as the screen is on.
   1740             noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
   1741 
   1742             // Update discharge amounts.
   1743             if (mOnBatteryInternal) {
   1744                 updateDischargeScreenLevelsLocked(false, true);
   1745             }
   1746         }
   1747     }
   1748 
   1749     public void noteScreenOffLocked() {
   1750         if (mScreenOn) {
   1751             mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
   1752             if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
   1753                     + Integer.toHexString(mHistoryCur.states));
   1754             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   1755             mScreenOn = false;
   1756             mScreenOnTimer.stopRunningLocked(this);
   1757             if (mScreenBrightnessBin >= 0) {
   1758                 mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
   1759             }
   1760 
   1761             noteStopWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
   1762 
   1763             // Update discharge amounts.
   1764             if (mOnBatteryInternal) {
   1765                 updateDischargeScreenLevelsLocked(true, false);
   1766             }
   1767         }
   1768     }
   1769 
   1770     public void noteScreenBrightnessLocked(int brightness) {
   1771         // Bin the brightness.
   1772         int bin = brightness / (256/NUM_SCREEN_BRIGHTNESS_BINS);
   1773         if (bin < 0) bin = 0;
   1774         else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
   1775         if (mScreenBrightnessBin != bin) {
   1776             mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_BRIGHTNESS_MASK)
   1777                     | (bin << HistoryItem.STATE_BRIGHTNESS_SHIFT);
   1778             if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
   1779                     + Integer.toHexString(mHistoryCur.states));
   1780             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   1781             if (mScreenOn) {
   1782                 if (mScreenBrightnessBin >= 0) {
   1783                     mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
   1784                 }
   1785                 mScreenBrightnessTimer[bin].startRunningLocked(this);
   1786             }
   1787             mScreenBrightnessBin = bin;
   1788         }
   1789     }
   1790 
   1791     public void noteInputEventAtomic() {
   1792         mInputEventCounter.stepAtomic();
   1793     }
   1794 
   1795     public void noteUserActivityLocked(int uid, int event) {
   1796         getUidStatsLocked(uid).noteUserActivityLocked(event);
   1797     }
   1798 
   1799     public void notePhoneOnLocked() {
   1800         if (!mPhoneOn) {
   1801             mHistoryCur.states |= HistoryItem.STATE_PHONE_IN_CALL_FLAG;
   1802             if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
   1803                     + Integer.toHexString(mHistoryCur.states));
   1804             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   1805             mPhoneOn = true;
   1806             mPhoneOnTimer.startRunningLocked(this);
   1807         }
   1808     }
   1809 
   1810     public void notePhoneOffLocked() {
   1811         if (mPhoneOn) {
   1812             mHistoryCur.states &= ~HistoryItem.STATE_PHONE_IN_CALL_FLAG;
   1813             if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
   1814                     + Integer.toHexString(mHistoryCur.states));
   1815             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   1816             mPhoneOn = false;
   1817             mPhoneOnTimer.stopRunningLocked(this);
   1818         }
   1819     }
   1820 
   1821     void stopAllSignalStrengthTimersLocked(int except) {
   1822         for (int i = 0; i < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
   1823             if (i == except) {
   1824                 continue;
   1825             }
   1826             while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
   1827                 mPhoneSignalStrengthsTimer[i].stopRunningLocked(this);
   1828             }
   1829         }
   1830     }
   1831 
   1832     private int fixPhoneServiceState(int state, int signalBin) {
   1833         if (mPhoneSimStateRaw == TelephonyManager.SIM_STATE_ABSENT) {
   1834             // In this case we will always be STATE_OUT_OF_SERVICE, so need
   1835             // to infer that we are scanning from other data.
   1836             if (state == ServiceState.STATE_OUT_OF_SERVICE
   1837                     && signalBin > SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
   1838                 state = ServiceState.STATE_IN_SERVICE;
   1839             }
   1840         }
   1841 
   1842         return state;
   1843     }
   1844 
   1845     private void updateAllPhoneStateLocked(int state, int simState, int bin) {
   1846         boolean scanning = false;
   1847         boolean newHistory = false;
   1848 
   1849         mPhoneServiceStateRaw = state;
   1850         mPhoneSimStateRaw = simState;
   1851         mPhoneSignalStrengthBinRaw = bin;
   1852 
   1853         if (simState == TelephonyManager.SIM_STATE_ABSENT) {
   1854             // In this case we will always be STATE_OUT_OF_SERVICE, so need
   1855             // to infer that we are scanning from other data.
   1856             if (state == ServiceState.STATE_OUT_OF_SERVICE
   1857                     && bin > SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
   1858                 state = ServiceState.STATE_IN_SERVICE;
   1859             }
   1860         }
   1861 
   1862         // If the phone is powered off, stop all timers.
   1863         if (state == ServiceState.STATE_POWER_OFF) {
   1864             bin = -1;
   1865 
   1866         // If we are in service, make sure the correct signal string timer is running.
   1867         } else if (state == ServiceState.STATE_IN_SERVICE) {
   1868             // Bin will be changed below.
   1869 
   1870         // If we're out of service, we are in the lowest signal strength
   1871         // bin and have the scanning bit set.
   1872         } else if (state == ServiceState.STATE_OUT_OF_SERVICE) {
   1873             scanning = true;
   1874             bin = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
   1875             if (!mPhoneSignalScanningTimer.isRunningLocked()) {
   1876                 mHistoryCur.states |= HistoryItem.STATE_PHONE_SCANNING_FLAG;
   1877                 newHistory = true;
   1878                 if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: "
   1879                         + Integer.toHexString(mHistoryCur.states));
   1880                 mPhoneSignalScanningTimer.startRunningLocked(this);
   1881             }
   1882         }
   1883 
   1884         if (!scanning) {
   1885             // If we are no longer scanning, then stop the scanning timer.
   1886             if (mPhoneSignalScanningTimer.isRunningLocked()) {
   1887                 mHistoryCur.states &= ~HistoryItem.STATE_PHONE_SCANNING_FLAG;
   1888                 if (DEBUG_HISTORY) Slog.v(TAG, "Phone stopped scanning to: "
   1889                         + Integer.toHexString(mHistoryCur.states));
   1890                 newHistory = true;
   1891                 mPhoneSignalScanningTimer.stopRunningLocked(this);
   1892             }
   1893         }
   1894 
   1895         if (mPhoneServiceState != state) {
   1896             mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_PHONE_STATE_MASK)
   1897                     | (state << HistoryItem.STATE_PHONE_STATE_SHIFT);
   1898             if (DEBUG_HISTORY) Slog.v(TAG, "Phone state " + state + " to: "
   1899                     + Integer.toHexString(mHistoryCur.states));
   1900             newHistory = true;
   1901             mPhoneServiceState = state;
   1902         }
   1903 
   1904         if (mPhoneSignalStrengthBin != bin) {
   1905             if (mPhoneSignalStrengthBin >= 0) {
   1906                 mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this);
   1907             }
   1908             if (bin >= 0) {
   1909                 if (!mPhoneSignalStrengthsTimer[bin].isRunningLocked()) {
   1910                     mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
   1911                 }
   1912                 mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_SIGNAL_STRENGTH_MASK)
   1913                         | (bin << HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT);
   1914                 if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + bin + " to: "
   1915                         + Integer.toHexString(mHistoryCur.states));
   1916                 newHistory = true;
   1917             } else {
   1918                 stopAllSignalStrengthTimersLocked(-1);
   1919             }
   1920             mPhoneSignalStrengthBin = bin;
   1921         }
   1922 
   1923         if (newHistory) {
   1924             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   1925         }
   1926     }
   1927 
   1928     /**
   1929      * Telephony stack updates the phone state.
   1930      * @param state phone state from ServiceState.getState()
   1931      */
   1932     public void notePhoneStateLocked(int state, int simState) {
   1933         updateAllPhoneStateLocked(state, simState, mPhoneSignalStrengthBinRaw);
   1934     }
   1935 
   1936     public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
   1937         // Bin the strength.
   1938         int bin = signalStrength.getLevel();
   1939         updateAllPhoneStateLocked(mPhoneServiceStateRaw, mPhoneSimStateRaw, bin);
   1940     }
   1941 
   1942     public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData) {
   1943         int bin = DATA_CONNECTION_NONE;
   1944         if (hasData) {
   1945             switch (dataType) {
   1946                 case TelephonyManager.NETWORK_TYPE_EDGE:
   1947                     bin = DATA_CONNECTION_EDGE;
   1948                     break;
   1949                 case TelephonyManager.NETWORK_TYPE_GPRS:
   1950                     bin = DATA_CONNECTION_GPRS;
   1951                     break;
   1952                 case TelephonyManager.NETWORK_TYPE_UMTS:
   1953                     bin = DATA_CONNECTION_UMTS;
   1954                     break;
   1955                 case TelephonyManager.NETWORK_TYPE_CDMA:
   1956                     bin = DATA_CONNECTION_CDMA;
   1957                     break;
   1958                 case TelephonyManager.NETWORK_TYPE_EVDO_0:
   1959                     bin = DATA_CONNECTION_EVDO_0;
   1960                     break;
   1961                 case TelephonyManager.NETWORK_TYPE_EVDO_A:
   1962                     bin = DATA_CONNECTION_EVDO_A;
   1963                     break;
   1964                 case TelephonyManager.NETWORK_TYPE_1xRTT:
   1965                     bin = DATA_CONNECTION_1xRTT;
   1966                     break;
   1967                 case TelephonyManager.NETWORK_TYPE_HSDPA:
   1968                     bin = DATA_CONNECTION_HSDPA;
   1969                     break;
   1970                 case TelephonyManager.NETWORK_TYPE_HSUPA:
   1971                     bin = DATA_CONNECTION_HSUPA;
   1972                     break;
   1973                 case TelephonyManager.NETWORK_TYPE_HSPA:
   1974                     bin = DATA_CONNECTION_HSPA;
   1975                     break;
   1976                 case TelephonyManager.NETWORK_TYPE_IDEN:
   1977                     bin = DATA_CONNECTION_IDEN;
   1978                     break;
   1979                 case TelephonyManager.NETWORK_TYPE_EVDO_B:
   1980                     bin = DATA_CONNECTION_EVDO_B;
   1981                     break;
   1982                 case TelephonyManager.NETWORK_TYPE_LTE:
   1983                     bin = DATA_CONNECTION_LTE;
   1984                     break;
   1985                 case TelephonyManager.NETWORK_TYPE_EHRPD:
   1986                     bin = DATA_CONNECTION_EHRPD;
   1987                     break;
   1988                 default:
   1989                     bin = DATA_CONNECTION_OTHER;
   1990                     break;
   1991             }
   1992         }
   1993         if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
   1994         if (mPhoneDataConnectionType != bin) {
   1995             mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
   1996                     | (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
   1997             if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
   1998                     + Integer.toHexString(mHistoryCur.states));
   1999             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2000             if (mPhoneDataConnectionType >= 0) {
   2001                 mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this);
   2002             }
   2003             mPhoneDataConnectionType = bin;
   2004             mPhoneDataConnectionsTimer[bin].startRunningLocked(this);
   2005         }
   2006     }
   2007 
   2008     public void noteWifiOnLocked() {
   2009         if (!mWifiOn) {
   2010             mHistoryCur.states |= HistoryItem.STATE_WIFI_ON_FLAG;
   2011             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
   2012                     + Integer.toHexString(mHistoryCur.states));
   2013             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2014             mWifiOn = true;
   2015             mWifiOnTimer.startRunningLocked(this);
   2016         }
   2017     }
   2018 
   2019     public void noteWifiOffLocked() {
   2020         if (mWifiOn) {
   2021             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_ON_FLAG;
   2022             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
   2023                     + Integer.toHexString(mHistoryCur.states));
   2024             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2025             mWifiOn = false;
   2026             mWifiOnTimer.stopRunningLocked(this);
   2027         }
   2028         if (mWifiOnUid >= 0) {
   2029             getUidStatsLocked(mWifiOnUid).noteWifiStoppedLocked();
   2030             mWifiOnUid = -1;
   2031         }
   2032     }
   2033 
   2034     public void noteAudioOnLocked(int uid) {
   2035         if (!mAudioOn) {
   2036             mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
   2037             if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
   2038                     + Integer.toHexString(mHistoryCur.states));
   2039             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2040             mAudioOn = true;
   2041             mAudioOnTimer.startRunningLocked(this);
   2042         }
   2043         getUidStatsLocked(uid).noteAudioTurnedOnLocked();
   2044     }
   2045 
   2046     public void noteAudioOffLocked(int uid) {
   2047         if (mAudioOn) {
   2048             mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
   2049             if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
   2050                     + Integer.toHexString(mHistoryCur.states));
   2051             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2052             mAudioOn = false;
   2053             mAudioOnTimer.stopRunningLocked(this);
   2054         }
   2055         getUidStatsLocked(uid).noteAudioTurnedOffLocked();
   2056     }
   2057 
   2058     public void noteVideoOnLocked(int uid) {
   2059         if (!mVideoOn) {
   2060             mHistoryCur.states |= HistoryItem.STATE_VIDEO_ON_FLAG;
   2061             if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
   2062                     + Integer.toHexString(mHistoryCur.states));
   2063             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2064             mVideoOn = true;
   2065             mVideoOnTimer.startRunningLocked(this);
   2066         }
   2067         getUidStatsLocked(uid).noteVideoTurnedOnLocked();
   2068     }
   2069 
   2070     public void noteVideoOffLocked(int uid) {
   2071         if (mVideoOn) {
   2072             mHistoryCur.states &= ~HistoryItem.STATE_VIDEO_ON_FLAG;
   2073             if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
   2074                     + Integer.toHexString(mHistoryCur.states));
   2075             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2076             mVideoOn = false;
   2077             mVideoOnTimer.stopRunningLocked(this);
   2078         }
   2079         getUidStatsLocked(uid).noteVideoTurnedOffLocked();
   2080     }
   2081 
   2082     public void noteWifiRunningLocked(WorkSource ws) {
   2083         if (!mGlobalWifiRunning) {
   2084             mHistoryCur.states |= HistoryItem.STATE_WIFI_RUNNING_FLAG;
   2085             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
   2086                     + Integer.toHexString(mHistoryCur.states));
   2087             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2088             mGlobalWifiRunning = true;
   2089             mGlobalWifiRunningTimer.startRunningLocked(this);
   2090             int N = ws.size();
   2091             for (int i=0; i<N; i++) {
   2092                 getUidStatsLocked(ws.get(i)).noteWifiRunningLocked();
   2093             }
   2094         } else {
   2095             Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
   2096         }
   2097     }
   2098 
   2099     public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
   2100         if (mGlobalWifiRunning) {
   2101             int N = oldWs.size();
   2102             for (int i=0; i<N; i++) {
   2103                 getUidStatsLocked(oldWs.get(i)).noteWifiStoppedLocked();
   2104             }
   2105             N = newWs.size();
   2106             for (int i=0; i<N; i++) {
   2107                 getUidStatsLocked(newWs.get(i)).noteWifiRunningLocked();
   2108             }
   2109         } else {
   2110             Log.w(TAG, "noteWifiRunningChangedLocked -- called while WIFI not running");
   2111         }
   2112     }
   2113 
   2114     public void noteWifiStoppedLocked(WorkSource ws) {
   2115         if (mGlobalWifiRunning) {
   2116             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RUNNING_FLAG;
   2117             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
   2118                     + Integer.toHexString(mHistoryCur.states));
   2119             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2120             mGlobalWifiRunning = false;
   2121             mGlobalWifiRunningTimer.stopRunningLocked(this);
   2122             int N = ws.size();
   2123             for (int i=0; i<N; i++) {
   2124                 getUidStatsLocked(ws.get(i)).noteWifiStoppedLocked();
   2125             }
   2126         } else {
   2127             Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
   2128         }
   2129     }
   2130 
   2131     public void noteBluetoothOnLocked() {
   2132         if (!mBluetoothOn) {
   2133             mHistoryCur.states |= HistoryItem.STATE_BLUETOOTH_ON_FLAG;
   2134             if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth on to: "
   2135                     + Integer.toHexString(mHistoryCur.states));
   2136             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2137             mBluetoothOn = true;
   2138             mBluetoothOnTimer.startRunningLocked(this);
   2139         }
   2140     }
   2141 
   2142     public void noteBluetoothOffLocked() {
   2143         if (mBluetoothOn) {
   2144             mHistoryCur.states &= ~HistoryItem.STATE_BLUETOOTH_ON_FLAG;
   2145             if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth off to: "
   2146                     + Integer.toHexString(mHistoryCur.states));
   2147             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2148             mBluetoothOn = false;
   2149             mBluetoothOnTimer.stopRunningLocked(this);
   2150         }
   2151     }
   2152 
   2153     int mWifiFullLockNesting = 0;
   2154 
   2155     public void noteFullWifiLockAcquiredLocked(int uid) {
   2156         if (mWifiFullLockNesting == 0) {
   2157             mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
   2158             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
   2159                     + Integer.toHexString(mHistoryCur.states));
   2160             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2161         }
   2162         mWifiFullLockNesting++;
   2163         getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
   2164     }
   2165 
   2166     public void noteFullWifiLockReleasedLocked(int uid) {
   2167         mWifiFullLockNesting--;
   2168         if (mWifiFullLockNesting == 0) {
   2169             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
   2170             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
   2171                     + Integer.toHexString(mHistoryCur.states));
   2172             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2173         }
   2174         getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
   2175     }
   2176 
   2177     int mWifiScanLockNesting = 0;
   2178 
   2179     public void noteScanWifiLockAcquiredLocked(int uid) {
   2180         if (mWifiScanLockNesting == 0) {
   2181             mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_LOCK_FLAG;
   2182             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock on to: "
   2183                     + Integer.toHexString(mHistoryCur.states));
   2184             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2185         }
   2186         mWifiScanLockNesting++;
   2187         getUidStatsLocked(uid).noteScanWifiLockAcquiredLocked();
   2188     }
   2189 
   2190     public void noteScanWifiLockReleasedLocked(int uid) {
   2191         mWifiScanLockNesting--;
   2192         if (mWifiScanLockNesting == 0) {
   2193             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_LOCK_FLAG;
   2194             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock off to: "
   2195                     + Integer.toHexString(mHistoryCur.states));
   2196             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2197         }
   2198         getUidStatsLocked(uid).noteScanWifiLockReleasedLocked();
   2199     }
   2200 
   2201     int mWifiMulticastNesting = 0;
   2202 
   2203     public void noteWifiMulticastEnabledLocked(int uid) {
   2204         if (mWifiMulticastNesting == 0) {
   2205             mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
   2206             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
   2207                     + Integer.toHexString(mHistoryCur.states));
   2208             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2209         }
   2210         mWifiMulticastNesting++;
   2211         getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
   2212     }
   2213 
   2214     public void noteWifiMulticastDisabledLocked(int uid) {
   2215         mWifiMulticastNesting--;
   2216         if (mWifiMulticastNesting == 0) {
   2217             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
   2218             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
   2219                     + Integer.toHexString(mHistoryCur.states));
   2220             addHistoryRecordLocked(SystemClock.elapsedRealtime());
   2221         }
   2222         getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
   2223     }
   2224 
   2225     public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
   2226         int N = ws.size();
   2227         for (int i=0; i<N; i++) {
   2228             noteFullWifiLockAcquiredLocked(ws.get(i));
   2229         }
   2230     }
   2231 
   2232     public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
   2233         int N = ws.size();
   2234         for (int i=0; i<N; i++) {
   2235             noteFullWifiLockReleasedLocked(ws.get(i));
   2236         }
   2237     }
   2238 
   2239     public void noteScanWifiLockAcquiredFromSourceLocked(WorkSource ws) {
   2240         int N = ws.size();
   2241         for (int i=0; i<N; i++) {
   2242             noteScanWifiLockAcquiredLocked(ws.get(i));
   2243         }
   2244     }
   2245 
   2246     public void noteScanWifiLockReleasedFromSourceLocked(WorkSource ws) {
   2247         int N = ws.size();
   2248         for (int i=0; i<N; i++) {
   2249             noteScanWifiLockReleasedLocked(ws.get(i));
   2250         }
   2251     }
   2252 
   2253     public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
   2254         int N = ws.size();
   2255         for (int i=0; i<N; i++) {
   2256             noteWifiMulticastEnabledLocked(ws.get(i));
   2257         }
   2258     }
   2259 
   2260     public void noteWifiMulticastDisabledFromSourceLocked(WorkSource ws) {
   2261         int N = ws.size();
   2262         for (int i=0; i<N; i++) {
   2263             noteWifiMulticastDisabledLocked(ws.get(i));
   2264         }
   2265     }
   2266 
   2267     public void noteNetworkInterfaceTypeLocked(String iface, int networkType) {
   2268         if (ConnectivityManager.isNetworkTypeMobile(networkType)) {
   2269             mMobileIfaces.add(iface);
   2270         } else {
   2271             mMobileIfaces.remove(iface);
   2272         }
   2273     }
   2274 
   2275     @Override public long getScreenOnTime(long batteryRealtime, int which) {
   2276         return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
   2277     }
   2278 
   2279     @Override public long getScreenBrightnessTime(int brightnessBin,
   2280             long batteryRealtime, int which) {
   2281         return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
   2282                 batteryRealtime, which);
   2283     }
   2284 
   2285     @Override public int getInputEventCount(int which) {
   2286         return mInputEventCounter.getCountLocked(which);
   2287     }
   2288 
   2289     @Override public long getPhoneOnTime(long batteryRealtime, int which) {
   2290         return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
   2291     }
   2292 
   2293     @Override public long getPhoneSignalStrengthTime(int strengthBin,
   2294             long batteryRealtime, int which) {
   2295         return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
   2296                 batteryRealtime, which);
   2297     }
   2298 
   2299     @Override public long getPhoneSignalScanningTime(
   2300             long batteryRealtime, int which) {
   2301         return mPhoneSignalScanningTimer.getTotalTimeLocked(
   2302                 batteryRealtime, which);
   2303     }
   2304 
   2305     @Override public int getPhoneSignalStrengthCount(int dataType, int which) {
   2306         return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
   2307     }
   2308 
   2309     @Override public long getPhoneDataConnectionTime(int dataType,
   2310             long batteryRealtime, int which) {
   2311         return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
   2312                 batteryRealtime, which);
   2313     }
   2314 
   2315     @Override public int getPhoneDataConnectionCount(int dataType, int which) {
   2316         return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
   2317     }
   2318 
   2319     @Override public long getWifiOnTime(long batteryRealtime, int which) {
   2320         return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
   2321     }
   2322 
   2323     @Override public long getGlobalWifiRunningTime(long batteryRealtime, int which) {
   2324         return mGlobalWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
   2325     }
   2326 
   2327     @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
   2328         return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
   2329     }
   2330 
   2331     @Override public boolean getIsOnBattery() {
   2332         return mOnBattery;
   2333     }
   2334 
   2335     @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
   2336         return mUidStats;
   2337     }
   2338 
   2339     /**
   2340      * The statistics associated with a particular uid.
   2341      */
   2342     public final class Uid extends BatteryStats.Uid {
   2343 
   2344         final int mUid;
   2345         long mLoadedTcpBytesReceived;
   2346         long mLoadedTcpBytesSent;
   2347         long mCurrentTcpBytesReceived;
   2348         long mCurrentTcpBytesSent;
   2349         long mTcpBytesReceivedAtLastUnplug;
   2350         long mTcpBytesSentAtLastUnplug;
   2351 
   2352         // These are not saved/restored when parcelling, since we want
   2353         // to return from the parcel with a snapshot of the state.
   2354         long mStartedTcpBytesReceived = -1;
   2355         long mStartedTcpBytesSent = -1;
   2356 
   2357         boolean mWifiRunning;
   2358         StopwatchTimer mWifiRunningTimer;
   2359 
   2360         boolean mFullWifiLockOut;
   2361         StopwatchTimer mFullWifiLockTimer;
   2362 
   2363         boolean mScanWifiLockOut;
   2364         StopwatchTimer mScanWifiLockTimer;
   2365 
   2366         boolean mWifiMulticastEnabled;
   2367         StopwatchTimer mWifiMulticastTimer;
   2368 
   2369         boolean mAudioTurnedOn;
   2370         StopwatchTimer mAudioTurnedOnTimer;
   2371 
   2372         boolean mVideoTurnedOn;
   2373         StopwatchTimer mVideoTurnedOnTimer;
   2374 
   2375         Counter[] mUserActivityCounters;
   2376 
   2377         /**
   2378          * The statistics we have collected for this uid's wake locks.
   2379          */
   2380         final HashMap<String, Wakelock> mWakelockStats = new HashMap<String, Wakelock>();
   2381 
   2382         /**
   2383          * The statistics we have collected for this uid's sensor activations.
   2384          */
   2385         final HashMap<Integer, Sensor> mSensorStats = new HashMap<Integer, Sensor>();
   2386 
   2387         /**
   2388          * The statistics we have collected for this uid's processes.
   2389          */
   2390         final HashMap<String, Proc> mProcessStats = new HashMap<String, Proc>();
   2391 
   2392         /**
   2393          * The statistics we have collected for this uid's processes.
   2394          */
   2395         final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
   2396 
   2397         /**
   2398          * The transient wake stats we have collected for this uid's pids.
   2399          */
   2400         final SparseArray<Pid> mPids = new SparseArray<Pid>();
   2401 
   2402         public Uid(int uid) {
   2403             mUid = uid;
   2404             mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
   2405                     mWifiRunningTimers, mUnpluggables);
   2406             mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
   2407                     mFullWifiLockTimers, mUnpluggables);
   2408             mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
   2409                     mScanWifiLockTimers, mUnpluggables);
   2410             mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
   2411                     mWifiMulticastTimers, mUnpluggables);
   2412             mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
   2413                     null, mUnpluggables);
   2414             mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
   2415                     null, mUnpluggables);
   2416         }
   2417 
   2418         @Override
   2419         public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
   2420             return mWakelockStats;
   2421         }
   2422 
   2423         @Override
   2424         public Map<Integer, ? extends BatteryStats.Uid.Sensor> getSensorStats() {
   2425             return mSensorStats;
   2426         }
   2427 
   2428         @Override
   2429         public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
   2430             return mProcessStats;
   2431         }
   2432 
   2433         @Override
   2434         public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
   2435             return mPackageStats;
   2436         }
   2437 
   2438         @Override
   2439         public int getUid() {
   2440             return mUid;
   2441         }
   2442 
   2443         @Override
   2444         public long getTcpBytesReceived(int which) {
   2445             if (which == STATS_LAST) {
   2446                 return mLoadedTcpBytesReceived;
   2447             } else {
   2448                 long current = computeCurrentTcpBytesReceived();
   2449                 if (which == STATS_SINCE_UNPLUGGED) {
   2450                     current -= mTcpBytesReceivedAtLastUnplug;
   2451                 } else if (which == STATS_SINCE_CHARGED) {
   2452                     current += mLoadedTcpBytesReceived;
   2453                 }
   2454                 return current;
   2455             }
   2456         }
   2457 
   2458         public long computeCurrentTcpBytesReceived() {
   2459             final long uidRxBytes = getNetworkStatsDetailGroupedByUid().getTotal(
   2460                     null, mUid).rxBytes;
   2461             return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
   2462                     ? (uidRxBytes - mStartedTcpBytesReceived) : 0);
   2463         }
   2464 
   2465         @Override
   2466         public long getTcpBytesSent(int which) {
   2467             if (which == STATS_LAST) {
   2468                 return mLoadedTcpBytesSent;
   2469             } else {
   2470                 long current = computeCurrentTcpBytesSent();
   2471                 if (which == STATS_SINCE_UNPLUGGED) {
   2472                     current -= mTcpBytesSentAtLastUnplug;
   2473                 } else if (which == STATS_SINCE_CHARGED) {
   2474                     current += mLoadedTcpBytesSent;
   2475                 }
   2476                 return current;
   2477             }
   2478         }
   2479 
   2480         @Override
   2481         public void noteWifiRunningLocked() {
   2482             if (!mWifiRunning) {
   2483                 mWifiRunning = true;
   2484                 if (mWifiRunningTimer == null) {
   2485                     mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
   2486                             mWifiRunningTimers, mUnpluggables);
   2487                 }
   2488                 mWifiRunningTimer.startRunningLocked(BatteryStatsImpl.this);
   2489             }
   2490         }
   2491 
   2492         @Override
   2493         public void noteWifiStoppedLocked() {
   2494             if (mWifiRunning) {
   2495                 mWifiRunning = false;
   2496                 mWifiRunningTimer.stopRunningLocked(BatteryStatsImpl.this);
   2497             }
   2498         }
   2499 
   2500         @Override
   2501         public void noteFullWifiLockAcquiredLocked() {
   2502             if (!mFullWifiLockOut) {
   2503                 mFullWifiLockOut = true;
   2504                 if (mFullWifiLockTimer == null) {
   2505                     mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
   2506                             mFullWifiLockTimers, mUnpluggables);
   2507                 }
   2508                 mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
   2509             }
   2510         }
   2511 
   2512         @Override
   2513         public void noteFullWifiLockReleasedLocked() {
   2514             if (mFullWifiLockOut) {
   2515                 mFullWifiLockOut = false;
   2516                 mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
   2517             }
   2518         }
   2519 
   2520         @Override
   2521         public void noteScanWifiLockAcquiredLocked() {
   2522             if (!mScanWifiLockOut) {
   2523                 mScanWifiLockOut = true;
   2524                 if (mScanWifiLockTimer == null) {
   2525                     mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
   2526                             mScanWifiLockTimers, mUnpluggables);
   2527                 }
   2528                 mScanWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
   2529             }
   2530         }
   2531 
   2532         @Override
   2533         public void noteScanWifiLockReleasedLocked() {
   2534             if (mScanWifiLockOut) {
   2535                 mScanWifiLockOut = false;
   2536                 mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
   2537             }
   2538         }
   2539 
   2540         @Override
   2541         public void noteWifiMulticastEnabledLocked() {
   2542             if (!mWifiMulticastEnabled) {
   2543                 mWifiMulticastEnabled = true;
   2544                 if (mWifiMulticastTimer == null) {
   2545                     mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
   2546                             mWifiMulticastTimers, mUnpluggables);
   2547                 }
   2548                 mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
   2549             }
   2550         }
   2551 
   2552         @Override
   2553         public void noteWifiMulticastDisabledLocked() {
   2554             if (mWifiMulticastEnabled) {
   2555                 mWifiMulticastEnabled = false;
   2556                 mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
   2557             }
   2558         }
   2559 
   2560         @Override
   2561         public void noteAudioTurnedOnLocked() {
   2562             if (!mAudioTurnedOn) {
   2563                 mAudioTurnedOn = true;
   2564                 if (mAudioTurnedOnTimer == null) {
   2565                     mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
   2566                             null, mUnpluggables);
   2567                 }
   2568                 mAudioTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
   2569             }
   2570         }
   2571 
   2572         @Override
   2573         public void noteAudioTurnedOffLocked() {
   2574             if (mAudioTurnedOn) {
   2575                 mAudioTurnedOn = false;
   2576                 mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
   2577             }
   2578         }
   2579 
   2580         @Override
   2581         public void noteVideoTurnedOnLocked() {
   2582             if (!mVideoTurnedOn) {
   2583                 mVideoTurnedOn = true;
   2584                 if (mVideoTurnedOnTimer == null) {
   2585                     mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
   2586                             null, mUnpluggables);
   2587                 }
   2588                 mVideoTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
   2589             }
   2590         }
   2591 
   2592         @Override
   2593         public void noteVideoTurnedOffLocked() {
   2594             if (mVideoTurnedOn) {
   2595                 mVideoTurnedOn = false;
   2596                 mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
   2597             }
   2598         }
   2599 
   2600         @Override
   2601         public long getWifiRunningTime(long batteryRealtime, int which) {
   2602             if (mWifiRunningTimer == null) {
   2603                 return 0;
   2604             }
   2605             return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
   2606         }
   2607 
   2608         @Override
   2609         public long getFullWifiLockTime(long batteryRealtime, int which) {
   2610             if (mFullWifiLockTimer == null) {
   2611                 return 0;
   2612             }
   2613             return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
   2614         }
   2615 
   2616         @Override
   2617         public long getScanWifiLockTime(long batteryRealtime, int which) {
   2618             if (mScanWifiLockTimer == null) {
   2619                 return 0;
   2620             }
   2621             return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
   2622         }
   2623 
   2624         @Override
   2625         public long getWifiMulticastTime(long batteryRealtime, int which) {
   2626             if (mWifiMulticastTimer == null) {
   2627                 return 0;
   2628             }
   2629             return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime,
   2630                                                           which);
   2631         }
   2632 
   2633         @Override
   2634         public long getAudioTurnedOnTime(long batteryRealtime, int which) {
   2635             if (mAudioTurnedOnTimer == null) {
   2636                 return 0;
   2637             }
   2638             return mAudioTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
   2639         }
   2640 
   2641         @Override
   2642         public long getVideoTurnedOnTime(long batteryRealtime, int which) {
   2643             if (mVideoTurnedOnTimer == null) {
   2644                 return 0;
   2645             }
   2646             return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
   2647         }
   2648 
   2649         @Override
   2650         public void noteUserActivityLocked(int type) {
   2651             if (mUserActivityCounters == null) {
   2652                 initUserActivityLocked();
   2653             }
   2654             if (type < 0) type = 0;
   2655             else if (type >= NUM_USER_ACTIVITY_TYPES) type = NUM_USER_ACTIVITY_TYPES-1;
   2656             mUserActivityCounters[type].stepAtomic();
   2657         }
   2658 
   2659         @Override
   2660         public boolean hasUserActivity() {
   2661             return mUserActivityCounters != null;
   2662         }
   2663 
   2664         @Override
   2665         public int getUserActivityCount(int type, int which) {
   2666             if (mUserActivityCounters == null) {
   2667                 return 0;
   2668             }
   2669             return mUserActivityCounters[type].getCountLocked(which);
   2670         }
   2671 
   2672         void initUserActivityLocked() {
   2673             mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
   2674             for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
   2675                 mUserActivityCounters[i] = new Counter(mUnpluggables);
   2676             }
   2677         }
   2678 
   2679         public long computeCurrentTcpBytesSent() {
   2680             final long uidTxBytes = getNetworkStatsDetailGroupedByUid().getTotal(
   2681                     null, mUid).txBytes;
   2682             return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
   2683                     ? (uidTxBytes - mStartedTcpBytesSent) : 0);
   2684         }
   2685 
   2686         /**
   2687          * Clear all stats for this uid.  Returns true if the uid is completely
   2688          * inactive so can be dropped.
   2689          */
   2690         boolean reset() {
   2691             boolean active = false;
   2692 
   2693             if (mWifiRunningTimer != null) {
   2694                 active |= !mWifiRunningTimer.reset(BatteryStatsImpl.this, false);
   2695                 active |= mWifiRunning;
   2696             }
   2697             if (mFullWifiLockTimer != null) {
   2698                 active |= !mFullWifiLockTimer.reset(BatteryStatsImpl.this, false);
   2699                 active |= mFullWifiLockOut;
   2700             }
   2701             if (mScanWifiLockTimer != null) {
   2702                 active |= !mScanWifiLockTimer.reset(BatteryStatsImpl.this, false);
   2703                 active |= mScanWifiLockOut;
   2704             }
   2705             if (mWifiMulticastTimer != null) {
   2706                 active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
   2707                 active |= mWifiMulticastEnabled;
   2708             }
   2709             if (mAudioTurnedOnTimer != null) {
   2710                 active |= !mAudioTurnedOnTimer.reset(BatteryStatsImpl.this, false);
   2711                 active |= mAudioTurnedOn;
   2712             }
   2713             if (mVideoTurnedOnTimer != null) {
   2714                 active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
   2715                 active |= mVideoTurnedOn;
   2716             }
   2717 
   2718             mLoadedTcpBytesReceived = mLoadedTcpBytesSent = 0;
   2719             mCurrentTcpBytesReceived = mCurrentTcpBytesSent = 0;
   2720 
   2721             if (mUserActivityCounters != null) {
   2722                 for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
   2723                     mUserActivityCounters[i].reset(false);
   2724                 }
   2725             }
   2726 
   2727             if (mWakelockStats.size() > 0) {
   2728                 Iterator<Map.Entry<String, Wakelock>> it = mWakelockStats.entrySet().iterator();
   2729                 while (it.hasNext()) {
   2730                     Map.Entry<String, Wakelock> wakelockEntry = it.next();
   2731                     Wakelock wl = wakelockEntry.getValue();
   2732                     if (wl.reset()) {
   2733                         it.remove();
   2734                     } else {
   2735                         active = true;
   2736                     }
   2737                 }
   2738             }
   2739             if (mSensorStats.size() > 0) {
   2740                 Iterator<Map.Entry<Integer, Sensor>> it = mSensorStats.entrySet().iterator();
   2741                 while (it.hasNext()) {
   2742                     Map.Entry<Integer, Sensor> sensorEntry = it.next();
   2743                     Sensor s = sensorEntry.getValue();
   2744                     if (s.reset()) {
   2745                         it.remove();
   2746                     } else {
   2747                         active = true;
   2748                     }
   2749                 }
   2750             }
   2751             if (mProcessStats.size() > 0) {
   2752                 Iterator<Map.Entry<String, Proc>> it = mProcessStats.entrySet().iterator();
   2753                 while (it.hasNext()) {
   2754                     Map.Entry<String, Proc> procEntry = it.next();
   2755                     procEntry.getValue().detach();
   2756                 }
   2757                 mProcessStats.clear();
   2758             }
   2759             if (mPids.size() > 0) {
   2760                 for (int i=0; !active && i<mPids.size(); i++) {
   2761                     Pid pid = mPids.valueAt(i);
   2762                     if (pid.mWakeStart != 0) {
   2763                         active = true;
   2764                     }
   2765                 }
   2766             }
   2767             if (mPackageStats.size() > 0) {
   2768                 Iterator<Map.Entry<String, Pkg>> it = mPackageStats.entrySet().iterator();
   2769                 while (it.hasNext()) {
   2770                     Map.Entry<String, Pkg> pkgEntry = it.next();
   2771                     Pkg p = pkgEntry.getValue();
   2772                     p.detach();
   2773                     if (p.mServiceStats.size() > 0) {
   2774                         Iterator<Map.Entry<String, Pkg.Serv>> it2
   2775                                 = p.mServiceStats.entrySet().iterator();
   2776                         while (it2.hasNext()) {
   2777                             Map.Entry<String, Pkg.Serv> servEntry = it2.next();
   2778                             servEntry.getValue().detach();
   2779                         }
   2780                     }
   2781                 }
   2782                 mPackageStats.clear();
   2783             }
   2784 
   2785             mPids.clear();
   2786 
   2787             if (!active) {
   2788                 if (mWifiRunningTimer != null) {
   2789                     mWifiRunningTimer.detach();
   2790                 }
   2791                 if (mFullWifiLockTimer != null) {
   2792                     mFullWifiLockTimer.detach();
   2793                 }
   2794                 if (mScanWifiLockTimer != null) {
   2795                     mScanWifiLockTimer.detach();
   2796                 }
   2797                 if (mWifiMulticastTimer != null) {
   2798                     mWifiMulticastTimer.detach();
   2799                 }
   2800                 if (mAudioTurnedOnTimer != null) {
   2801                     mAudioTurnedOnTimer.detach();
   2802                 }
   2803                 if (mVideoTurnedOnTimer != null) {
   2804                     mVideoTurnedOnTimer.detach();
   2805                 }
   2806                 if (mUserActivityCounters != null) {
   2807                     for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
   2808                         mUserActivityCounters[i].detach();
   2809                     }
   2810                 }
   2811             }
   2812 
   2813             return !active;
   2814         }
   2815 
   2816         void writeToParcelLocked(Parcel out, long batteryRealtime) {
   2817             out.writeInt(mWakelockStats.size());
   2818             for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
   2819                 out.writeString(wakelockEntry.getKey());
   2820                 Uid.Wakelock wakelock = wakelockEntry.getValue();
   2821                 wakelock.writeToParcelLocked(out, batteryRealtime);
   2822             }
   2823 
   2824             out.writeInt(mSensorStats.size());
   2825             for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
   2826                 out.writeInt(sensorEntry.getKey());
   2827                 Uid.Sensor sensor = sensorEntry.getValue();
   2828                 sensor.writeToParcelLocked(out, batteryRealtime);
   2829             }
   2830 
   2831             out.writeInt(mProcessStats.size());
   2832             for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
   2833                 out.writeString(procEntry.getKey());
   2834                 Uid.Proc proc = procEntry.getValue();
   2835                 proc.writeToParcelLocked(out);
   2836             }
   2837 
   2838             out.writeInt(mPackageStats.size());
   2839             for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
   2840                 out.writeString(pkgEntry.getKey());
   2841                 Uid.Pkg pkg = pkgEntry.getValue();
   2842                 pkg.writeToParcelLocked(out);
   2843             }
   2844 
   2845             out.writeLong(mLoadedTcpBytesReceived);
   2846             out.writeLong(mLoadedTcpBytesSent);
   2847             out.writeLong(computeCurrentTcpBytesReceived());
   2848             out.writeLong(computeCurrentTcpBytesSent());
   2849             out.writeLong(mTcpBytesReceivedAtLastUnplug);
   2850             out.writeLong(mTcpBytesSentAtLastUnplug);
   2851             if (mWifiRunningTimer != null) {
   2852                 out.writeInt(1);
   2853                 mWifiRunningTimer.writeToParcel(out, batteryRealtime);
   2854             } else {
   2855                 out.writeInt(0);
   2856             }
   2857             if (mFullWifiLockTimer != null) {
   2858                 out.writeInt(1);
   2859                 mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
   2860             } else {
   2861                 out.writeInt(0);
   2862             }
   2863             if (mScanWifiLockTimer != null) {
   2864                 out.writeInt(1);
   2865                 mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
   2866             } else {
   2867                 out.writeInt(0);
   2868             }
   2869             if (mWifiMulticastTimer != null) {
   2870                 out.writeInt(1);
   2871                 mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
   2872             } else {
   2873                 out.writeInt(0);
   2874             }
   2875             if (mAudioTurnedOnTimer != null) {
   2876                 out.writeInt(1);
   2877                 mAudioTurnedOnTimer.writeToParcel(out, batteryRealtime);
   2878             } else {
   2879                 out.writeInt(0);
   2880             }
   2881             if (mVideoTurnedOnTimer != null) {
   2882                 out.writeInt(1);
   2883                 mVideoTurnedOnTimer.writeToParcel(out, batteryRealtime);
   2884             } else {
   2885                 out.writeInt(0);
   2886             }
   2887             if (mUserActivityCounters != null) {
   2888                 out.writeInt(1);
   2889                 for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
   2890                     mUserActivityCounters[i].writeToParcel(out);
   2891                 }
   2892             } else {
   2893                 out.writeInt(0);
   2894             }
   2895         }
   2896 
   2897         void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
   2898             int numWakelocks = in.readInt();
   2899             mWakelockStats.clear();
   2900             for (int j = 0; j < numWakelocks; j++) {
   2901                 String wakelockName = in.readString();
   2902                 Uid.Wakelock wakelock = new Wakelock();
   2903                 wakelock.readFromParcelLocked(unpluggables, in);
   2904                 // We will just drop some random set of wakelocks if
   2905                 // the previous run of the system was an older version
   2906                 // that didn't impose a limit.
   2907                 mWakelockStats.put(wakelockName, wakelock);
   2908             }
   2909 
   2910             int numSensors = in.readInt();
   2911             mSensorStats.clear();
   2912             for (int k = 0; k < numSensors; k++) {
   2913                 int sensorNumber = in.readInt();
   2914                 Uid.Sensor sensor = new Sensor(sensorNumber);
   2915                 sensor.readFromParcelLocked(mUnpluggables, in);
   2916                 mSensorStats.put(sensorNumber, sensor);
   2917             }
   2918 
   2919             int numProcs = in.readInt();
   2920             mProcessStats.clear();
   2921             for (int k = 0; k < numProcs; k++) {
   2922                 String processName = in.readString();
   2923                 Uid.Proc proc = new Proc();
   2924                 proc.readFromParcelLocked(in);
   2925                 mProcessStats.put(processName, proc);
   2926             }
   2927 
   2928             int numPkgs = in.readInt();
   2929             mPackageStats.clear();
   2930             for (int l = 0; l < numPkgs; l++) {
   2931                 String packageName = in.readString();
   2932                 Uid.Pkg pkg = new Pkg();
   2933                 pkg.readFromParcelLocked(in);
   2934                 mPackageStats.put(packageName, pkg);
   2935             }
   2936 
   2937             mLoadedTcpBytesReceived = in.readLong();
   2938             mLoadedTcpBytesSent = in.readLong();
   2939             mCurrentTcpBytesReceived = in.readLong();
   2940             mCurrentTcpBytesSent = in.readLong();
   2941             mTcpBytesReceivedAtLastUnplug = in.readLong();
   2942             mTcpBytesSentAtLastUnplug = in.readLong();
   2943             mWifiRunning = false;
   2944             if (in.readInt() != 0) {
   2945                 mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
   2946                         mWifiRunningTimers, mUnpluggables, in);
   2947             } else {
   2948                 mWifiRunningTimer = null;
   2949             }
   2950             mFullWifiLockOut = false;
   2951             if (in.readInt() != 0) {
   2952                 mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
   2953                         mFullWifiLockTimers, mUnpluggables, in);
   2954             } else {
   2955                 mFullWifiLockTimer = null;
   2956             }
   2957             mScanWifiLockOut = false;
   2958             if (in.readInt() != 0) {
   2959                 mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
   2960                         mScanWifiLockTimers, mUnpluggables, in);
   2961             } else {
   2962                 mScanWifiLockTimer = null;
   2963             }
   2964             mWifiMulticastEnabled = false;
   2965             if (in.readInt() != 0) {
   2966                 mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
   2967                         mWifiMulticastTimers, mUnpluggables, in);
   2968             } else {
   2969                 mWifiMulticastTimer = null;
   2970             }
   2971             mAudioTurnedOn = false;
   2972             if (in.readInt() != 0) {
   2973                 mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
   2974                         null, mUnpluggables, in);
   2975             } else {
   2976                 mAudioTurnedOnTimer = null;
   2977             }
   2978             mVideoTurnedOn = false;
   2979             if (in.readInt() != 0) {
   2980                 mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
   2981                         null, mUnpluggables, in);
   2982             } else {
   2983                 mVideoTurnedOnTimer = null;
   2984             }
   2985             if (in.readInt() != 0) {
   2986                 mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
   2987                 for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
   2988                     mUserActivityCounters[i] = new Counter(mUnpluggables, in);
   2989                 }
   2990             } else {
   2991                 mUserActivityCounters = null;
   2992             }
   2993         }
   2994 
   2995         /**
   2996          * The statistics associated with a particular wake lock.
   2997          */
   2998         public final class Wakelock extends BatteryStats.Uid.Wakelock {
   2999             /**
   3000              * How long (in ms) this uid has been keeping the device partially awake.
   3001              */
   3002             StopwatchTimer mTimerPartial;
   3003 
   3004             /**
   3005              * How long (in ms) this uid has been keeping the device fully awake.
   3006              */
   3007             StopwatchTimer mTimerFull;
   3008 
   3009             /**
   3010              * How long (in ms) this uid has had a window keeping the device awake.
   3011              */
   3012             StopwatchTimer mTimerWindow;
   3013 
   3014             /**
   3015              * Reads a possibly null Timer from a Parcel.  The timer is associated with the
   3016              * proper timer pool from the given BatteryStatsImpl object.
   3017              *
   3018              * @param in the Parcel to be read from.
   3019              * return a new Timer, or null.
   3020              */
   3021             private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
   3022                     ArrayList<Unpluggable> unpluggables, Parcel in) {
   3023                 if (in.readInt() == 0) {
   3024                     return null;
   3025                 }
   3026 
   3027                 return new StopwatchTimer(Uid.this, type, pool, unpluggables, in);
   3028             }
   3029 
   3030             boolean reset() {
   3031                 boolean wlactive = false;
   3032                 if (mTimerFull != null) {
   3033                     wlactive |= !mTimerFull.reset(BatteryStatsImpl.this, false);
   3034                 }
   3035                 if (mTimerPartial != null) {
   3036                     wlactive |= !mTimerPartial.reset(BatteryStatsImpl.this, false);
   3037                 }
   3038                 if (mTimerWindow != null) {
   3039                     wlactive |= !mTimerWindow.reset(BatteryStatsImpl.this, false);
   3040                 }
   3041                 if (!wlactive) {
   3042                     if (mTimerFull != null) {
   3043                         mTimerFull.detach();
   3044                         mTimerFull = null;
   3045                     }
   3046                     if (mTimerPartial != null) {
   3047                         mTimerPartial.detach();
   3048                         mTimerPartial = null;
   3049                     }
   3050                     if (mTimerWindow != null) {
   3051                         mTimerWindow.detach();
   3052                         mTimerWindow = null;
   3053                     }
   3054                 }
   3055                 return !wlactive;
   3056             }
   3057 
   3058             void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
   3059                 mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
   3060                         mPartialTimers, unpluggables, in);
   3061                 mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
   3062                         mFullTimers, unpluggables, in);
   3063                 mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
   3064                         mWindowTimers, unpluggables, in);
   3065             }
   3066 
   3067             void writeToParcelLocked(Parcel out, long batteryRealtime) {
   3068                 Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
   3069                 Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
   3070                 Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
   3071             }
   3072 
   3073             @Override
   3074             public Timer getWakeTime(int type) {
   3075                 switch (type) {
   3076                 case WAKE_TYPE_FULL: return mTimerFull;
   3077                 case WAKE_TYPE_PARTIAL: return mTimerPartial;
   3078                 case WAKE_TYPE_WINDOW: return mTimerWindow;
   3079                 default: throw new IllegalArgumentException("type = " + type);
   3080                 }
   3081             }
   3082         }
   3083 
   3084         public final class Sensor extends BatteryStats.Uid.Sensor {
   3085             final int mHandle;
   3086             StopwatchTimer mTimer;
   3087 
   3088             public Sensor(int handle) {
   3089                 mHandle = handle;
   3090             }
   3091 
   3092             private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
   3093                     Parcel in) {
   3094                 if (in.readInt() == 0) {
   3095                     return null;
   3096                 }
   3097 
   3098                 ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
   3099                 if (pool == null) {
   3100                     pool = new ArrayList<StopwatchTimer>();
   3101                     mSensorTimers.put(mHandle, pool);
   3102                 }
   3103                 return new StopwatchTimer(Uid.this, 0, pool, unpluggables, in);
   3104             }
   3105 
   3106             boolean reset() {
   3107                 if (mTimer.reset(BatteryStatsImpl.this, true)) {
   3108                     mTimer = null;
   3109                     return true;
   3110                 }
   3111                 return false;
   3112             }
   3113 
   3114             void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
   3115                 mTimer = readTimerFromParcel(unpluggables, in);
   3116             }
   3117 
   3118             void writeToParcelLocked(Parcel out, long batteryRealtime) {
   3119                 Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
   3120             }
   3121 
   3122             @Override
   3123             public Timer getSensorTime() {
   3124                 return mTimer;
   3125             }
   3126 
   3127             @Override
   3128             public int getHandle() {
   3129                 return mHandle;
   3130             }
   3131         }
   3132 
   3133         /**
   3134          * The statistics associated with a particular process.
   3135          */
   3136         public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
   3137             /**
   3138              * Total time (in 1/100 sec) spent executing in user code.
   3139              */
   3140             long mUserTime;
   3141 
   3142             /**
   3143              * Total time (in 1/100 sec) spent executing in kernel code.
   3144              */
   3145             long mSystemTime;
   3146 
   3147             /**
   3148              * Number of times the process has been started.
   3149              */
   3150             int mStarts;
   3151 
   3152             /**
   3153              * Amount of time the process was running in the foreground.
   3154              */
   3155             long mForegroundTime;
   3156 
   3157             /**
   3158              * The amount of user time loaded from a previous save.
   3159              */
   3160             long mLoadedUserTime;
   3161 
   3162             /**
   3163              * The amount of system time loaded from a previous save.
   3164              */
   3165             long mLoadedSystemTime;
   3166 
   3167             /**
   3168              * The number of times the process has started from a previous save.
   3169              */
   3170             int mLoadedStarts;
   3171 
   3172             /**
   3173              * The amount of foreground time loaded from a previous save.
   3174              */
   3175             long mLoadedForegroundTime;
   3176 
   3177             /**
   3178              * The amount of user time loaded from the previous run.
   3179              */
   3180             long mLastUserTime;
   3181 
   3182             /**
   3183              * The amount of system time loaded from the previous run.
   3184              */
   3185             long mLastSystemTime;
   3186 
   3187             /**
   3188              * The number of times the process has started from the previous run.
   3189              */
   3190             int mLastStarts;
   3191 
   3192             /**
   3193              * The amount of foreground time loaded from the previous run
   3194              */
   3195             long mLastForegroundTime;
   3196 
   3197             /**
   3198              * The amount of user time when last unplugged.
   3199              */
   3200             long mUnpluggedUserTime;
   3201 
   3202             /**
   3203              * The amount of system time when last unplugged.
   3204              */
   3205             long mUnpluggedSystemTime;
   3206 
   3207             /**
   3208              * The number of times the process has started before unplugged.
   3209              */
   3210             int mUnpluggedStarts;
   3211 
   3212             /**
   3213              * The amount of foreground time since unplugged.
   3214              */
   3215             long mUnpluggedForegroundTime;
   3216 
   3217             SamplingCounter[] mSpeedBins;
   3218 
   3219             ArrayList<ExcessivePower> mExcessivePower;
   3220 
   3221             Proc() {
   3222                 mUnpluggables.add(this);
   3223                 mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
   3224             }
   3225 
   3226             public void unplug(long batteryUptime, long batteryRealtime) {
   3227                 mUnpluggedUserTime = mUserTime;
   3228                 mUnpluggedSystemTime = mSystemTime;
   3229                 mUnpluggedStarts = mStarts;
   3230                 mUnpluggedForegroundTime = mForegroundTime;
   3231             }
   3232 
   3233             public void plug(long batteryUptime, long batteryRealtime) {
   3234             }
   3235 
   3236             void detach() {
   3237                 mUnpluggables.remove(this);
   3238                 for (int i = 0; i < mSpeedBins.length; i++) {
   3239                     SamplingCounter c = mSpeedBins[i];
   3240                     if (c != null) {
   3241                         mUnpluggables.remove(c);
   3242                         mSpeedBins[i] = null;
   3243                     }
   3244                 }
   3245             }
   3246 
   3247             public int countExcessivePowers() {
   3248                 return mExcessivePower != null ? mExcessivePower.size() : 0;
   3249             }
   3250 
   3251             public ExcessivePower getExcessivePower(int i) {
   3252                 if (mExcessivePower != null) {
   3253                     return mExcessivePower.get(i);
   3254                 }
   3255                 return null;
   3256             }
   3257 
   3258             public void addExcessiveWake(long overTime, long usedTime) {
   3259                 if (mExcessivePower == null) {
   3260                     mExcessivePower = new ArrayList<ExcessivePower>();
   3261                 }
   3262                 ExcessivePower ew = new ExcessivePower();
   3263                 ew.type = ExcessivePower.TYPE_WAKE;
   3264                 ew.overTime = overTime;
   3265                 ew.usedTime = usedTime;
   3266                 mExcessivePower.add(ew);
   3267             }
   3268 
   3269             public void addExcessiveCpu(long overTime, long usedTime) {
   3270                 if (mExcessivePower == null) {
   3271                     mExcessivePower = new ArrayList<ExcessivePower>();
   3272                 }
   3273                 ExcessivePower ew = new ExcessivePower();
   3274                 ew.type = ExcessivePower.TYPE_CPU;
   3275                 ew.overTime = overTime;
   3276                 ew.usedTime = usedTime;
   3277                 mExcessivePower.add(ew);
   3278             }
   3279 
   3280             void writeExcessivePowerToParcelLocked(Parcel out) {
   3281                 if (mExcessivePower == null) {
   3282                     out.writeInt(0);
   3283                     return;
   3284                 }
   3285 
   3286                 final int N = mExcessivePower.size();
   3287                 out.writeInt(N);
   3288                 for (int i=0; i<N; i++) {
   3289                     ExcessivePower ew = mExcessivePower.get(i);
   3290                     out.writeInt(ew.type);
   3291                     out.writeLong(ew.overTime);
   3292                     out.writeLong(ew.usedTime);
   3293                 }
   3294             }
   3295 
   3296             boolean readExcessivePowerFromParcelLocked(Parcel in) {
   3297                 final int N = in.readInt();
   3298                 if (N == 0) {
   3299                     mExcessivePower = null;
   3300                     return true;
   3301                 }
   3302 
   3303                 if (N > 10000) {
   3304                     Slog.w(TAG, "File corrupt: too many excessive power entries " + N);
   3305                     return false;
   3306                 }
   3307 
   3308                 mExcessivePower = new ArrayList<ExcessivePower>();
   3309                 for (int i=0; i<N; i++) {
   3310                     ExcessivePower ew = new ExcessivePower();
   3311                     ew.type = in.readInt();
   3312                     ew.overTime = in.readLong();
   3313                     ew.usedTime = in.readLong();
   3314                     mExcessivePower.add(ew);
   3315                 }
   3316                 return true;
   3317             }
   3318 
   3319             void writeToParcelLocked(Parcel out) {
   3320                 out.writeLong(mUserTime);
   3321                 out.writeLong(mSystemTime);
   3322                 out.writeLong(mForegroundTime);
   3323                 out.writeInt(mStarts);
   3324                 out.writeLong(mLoadedUserTime);
   3325                 out.writeLong(mLoadedSystemTime);
   3326                 out.writeLong(mLoadedForegroundTime);
   3327                 out.writeInt(mLoadedStarts);
   3328                 out.writeLong(mUnpluggedUserTime);
   3329                 out.writeLong(mUnpluggedSystemTime);
   3330                 out.writeLong(mUnpluggedForegroundTime);
   3331                 out.writeInt(mUnpluggedStarts);
   3332 
   3333                 out.writeInt(mSpeedBins.length);
   3334                 for (int i = 0; i < mSpeedBins.length; i++) {
   3335                     SamplingCounter c = mSpeedBins[i];
   3336                     if (c != null) {
   3337                         out.writeInt(1);
   3338                         c.writeToParcel(out);
   3339                     } else {
   3340                         out.writeInt(0);
   3341                     }
   3342                 }
   3343 
   3344                 writeExcessivePowerToParcelLocked(out);
   3345             }
   3346 
   3347             void readFromParcelLocked(Parcel in) {
   3348                 mUserTime = in.readLong();
   3349                 mSystemTime = in.readLong();
   3350                 mForegroundTime = in.readLong();
   3351                 mStarts = in.readInt();
   3352                 mLoadedUserTime = in.readLong();
   3353                 mLoadedSystemTime = in.readLong();
   3354                 mLoadedForegroundTime = in.readLong();
   3355                 mLoadedStarts = in.readInt();
   3356                 mLastUserTime = 0;
   3357                 mLastSystemTime = 0;
   3358                 mLastForegroundTime = 0;
   3359                 mLastStarts = 0;
   3360                 mUnpluggedUserTime = in.readLong();
   3361                 mUnpluggedSystemTime = in.readLong();
   3362                 mUnpluggedForegroundTime = in.readLong();
   3363                 mUnpluggedStarts = in.readInt();
   3364 
   3365                 int bins = in.readInt();
   3366                 int steps = getCpuSpeedSteps();
   3367                 mSpeedBins = new SamplingCounter[bins >= steps ? bins : steps];
   3368                 for (int i = 0; i < bins; i++) {
   3369                     if (in.readInt() != 0) {
   3370                         mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
   3371                     }
   3372                 }
   3373 
   3374                 readExcessivePowerFromParcelLocked(in);
   3375             }
   3376 
   3377             public BatteryStatsImpl getBatteryStats() {
   3378                 return BatteryStatsImpl.this;
   3379             }
   3380 
   3381             public void addCpuTimeLocked(int utime, int stime) {
   3382                 mUserTime += utime;
   3383                 mSystemTime += stime;
   3384             }
   3385 
   3386             public void addForegroundTimeLocked(long ttime) {
   3387                 mForegroundTime += ttime;
   3388             }
   3389 
   3390             public void incStartsLocked() {
   3391                 mStarts++;
   3392             }
   3393 
   3394             @Override
   3395             public long getUserTime(int which) {
   3396                 long val;
   3397                 if (which == STATS_LAST) {
   3398                     val = mLastUserTime;
   3399                 } else {
   3400                     val = mUserTime;
   3401                     if (which == STATS_CURRENT) {
   3402                         val -= mLoadedUserTime;
   3403                     } else if (which == STATS_SINCE_UNPLUGGED) {
   3404                         val -= mUnpluggedUserTime;
   3405                     }
   3406                 }
   3407                 return val;
   3408             }
   3409 
   3410             @Override
   3411             public long getSystemTime(int which) {
   3412                 long val;
   3413                 if (which == STATS_LAST) {
   3414                     val = mLastSystemTime;
   3415                 } else {
   3416                     val = mSystemTime;
   3417                     if (which == STATS_CURRENT) {
   3418                         val -= mLoadedSystemTime;
   3419                     } else if (which == STATS_SINCE_UNPLUGGED) {
   3420                         val -= mUnpluggedSystemTime;
   3421                     }
   3422                 }
   3423                 return val;
   3424             }
   3425 
   3426             @Override
   3427             public long getForegroundTime(int which) {
   3428                 long val;
   3429                 if (which == STATS_LAST) {
   3430                     val = mLastForegroundTime;
   3431                 } else {
   3432                     val = mForegroundTime;
   3433                     if (which == STATS_CURRENT) {
   3434                         val -= mLoadedForegroundTime;
   3435                     } else if (which == STATS_SINCE_UNPLUGGED) {
   3436                         val -= mUnpluggedForegroundTime;
   3437                     }
   3438                 }
   3439                 return val;
   3440             }
   3441 
   3442             @Override
   3443             public int getStarts(int which) {
   3444                 int val;
   3445                 if (which == STATS_LAST) {
   3446                     val = mLastStarts;
   3447                 } else {
   3448                     val = mStarts;
   3449                     if (which == STATS_CURRENT) {
   3450                         val -= mLoadedStarts;
   3451                     } else if (which == STATS_SINCE_UNPLUGGED) {
   3452                         val -= mUnpluggedStarts;
   3453                     }
   3454                 }
   3455                 return val;
   3456             }
   3457 
   3458             /* Called by ActivityManagerService when CPU times are updated. */
   3459             public void addSpeedStepTimes(long[] values) {
   3460                 for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
   3461                     long amt = values[i];
   3462                     if (amt != 0) {
   3463                         SamplingCounter c = mSpeedBins[i];
   3464                         if (c == null) {
   3465                             mSpeedBins[i] = c = new SamplingCounter(mUnpluggables);
   3466                         }
   3467                         c.addCountAtomic(values[i]);
   3468                     }
   3469                 }
   3470             }
   3471 
   3472             @Override
   3473             public long getTimeAtCpuSpeedStep(int speedStep, int which) {
   3474                 if (speedStep < mSpeedBins.length) {
   3475                     SamplingCounter c = mSpeedBins[speedStep];
   3476                     return c != null ? c.getCountLocked(which) : 0;
   3477                 } else {
   3478                     return 0;
   3479                 }
   3480             }
   3481         }
   3482 
   3483         /**
   3484          * The statistics associated with a particular package.
   3485          */
   3486         public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
   3487             /**
   3488              * Number of times this package has done something that could wake up the
   3489              * device from sleep.
   3490              */
   3491             int mWakeups;
   3492 
   3493             /**
   3494              * Number of things that could wake up the device loaded from a
   3495              * previous save.
   3496              */
   3497             int mLoadedWakeups;
   3498 
   3499             /**
   3500              * Number of things that could wake up the device as of the
   3501              * last run.
   3502              */
   3503             int mLastWakeups;
   3504 
   3505             /**
   3506              * Number of things that could wake up the device as of the
   3507              * last run.
   3508              */
   3509             int mUnpluggedWakeups;
   3510 
   3511             /**
   3512              * The statics we have collected for this package's services.
   3513              */
   3514             final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
   3515 
   3516             Pkg() {
   3517                 mUnpluggables.add(this);
   3518             }
   3519 
   3520             public void unplug(long batteryUptime, long batteryRealtime) {
   3521                 mUnpluggedWakeups = mWakeups;
   3522             }
   3523 
   3524             public void plug(long batteryUptime, long batteryRealtime) {
   3525             }
   3526 
   3527             void detach() {
   3528                 mUnpluggables.remove(this);
   3529             }
   3530 
   3531             void readFromParcelLocked(Parcel in) {
   3532                 mWakeups = in.readInt();
   3533                 mLoadedWakeups = in.readInt();
   3534                 mLastWakeups = 0;
   3535                 mUnpluggedWakeups = in.readInt();
   3536 
   3537                 int numServs = in.readInt();
   3538                 mServiceStats.clear();
   3539                 for (int m = 0; m < numServs; m++) {
   3540                     String serviceName = in.readString();
   3541                     Uid.Pkg.Serv serv = new Serv();
   3542                     mServiceStats.put(serviceName, serv);
   3543 
   3544                     serv.readFromParcelLocked(in);
   3545                 }
   3546             }
   3547 
   3548             void writeToParcelLocked(Parcel out) {
   3549                 out.writeInt(mWakeups);
   3550                 out.writeInt(mLoadedWakeups);
   3551                 out.writeInt(mUnpluggedWakeups);
   3552 
   3553                 out.writeInt(mServiceStats.size());
   3554                 for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
   3555                     out.writeString(servEntry.getKey());
   3556                     Uid.Pkg.Serv serv = servEntry.getValue();
   3557 
   3558                     serv.writeToParcelLocked(out);
   3559                 }
   3560             }
   3561 
   3562             @Override
   3563             public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
   3564                 return mServiceStats;
   3565             }
   3566 
   3567             @Override
   3568             public int getWakeups(int which) {
   3569                 int val;
   3570                 if (which == STATS_LAST) {
   3571                     val = mLastWakeups;
   3572                 } else {
   3573                     val = mWakeups;
   3574                     if (which == STATS_CURRENT) {
   3575                         val -= mLoadedWakeups;
   3576                     } else if (which == STATS_SINCE_UNPLUGGED) {
   3577                         val -= mUnpluggedWakeups;
   3578                     }
   3579                 }
   3580 
   3581                 return val;
   3582             }
   3583 
   3584             /**
   3585              * The statistics associated with a particular service.
   3586              */
   3587             public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
   3588                 /**
   3589                  * Total time (ms in battery uptime) the service has been left started.
   3590                  */
   3591                 long mStartTime;
   3592 
   3593                 /**
   3594                  * If service has been started and not yet stopped, this is
   3595                  * when it was started.
   3596                  */
   3597                 long mRunningSince;
   3598 
   3599                 /**
   3600                  * True if we are currently running.
   3601                  */
   3602                 boolean mRunning;
   3603 
   3604                 /**
   3605                  * Total number of times startService() has been called.
   3606                  */
   3607                 int mStarts;
   3608 
   3609                 /**
   3610                  * Total time (ms in battery uptime) the service has been left launched.
   3611                  */
   3612                 long mLaunchedTime;
   3613 
   3614                 /**
   3615                  * If service has been launched and not yet exited, this is
   3616                  * when it was launched (ms in battery uptime).
   3617                  */
   3618                 long mLaunchedSince;
   3619 
   3620                 /**
   3621                  * True if we are currently launched.
   3622                  */
   3623                 boolean mLaunched;
   3624 
   3625                 /**
   3626                  * Total number times the service has been launched.
   3627                  */
   3628                 int mLaunches;
   3629 
   3630                 /**
   3631                  * The amount of time spent started loaded from a previous save
   3632                  * (ms in battery uptime).
   3633                  */
   3634                 long mLoadedStartTime;
   3635 
   3636                 /**
   3637                  * The number of starts loaded from a previous save.
   3638                  */
   3639                 int mLoadedStarts;
   3640 
   3641                 /**
   3642                  * The number of launches loaded from a previous save.
   3643                  */
   3644                 int mLoadedLaunches;
   3645 
   3646                 /**
   3647                  * The amount of time spent started as of the last run (ms
   3648                  * in battery uptime).
   3649                  */
   3650                 long mLastStartTime;
   3651 
   3652                 /**
   3653                  * The number of starts as of the last run.
   3654                  */
   3655                 int mLastStarts;
   3656 
   3657                 /**
   3658                  * The number of launches as of the last run.
   3659                  */
   3660                 int mLastLaunches;
   3661 
   3662                 /**
   3663                  * The amount of time spent started when last unplugged (ms
   3664                  * in battery uptime).
   3665                  */
   3666                 long mUnpluggedStartTime;
   3667 
   3668                 /**
   3669                  * The number of starts when last unplugged.
   3670                  */
   3671                 int mUnpluggedStarts;
   3672 
   3673                 /**
   3674                  * The number of launches when last unplugged.
   3675                  */
   3676                 int mUnpluggedLaunches;
   3677 
   3678                 Serv() {
   3679                     mUnpluggables.add(this);
   3680                 }
   3681 
   3682                 public void unplug(long batteryUptime, long batteryRealtime) {
   3683                     mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
   3684                     mUnpluggedStarts = mStarts;
   3685                     mUnpluggedLaunches = mLaunches;
   3686                 }
   3687 
   3688                 public void plug(long batteryUptime, long batteryRealtime) {
   3689                 }
   3690 
   3691                 void detach() {
   3692                     mUnpluggables.remove(this);
   3693                 }
   3694 
   3695                 void readFromParcelLocked(Parcel in) {
   3696                     mStartTime = in.readLong();
   3697                     mRunningSince = in.readLong();
   3698                     mRunning = in.readInt() != 0;
   3699                     mStarts = in.readInt();
   3700                     mLaunchedTime = in.readLong();
   3701                     mLaunchedSince = in.readLong();
   3702                     mLaunched = in.readInt() != 0;
   3703                     mLaunches = in.readInt();
   3704                     mLoadedStartTime = in.readLong();
   3705                     mLoadedStarts = in.readInt();
   3706                     mLoadedLaunches = in.readInt();
   3707                     mLastStartTime = 0;
   3708                     mLastStarts = 0;
   3709                     mLastLaunches = 0;
   3710                     mUnpluggedStartTime = in.readLong();
   3711                     mUnpluggedStarts = in.readInt();
   3712                     mUnpluggedLaunches = in.readInt();
   3713                 }
   3714 
   3715                 void writeToParcelLocked(Parcel out) {
   3716                     out.writeLong(mStartTime);
   3717                     out.writeLong(mRunningSince);
   3718                     out.writeInt(mRunning ? 1 : 0);
   3719                     out.writeInt(mStarts);
   3720                     out.writeLong(mLaunchedTime);
   3721                     out.writeLong(mLaunchedSince);
   3722                     out.writeInt(mLaunched ? 1 : 0);
   3723                     out.writeInt(mLaunches);
   3724                     out.writeLong(mLoadedStartTime);
   3725                     out.writeInt(mLoadedStarts);
   3726                     out.writeInt(mLoadedLaunches);
   3727                     out.writeLong(mUnpluggedStartTime);
   3728                     out.writeInt(mUnpluggedStarts);
   3729                     out.writeInt(mUnpluggedLaunches);
   3730                 }
   3731 
   3732                 long getLaunchTimeToNowLocked(long batteryUptime) {
   3733                     if (!mLaunched) return mLaunchedTime;
   3734                     return mLaunchedTime + batteryUptime - mLaunchedSince;
   3735                 }
   3736 
   3737                 long getStartTimeToNowLocked(long batteryUptime) {
   3738                     if (!mRunning) return mStartTime;
   3739                     return mStartTime + batteryUptime - mRunningSince;
   3740                 }
   3741 
   3742                 public void startLaunchedLocked() {
   3743                     if (!mLaunched) {
   3744                         mLaunches++;
   3745                         mLaunchedSince = getBatteryUptimeLocked();
   3746                         mLaunched = true;
   3747                     }
   3748                 }
   3749 
   3750                 public void stopLaunchedLocked() {
   3751                     if (mLaunched) {
   3752                         long time = getBatteryUptimeLocked() - mLaunchedSince;
   3753                         if (time > 0) {
   3754                             mLaunchedTime += time;
   3755                         } else {
   3756                             mLaunches--;
   3757                         }
   3758                         mLaunched = false;
   3759                     }
   3760                 }
   3761 
   3762                 public void startRunningLocked() {
   3763                     if (!mRunning) {
   3764                         mStarts++;
   3765                         mRunningSince = getBatteryUptimeLocked();
   3766                         mRunning = true;
   3767                     }
   3768                 }
   3769 
   3770                 public void stopRunningLocked() {
   3771                     if (mRunning) {
   3772                         long time = getBatteryUptimeLocked() - mRunningSince;
   3773                         if (time > 0) {
   3774                             mStartTime += time;
   3775                         } else {
   3776                             mStarts--;
   3777                         }
   3778                         mRunning = false;
   3779                     }
   3780                 }
   3781 
   3782                 public BatteryStatsImpl getBatteryStats() {
   3783                     return BatteryStatsImpl.this;
   3784                 }
   3785 
   3786                 @Override
   3787                 public int getLaunches(int which) {
   3788                     int val;
   3789 
   3790                     if (which == STATS_LAST) {
   3791                         val = mLastLaunches;
   3792                     } else {
   3793                         val = mLaunches;
   3794                         if (which == STATS_CURRENT) {
   3795                             val -= mLoadedLaunches;
   3796                         } else if (which == STATS_SINCE_UNPLUGGED) {
   3797                             val -= mUnpluggedLaunches;
   3798                         }
   3799                     }
   3800 
   3801                     return val;
   3802                 }
   3803 
   3804                 @Override
   3805                 public long getStartTime(long now, int which) {
   3806                     long val;
   3807                     if (which == STATS_LAST) {
   3808                         val = mLastStartTime;
   3809                     } else {
   3810                         val = getStartTimeToNowLocked(now);
   3811                         if (which == STATS_CURRENT) {
   3812                             val -= mLoadedStartTime;
   3813                         } else if (which == STATS_SINCE_UNPLUGGED) {
   3814                             val -= mUnpluggedStartTime;
   3815                         }
   3816                     }
   3817 
   3818                     return val;
   3819                 }
   3820 
   3821                 @Override
   3822                 public int getStarts(int which) {
   3823                     int val;
   3824                     if (which == STATS_LAST) {
   3825                         val = mLastStarts;
   3826                     } else {
   3827                         val = mStarts;
   3828                         if (which == STATS_CURRENT) {
   3829                             val -= mLoadedStarts;
   3830                         } else if (which == STATS_SINCE_UNPLUGGED) {
   3831                             val -= mUnpluggedStarts;
   3832                         }
   3833                     }
   3834 
   3835                     return val;
   3836                 }
   3837             }
   3838 
   3839             public BatteryStatsImpl getBatteryStats() {
   3840                 return BatteryStatsImpl.this;
   3841             }
   3842 
   3843             public void incWakeupsLocked() {
   3844                 mWakeups++;
   3845             }
   3846 
   3847             final Serv newServiceStatsLocked() {
   3848                 return new Serv();
   3849             }
   3850         }
   3851 
   3852         /**
   3853          * Retrieve the statistics object for a particular process, creating
   3854          * if needed.
   3855          */
   3856         public Proc getProcessStatsLocked(String name) {
   3857             Proc ps = mProcessStats.get(name);
   3858             if (ps == null) {
   3859                 ps = new Proc();
   3860                 mProcessStats.put(name, ps);
   3861             }
   3862 
   3863             return ps;
   3864         }
   3865 
   3866         public SparseArray<? extends Pid> getPidStats() {
   3867             return mPids;
   3868         }
   3869 
   3870         public Pid getPidStatsLocked(int pid) {
   3871             Pid p = mPids.get(pid);
   3872             if (p == null) {
   3873                 p = new Pid();
   3874                 mPids.put(pid, p);
   3875             }
   3876             return p;
   3877         }
   3878 
   3879         /**
   3880          * Retrieve the statistics object for a particular service, creating
   3881          * if needed.
   3882          */
   3883         public Pkg getPackageStatsLocked(String name) {
   3884             Pkg ps = mPackageStats.get(name);
   3885             if (ps == null) {
   3886                 ps = new Pkg();
   3887                 mPackageStats.put(name, ps);
   3888             }
   3889 
   3890             return ps;
   3891         }
   3892 
   3893         /**
   3894          * Retrieve the statistics object for a particular service, creating
   3895          * if needed.
   3896          */
   3897         public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
   3898             Pkg ps = getPackageStatsLocked(pkg);
   3899             Pkg.Serv ss = ps.mServiceStats.get(serv);
   3900             if (ss == null) {
   3901                 ss = ps.newServiceStatsLocked();
   3902                 ps.mServiceStats.put(serv, ss);
   3903             }
   3904 
   3905             return ss;
   3906         }
   3907 
   3908         public StopwatchTimer getWakeTimerLocked(String name, int type) {
   3909             Wakelock wl = mWakelockStats.get(name);
   3910             if (wl == null) {
   3911                 final int N = mWakelockStats.size();
   3912                 if (N > MAX_WAKELOCKS_PER_UID && (mUid != Process.SYSTEM_UID
   3913                         || N > MAX_WAKELOCKS_PER_UID_IN_SYSTEM)) {
   3914                     name = BATCHED_WAKELOCK_NAME;
   3915                     wl = mWakelockStats.get(name);
   3916                 }
   3917                 if (wl == null) {
   3918                     wl = new Wakelock();
   3919                     mWakelockStats.put(name, wl);
   3920                 }
   3921             }
   3922             StopwatchTimer t = null;
   3923             switch (type) {
   3924                 case WAKE_TYPE_PARTIAL:
   3925                     t = wl.mTimerPartial;
   3926                     if (t == null) {
   3927                         t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
   3928                                 mPartialTimers, mUnpluggables);
   3929                         wl.mTimerPartial = t;
   3930                     }
   3931                     return t;
   3932                 case WAKE_TYPE_FULL:
   3933                     t = wl.mTimerFull;
   3934                     if (t == null) {
   3935                         t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
   3936                                 mFullTimers, mUnpluggables);
   3937                         wl.mTimerFull = t;
   3938                     }
   3939                     return t;
   3940                 case WAKE_TYPE_WINDOW:
   3941                     t = wl.mTimerWindow;
   3942                     if (t == null) {
   3943                         t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
   3944                                 mWindowTimers, mUnpluggables);
   3945                         wl.mTimerWindow = t;
   3946                     }
   3947                     return t;
   3948                 default:
   3949                     throw new IllegalArgumentException("type=" + type);
   3950             }
   3951         }
   3952 
   3953         public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
   3954             Sensor se = mSensorStats.get(sensor);
   3955             if (se == null) {
   3956                 if (!create) {
   3957                     return null;
   3958                 }
   3959                 se = new Sensor(sensor);
   3960                 mSensorStats.put(sensor, se);
   3961             }
   3962             StopwatchTimer t = se.mTimer;
   3963             if (t != null) {
   3964                 return t;
   3965             }
   3966             ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
   3967             if (timers == null) {
   3968                 timers = new ArrayList<StopwatchTimer>();
   3969                 mSensorTimers.put(sensor, timers);
   3970             }
   3971             t = new StopwatchTimer(Uid.this, BatteryStats.SENSOR, timers, mUnpluggables);
   3972             se.mTimer = t;
   3973             return t;
   3974         }
   3975 
   3976         public void noteStartWakeLocked(int pid, String name, int type) {
   3977             StopwatchTimer t = getWakeTimerLocked(name, type);
   3978             if (t != null) {
   3979                 t.startRunningLocked(BatteryStatsImpl.this);
   3980             }
   3981             if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
   3982                 Pid p = getPidStatsLocked(pid);
   3983                 if (p.mWakeStart == 0) {
   3984                     p.mWakeStart = SystemClock.elapsedRealtime();
   3985                 }
   3986             }
   3987         }
   3988 
   3989         public void noteStopWakeLocked(int pid, String name, int type) {
   3990             StopwatchTimer t = getWakeTimerLocked(name, type);
   3991             if (t != null) {
   3992                 t.stopRunningLocked(BatteryStatsImpl.this);
   3993             }
   3994             if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
   3995                 Pid p = mPids.get(pid);
   3996                 if (p != null && p.mWakeStart != 0) {
   3997                     p.mWakeSum += SystemClock.elapsedRealtime() - p.mWakeStart;
   3998                     p.mWakeStart = 0;
   3999                 }
   4000             }
   4001         }
   4002 
   4003         public void reportExcessiveWakeLocked(String proc, long overTime, long usedTime) {
   4004             Proc p = getProcessStatsLocked(proc);
   4005             if (p != null) {
   4006                 p.addExcessiveWake(overTime, usedTime);
   4007             }
   4008         }
   4009 
   4010         public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) {
   4011             Proc p = getProcessStatsLocked(proc);
   4012             if (p != null) {
   4013                 p.addExcessiveCpu(overTime, usedTime);
   4014             }
   4015         }
   4016 
   4017         public void noteStartSensor(int sensor) {
   4018             StopwatchTimer t = getSensorTimerLocked(sensor, true);
   4019             if (t != null) {
   4020                 t.startRunningLocked(BatteryStatsImpl.this);
   4021             }
   4022         }
   4023 
   4024         public void noteStopSensor(int sensor) {
   4025             // Don't create a timer if one doesn't already exist
   4026             StopwatchTimer t = getSensorTimerLocked(sensor, false);
   4027             if (t != null) {
   4028                 t.stopRunningLocked(BatteryStatsImpl.this);
   4029             }
   4030         }
   4031 
   4032         public void noteStartGps() {
   4033             StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
   4034             if (t != null) {
   4035                 t.startRunningLocked(BatteryStatsImpl.this);
   4036             }
   4037         }
   4038 
   4039         public void noteStopGps() {
   4040             StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
   4041             if (t != null) {
   4042                 t.stopRunningLocked(BatteryStatsImpl.this);
   4043             }
   4044         }
   4045 
   4046         public BatteryStatsImpl getBatteryStats() {
   4047             return BatteryStatsImpl.this;
   4048         }
   4049     }
   4050 
   4051     public BatteryStatsImpl(String filename) {
   4052         mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
   4053         mHandler = new MyHandler();
   4054         mStartCount++;
   4055         mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables);
   4056         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
   4057             mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mUnpluggables);
   4058         }
   4059         mInputEventCounter = new Counter(mUnpluggables);
   4060         mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables);
   4061         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
   4062             mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null, mUnpluggables);
   4063         }
   4064         mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables);
   4065         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
   4066             mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null, mUnpluggables);
   4067         }
   4068         mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables);
   4069         mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
   4070         mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables);
   4071         mAudioOnTimer = new StopwatchTimer(null, -6, null, mUnpluggables);
   4072         mVideoOnTimer = new StopwatchTimer(null, -7, null, mUnpluggables);
   4073         mOnBattery = mOnBatteryInternal = false;
   4074         initTimes();
   4075         mTrackBatteryPastUptime = 0;
   4076         mTrackBatteryPastRealtime = 0;
   4077         mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
   4078         mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
   4079         mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
   4080         mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
   4081         mDischargeStartLevel = 0;
   4082         mDischargeUnplugLevel = 0;
   4083         mDischargeCurrentLevel = 0;
   4084         initDischarge();
   4085         clearHistoryLocked();
   4086     }
   4087 
   4088     public BatteryStatsImpl(Parcel p) {
   4089         mFile = null;
   4090         mHandler = null;
   4091         clearHistoryLocked();
   4092         readFromParcel(p);
   4093     }
   4094 
   4095     public void setCallback(BatteryCallback cb) {
   4096         mCallback = cb;
   4097     }
   4098 
   4099     public void setNumSpeedSteps(int steps) {
   4100         if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
   4101     }
   4102 
   4103     public void setRadioScanningTimeout(long timeout) {
   4104         if (mPhoneSignalScanningTimer != null) {
   4105             mPhoneSignalScanningTimer.setTimeout(timeout);
   4106         }
   4107     }
   4108 
   4109     @Override
   4110     public boolean startIteratingOldHistoryLocked() {
   4111         if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
   4112                 + " pos=" + mHistoryBuffer.dataPosition());
   4113         mHistoryBuffer.setDataPosition(0);
   4114         mHistoryReadTmp.clear();
   4115         mReadOverflow = false;
   4116         mIteratingHistory = true;
   4117         return (mHistoryIterator = mHistory) != null;
   4118     }
   4119 
   4120     @Override
   4121     public boolean getNextOldHistoryLocked(HistoryItem out) {
   4122         boolean end = mHistoryBuffer.dataPosition() >= mHistoryBuffer.dataSize();
   4123         if (!end) {
   4124             mHistoryReadTmp.readDelta(mHistoryBuffer);
   4125             mReadOverflow |= mHistoryReadTmp.cmd == HistoryItem.CMD_OVERFLOW;
   4126         }
   4127         HistoryItem cur = mHistoryIterator;
   4128         if (cur == null) {
   4129             if (!mReadOverflow && !end) {
   4130                 Slog.w(TAG, "Old history ends before new history!");
   4131             }
   4132             return false;
   4133         }
   4134         out.setTo(cur);
   4135         mHistoryIterator = cur.next;
   4136         if (!mReadOverflow) {
   4137             if (end) {
   4138                 Slog.w(TAG, "New history ends before old history!");
   4139             } else if (!out.same(mHistoryReadTmp)) {
   4140                 long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
   4141                 PrintWriter pw = new PrintWriter(new LogWriter(android.util.Log.WARN, TAG));
   4142                 pw.println("Histories differ!");
   4143                 pw.println("Old history:");
   4144                 (new HistoryPrinter()).printNextItem(pw, out, now);
   4145                 pw.println("New history:");
   4146                 (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, now);
   4147             }
   4148         }
   4149         return true;
   4150     }
   4151 
   4152     @Override
   4153     public void finishIteratingOldHistoryLocked() {
   4154         mIteratingHistory = false;
   4155         mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
   4156     }
   4157 
   4158     @Override
   4159     public boolean startIteratingHistoryLocked() {
   4160         if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
   4161                 + " pos=" + mHistoryBuffer.dataPosition());
   4162         mHistoryBuffer.setDataPosition(0);
   4163         mReadOverflow = false;
   4164         mIteratingHistory = true;
   4165         return mHistoryBuffer.dataSize() > 0;
   4166     }
   4167 
   4168     @Override
   4169     public boolean getNextHistoryLocked(HistoryItem out) {
   4170         final int pos = mHistoryBuffer.dataPosition();
   4171         if (pos == 0) {
   4172             out.clear();
   4173         }
   4174         boolean end = pos >= mHistoryBuffer.dataSize();
   4175         if (end) {
   4176             return false;
   4177         }
   4178 
   4179         out.readDelta(mHistoryBuffer);
   4180         return true;
   4181     }
   4182 
   4183     @Override
   4184     public void finishIteratingHistoryLocked() {
   4185         mIteratingHistory = false;
   4186         mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
   4187     }
   4188 
   4189     @Override
   4190     public long getHistoryBaseTime() {
   4191         return mHistoryBaseTime;
   4192     }
   4193 
   4194     @Override
   4195     public int getStartCount() {
   4196         return mStartCount;
   4197     }
   4198 
   4199     public boolean isOnBattery() {
   4200         return mOnBattery;
   4201     }
   4202 
   4203     public boolean isScreenOn() {
   4204         return mScreenOn;
   4205     }
   4206 
   4207     void initTimes() {
   4208         mBatteryRealtime = mTrackBatteryPastUptime = 0;
   4209         mBatteryUptime = mTrackBatteryPastRealtime = 0;
   4210         mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
   4211         mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
   4212         mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
   4213         mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
   4214     }
   4215 
   4216     void initDischarge() {
   4217         mLowDischargeAmountSinceCharge = 0;
   4218         mHighDischargeAmountSinceCharge = 0;
   4219         mDischargeAmountScreenOn = 0;
   4220         mDischargeAmountScreenOnSinceCharge = 0;
   4221         mDischargeAmountScreenOff = 0;
   4222         mDischargeAmountScreenOffSinceCharge = 0;
   4223     }
   4224 
   4225     public void resetAllStatsLocked() {
   4226         mStartCount = 0;
   4227         initTimes();
   4228         mScreenOnTimer.reset(this, false);
   4229         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
   4230             mScreenBrightnessTimer[i].reset(this, false);
   4231         }
   4232         mInputEventCounter.reset(false);
   4233         mPhoneOnTimer.reset(this, false);
   4234         mAudioOnTimer.reset(this, false);
   4235         mVideoOnTimer.reset(this, false);
   4236         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
   4237             mPhoneSignalStrengthsTimer[i].reset(this, false);
   4238         }
   4239         mPhoneSignalScanningTimer.reset(this, false);
   4240         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
   4241             mPhoneDataConnectionsTimer[i].reset(this, false);
   4242         }
   4243         mWifiOnTimer.reset(this, false);
   4244         mGlobalWifiRunningTimer.reset(this, false);
   4245         mBluetoothOnTimer.reset(this, false);
   4246 
   4247         for (int i=0; i<mUidStats.size(); i++) {
   4248             if (mUidStats.valueAt(i).reset()) {
   4249                 mUidStats.remove(mUidStats.keyAt(i));
   4250                 i--;
   4251             }
   4252         }
   4253 
   4254         if (mKernelWakelockStats.size() > 0) {
   4255             for (SamplingTimer timer : mKernelWakelockStats.values()) {
   4256                 mUnpluggables.remove(timer);
   4257             }
   4258             mKernelWakelockStats.clear();
   4259         }
   4260 
   4261         initDischarge();
   4262 
   4263         clearHistoryLocked();
   4264     }
   4265 
   4266     void updateDischargeScreenLevelsLocked(boolean oldScreenOn, boolean newScreenOn) {
   4267         if (oldScreenOn) {
   4268             int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
   4269             if (diff > 0) {
   4270                 mDischargeAmountScreenOn += diff;
   4271                 mDischargeAmountScreenOnSinceCharge += diff;
   4272             }
   4273         } else {
   4274             int diff = mDischargeScreenOffUnplugLevel - mDischargeCurrentLevel;
   4275             if (diff > 0) {
   4276                 mDischargeAmountScreenOff += diff;
   4277                 mDischargeAmountScreenOffSinceCharge += diff;
   4278             }
   4279         }
   4280         if (newScreenOn) {
   4281             mDischargeScreenOnUnplugLevel = mDischargeCurrentLevel;
   4282             mDischargeScreenOffUnplugLevel = 0;
   4283         } else {
   4284             mDischargeScreenOnUnplugLevel = 0;
   4285             mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
   4286         }
   4287     }
   4288 
   4289     void setOnBattery(boolean onBattery, int oldStatus, int level) {
   4290         synchronized(this) {
   4291             setOnBatteryLocked(onBattery, oldStatus, level);
   4292         }
   4293     }
   4294 
   4295     void setOnBatteryLocked(boolean onBattery, int oldStatus, int level) {
   4296         boolean doWrite = false;
   4297         Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
   4298         m.arg1 = onBattery ? 1 : 0;
   4299         mHandler.sendMessage(m);
   4300         mOnBattery = mOnBatteryInternal = onBattery;
   4301 
   4302         long uptime = SystemClock.uptimeMillis() * 1000;
   4303         long mSecRealtime = SystemClock.elapsedRealtime();
   4304         long realtime = mSecRealtime * 1000;
   4305         if (onBattery) {
   4306             // We will reset our status if we are unplugging after the
   4307             // battery was last full, or the level is at 100, or
   4308             // we have gone through a significant charge (from a very low
   4309             // level to a now very high level).
   4310             if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
   4311                     || level >= 90
   4312                     || (mDischargeCurrentLevel < 20 && level >= 80)) {
   4313                 doWrite = true;
   4314                 resetAllStatsLocked();
   4315                 mDischargeStartLevel = level;
   4316             }
   4317             updateKernelWakelocksLocked();
   4318             mHistoryCur.batteryLevel = (byte)level;
   4319             mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
   4320             if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
   4321                     + Integer.toHexString(mHistoryCur.states));
   4322             addHistoryRecordLocked(mSecRealtime);
   4323             mTrackBatteryUptimeStart = uptime;
   4324             mTrackBatteryRealtimeStart = realtime;
   4325             mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
   4326             mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
   4327             mDischargeCurrentLevel = mDischargeUnplugLevel = level;
   4328             if (mScreenOn) {
   4329                 mDischargeScreenOnUnplugLevel = level;
   4330                 mDischargeScreenOffUnplugLevel = 0;
   4331             } else {
   4332                 mDischargeScreenOnUnplugLevel = 0;
   4333                 mDischargeScreenOffUnplugLevel = level;
   4334             }
   4335             mDischargeAmountScreenOn = 0;
   4336             mDischargeAmountScreenOff = 0;
   4337             doUnplugLocked(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
   4338         } else {
   4339             updateKernelWakelocksLocked();
   4340             mHistoryCur.batteryLevel = (byte)level;
   4341             mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
   4342             if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
   4343                     + Integer.toHexString(mHistoryCur.states));
   4344             addHistoryRecordLocked(mSecRealtime);
   4345             mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
   4346             mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
   4347             mDischargeCurrentLevel = level;
   4348             if (level < mDischargeUnplugLevel) {
   4349                 mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
   4350                 mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
   4351             }
   4352             updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
   4353             doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
   4354         }
   4355         if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
   4356             if (mFile != null) {
   4357                 writeAsyncLocked();
   4358             }
   4359         }
   4360     }
   4361 
   4362     // This should probably be exposed in the API, though it's not critical
   4363     private static final int BATTERY_PLUGGED_NONE = 0;
   4364 
   4365     public void setBatteryState(int status, int health, int plugType, int level,
   4366             int temp, int volt) {
   4367         synchronized(this) {
   4368             boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
   4369             int oldStatus = mHistoryCur.batteryStatus;
   4370             if (!mHaveBatteryLevel) {
   4371                 mHaveBatteryLevel = true;
   4372                 // We start out assuming that the device is plugged in (not
   4373                 // on battery).  If our first report is now that we are indeed
   4374                 // plugged in, then twiddle our state to correctly reflect that
   4375                 // since we won't be going through the full setOnBattery().
   4376                 if (onBattery == mOnBattery) {
   4377                     if (onBattery) {
   4378                         mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
   4379                     } else {
   4380                         mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
   4381                     }
   4382                 }
   4383                 oldStatus = status;
   4384             }
   4385             if (onBattery) {
   4386                 mDischargeCurrentLevel = level;
   4387                 mRecordingHistory = true;
   4388             }
   4389             if (onBattery != mOnBattery) {
   4390                 mHistoryCur.batteryLevel = (byte)level;
   4391                 mHistoryCur.batteryStatus = (byte)status;
   4392                 mHistoryCur.batteryHealth = (byte)health;
   4393                 mHistoryCur.batteryPlugType = (byte)plugType;
   4394                 mHistoryCur.batteryTemperature = (char)temp;
   4395                 mHistoryCur.batteryVoltage = (char)volt;
   4396                 setOnBatteryLocked(onBattery, oldStatus, level);
   4397             } else {
   4398                 boolean changed = false;
   4399                 if (mHistoryCur.batteryLevel != level) {
   4400                     mHistoryCur.batteryLevel = (byte)level;
   4401                     changed = true;
   4402                 }
   4403                 if (mHistoryCur.batteryStatus != status) {
   4404                     mHistoryCur.batteryStatus = (byte)status;
   4405                     changed = true;
   4406                 }
   4407                 if (mHistoryCur.batteryHealth != health) {
   4408                     mHistoryCur.batteryHealth = (byte)health;
   4409                     changed = true;
   4410                 }
   4411                 if (mHistoryCur.batteryPlugType != plugType) {
   4412                     mHistoryCur.batteryPlugType = (byte)plugType;
   4413                     changed = true;
   4414                 }
   4415                 if (temp >= (mHistoryCur.batteryTemperature+10)
   4416                         || temp <= (mHistoryCur.batteryTemperature-10)) {
   4417                     mHistoryCur.batteryTemperature = (char)temp;
   4418                     changed = true;
   4419                 }
   4420                 if (volt > (mHistoryCur.batteryVoltage+20)
   4421                         || volt < (mHistoryCur.batteryVoltage-20)) {
   4422                     mHistoryCur.batteryVoltage = (char)volt;
   4423                     changed = true;
   4424                 }
   4425                 if (changed) {
   4426                     addHistoryRecordLocked(SystemClock.elapsedRealtime());
   4427                 }
   4428             }
   4429             if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
   4430                 // We don't record history while we are plugged in and fully charged.
   4431                 // The next time we are unplugged, history will be cleared.
   4432                 mRecordingHistory = false;
   4433             }
   4434         }
   4435     }
   4436 
   4437     public void updateKernelWakelocksLocked() {
   4438         Map<String, KernelWakelockStats> m = readKernelWakelockStats();
   4439 
   4440         if (m == null) {
   4441             // Not crashing might make board bringup easier.
   4442             Slog.w(TAG, "Couldn't get kernel wake lock stats");
   4443             return;
   4444         }
   4445 
   4446         for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
   4447             String name = ent.getKey();
   4448             KernelWakelockStats kws = ent.getValue();
   4449 
   4450             SamplingTimer kwlt = mKernelWakelockStats.get(name);
   4451             if (kwlt == null) {
   4452                 kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
   4453                         true /* track reported values */);
   4454                 mKernelWakelockStats.put(name, kwlt);
   4455             }
   4456             kwlt.updateCurrentReportedCount(kws.mCount);
   4457             kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
   4458             kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
   4459         }
   4460 
   4461         if (m.size() != mKernelWakelockStats.size()) {
   4462             // Set timers to stale if they didn't appear in /proc/wakelocks this time.
   4463             for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
   4464                 SamplingTimer st = ent.getValue();
   4465                 if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
   4466                     st.setStale();
   4467                 }
   4468             }
   4469         }
   4470     }
   4471 
   4472     public long getAwakeTimeBattery() {
   4473         return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
   4474     }
   4475 
   4476     public long getAwakeTimePlugged() {
   4477         return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
   4478     }
   4479 
   4480     @Override
   4481     public long computeUptime(long curTime, int which) {
   4482         switch (which) {
   4483             case STATS_SINCE_CHARGED: return mUptime + (curTime-mUptimeStart);
   4484             case STATS_LAST: return mLastUptime;
   4485             case STATS_CURRENT: return (curTime-mUptimeStart);
   4486             case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
   4487         }
   4488         return 0;
   4489     }
   4490 
   4491     @Override
   4492     public long computeRealtime(long curTime, int which) {
   4493         switch (which) {
   4494             case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
   4495             case STATS_LAST: return mLastRealtime;
   4496             case STATS_CURRENT: return (curTime-mRealtimeStart);
   4497             case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
   4498         }
   4499         return 0;
   4500     }
   4501 
   4502     @Override
   4503     public long computeBatteryUptime(long curTime, int which) {
   4504         switch (which) {
   4505             case STATS_SINCE_CHARGED:
   4506                 return mBatteryUptime + getBatteryUptime(curTime);
   4507             case STATS_LAST:
   4508                 return mBatteryLastUptime;
   4509             case STATS_CURRENT:
   4510                 return getBatteryUptime(curTime);
   4511             case STATS_SINCE_UNPLUGGED:
   4512                 return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
   4513         }
   4514         return 0;
   4515     }
   4516 
   4517     @Override
   4518     public long computeBatteryRealtime(long curTime, int which) {
   4519         switch (which) {
   4520             case STATS_SINCE_CHARGED:
   4521                 return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
   4522             case STATS_LAST:
   4523                 return mBatteryLastRealtime;
   4524             case STATS_CURRENT:
   4525                 return getBatteryRealtimeLocked(curTime);
   4526             case STATS_SINCE_UNPLUGGED:
   4527                 return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
   4528         }
   4529         return 0;
   4530     }
   4531 
   4532     long getBatteryUptimeLocked(long curTime) {
   4533         long time = mTrackBatteryPastUptime;
   4534         if (mOnBatteryInternal) {
   4535             time += curTime - mTrackBatteryUptimeStart;
   4536         }
   4537         return time;
   4538     }
   4539 
   4540     long getBatteryUptimeLocked() {
   4541         return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
   4542     }
   4543 
   4544     @Override
   4545     public long getBatteryUptime(long curTime) {
   4546         return getBatteryUptimeLocked(curTime);
   4547     }
   4548 
   4549     long getBatteryRealtimeLocked(long curTime) {
   4550         long time = mTrackBatteryPastRealtime;
   4551         if (mOnBatteryInternal) {
   4552             time += curTime - mTrackBatteryRealtimeStart;
   4553         }
   4554         return time;
   4555     }
   4556 
   4557     @Override
   4558     public long getBatteryRealtime(long curTime) {
   4559         return getBatteryRealtimeLocked(curTime);
   4560     }
   4561 
   4562     private long getTcpBytes(long current, long[] dataBytes, int which) {
   4563         if (which == STATS_LAST) {
   4564             return dataBytes[STATS_LAST];
   4565         } else {
   4566             if (which == STATS_SINCE_UNPLUGGED) {
   4567                 if (dataBytes[STATS_SINCE_UNPLUGGED] < 0) {
   4568                     return dataBytes[STATS_LAST];
   4569                 } else {
   4570                     return current - dataBytes[STATS_SINCE_UNPLUGGED];
   4571                 }
   4572             } else if (which == STATS_SINCE_CHARGED) {
   4573                 return (current - dataBytes[STATS_CURRENT]) + dataBytes[STATS_SINCE_CHARGED];
   4574             }
   4575             return current - dataBytes[STATS_CURRENT];
   4576         }
   4577     }
   4578 
   4579     /** Only STATS_UNPLUGGED works properly */
   4580     public long getMobileTcpBytesSent(int which) {
   4581         final long mobileTxBytes = getNetworkStatsSummary().getTotal(null, mMobileIfaces).txBytes;
   4582         return getTcpBytes(mobileTxBytes, mMobileDataTx, which);
   4583     }
   4584 
   4585     /** Only STATS_UNPLUGGED works properly */
   4586     public long getMobileTcpBytesReceived(int which) {
   4587         final long mobileRxBytes = getNetworkStatsSummary().getTotal(null, mMobileIfaces).rxBytes;
   4588         return getTcpBytes(mobileRxBytes, mMobileDataRx, which);
   4589     }
   4590 
   4591     /** Only STATS_UNPLUGGED works properly */
   4592     public long getTotalTcpBytesSent(int which) {
   4593         final long totalTxBytes = getNetworkStatsSummary().getTotal(null).txBytes;
   4594         return getTcpBytes(totalTxBytes, mTotalDataTx, which);
   4595     }
   4596 
   4597     /** Only STATS_UNPLUGGED works properly */
   4598     public long getTotalTcpBytesReceived(int which) {
   4599         final long totalRxBytes = getNetworkStatsSummary().getTotal(null).rxBytes;
   4600         return getTcpBytes(totalRxBytes, mTotalDataRx, which);
   4601     }
   4602 
   4603     @Override
   4604     public int getDischargeStartLevel() {
   4605         synchronized(this) {
   4606             return getDischargeStartLevelLocked();
   4607         }
   4608     }
   4609 
   4610     public int getDischargeStartLevelLocked() {
   4611             return mDischargeUnplugLevel;
   4612     }
   4613 
   4614     @Override
   4615     public int getDischargeCurrentLevel() {
   4616         synchronized(this) {
   4617             return getDischargeCurrentLevelLocked();
   4618         }
   4619     }
   4620 
   4621     public int getDischargeCurrentLevelLocked() {
   4622         return mDischargeCurrentLevel;
   4623     }
   4624 
   4625     @Override
   4626     public int getLowDischargeAmountSinceCharge() {
   4627         synchronized(this) {
   4628             int val = mLowDischargeAmountSinceCharge;
   4629             if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
   4630                 val += mDischargeUnplugLevel-mDischargeCurrentLevel-1;
   4631             }
   4632             return val;
   4633         }
   4634     }
   4635 
   4636     @Override
   4637     public int getHighDischargeAmountSinceCharge() {
   4638         synchronized(this) {
   4639             int val = mHighDischargeAmountSinceCharge;
   4640             if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
   4641                 val += mDischargeUnplugLevel-mDischargeCurrentLevel;
   4642             }
   4643             return val;
   4644         }
   4645     }
   4646 
   4647     public int getDischargeAmountScreenOn() {
   4648         synchronized(this) {
   4649             int val = mDischargeAmountScreenOn;
   4650             if (mOnBattery && mScreenOn
   4651                     && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
   4652                 val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
   4653             }
   4654             return val;
   4655         }
   4656     }
   4657 
   4658     public int getDischargeAmountScreenOnSinceCharge() {
   4659         synchronized(this) {
   4660             int val = mDischargeAmountScreenOnSinceCharge;
   4661             if (mOnBattery && mScreenOn
   4662                     && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
   4663                 val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
   4664             }
   4665             return val;
   4666         }
   4667     }
   4668 
   4669     public int getDischargeAmountScreenOff() {
   4670         synchronized(this) {
   4671             int val = mDischargeAmountScreenOff;
   4672             if (mOnBattery && !mScreenOn
   4673                     && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
   4674                 val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
   4675             }
   4676             return val;
   4677         }
   4678     }
   4679 
   4680     public int getDischargeAmountScreenOffSinceCharge() {
   4681         synchronized(this) {
   4682             int val = mDischargeAmountScreenOffSinceCharge;
   4683             if (mOnBattery && !mScreenOn
   4684                     && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
   4685                 val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
   4686             }
   4687             return val;
   4688         }
   4689     }
   4690 
   4691     @Override
   4692     public int getCpuSpeedSteps() {
   4693         return sNumSpeedSteps;
   4694     }
   4695 
   4696     /**
   4697      * Retrieve the statistics object for a particular uid, creating if needed.
   4698      */
   4699     public Uid getUidStatsLocked(int uid) {
   4700         Uid u = mUidStats.get(uid);
   4701         if (u == null) {
   4702             u = new Uid(uid);
   4703             mUidStats.put(uid, u);
   4704         }
   4705         return u;
   4706     }
   4707 
   4708     /**
   4709      * Remove the statistics object for a particular uid.
   4710      */
   4711     public void removeUidStatsLocked(int uid) {
   4712         mUidStats.remove(uid);
   4713     }
   4714 
   4715     /**
   4716      * Retrieve the statistics object for a particular process, creating
   4717      * if needed.
   4718      */
   4719     public Uid.Proc getProcessStatsLocked(int uid, String name) {
   4720         Uid u = getUidStatsLocked(uid);
   4721         return u.getProcessStatsLocked(name);
   4722     }
   4723 
   4724     /**
   4725      * Retrieve the statistics object for a particular process, given
   4726      * the name of the process.
   4727      * @param name process name
   4728      * @return the statistics object for the process
   4729      */
   4730     public Uid.Proc getProcessStatsLocked(String name, int pid) {
   4731         int uid;
   4732         if (mUidCache.containsKey(name)) {
   4733             uid = mUidCache.get(name);
   4734         } else {
   4735             uid = Process.getUidForPid(pid);
   4736             mUidCache.put(name, uid);
   4737         }
   4738         Uid u = getUidStatsLocked(uid);
   4739         return u.getProcessStatsLocked(name);
   4740     }
   4741 
   4742     /**
   4743      * Retrieve the statistics object for a particular process, creating
   4744      * if needed.
   4745      */
   4746     public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
   4747         Uid u = getUidStatsLocked(uid);
   4748         return u.getPackageStatsLocked(pkg);
   4749     }
   4750 
   4751     /**
   4752      * Retrieve the statistics object for a particular service, creating
   4753      * if needed.
   4754      */
   4755     public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
   4756         Uid u = getUidStatsLocked(uid);
   4757         return u.getServiceStatsLocked(pkg, name);
   4758     }
   4759 
   4760     /**
   4761      * Massage data to distribute any reasonable work down to more specific
   4762      * owners.  Must only be called on a dead BatteryStats object!
   4763      */
   4764     public void distributeWorkLocked(int which) {
   4765         // Aggregate all CPU time associated with WIFI.
   4766         Uid wifiUid = mUidStats.get(Process.WIFI_UID);
   4767         if (wifiUid != null) {
   4768             long uSecTime = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
   4769             for (Uid.Proc proc : wifiUid.mProcessStats.values()) {
   4770                 long totalRunningTime = getGlobalWifiRunningTime(uSecTime, which);
   4771                 for (int i=0; i<mUidStats.size(); i++) {
   4772                     Uid uid = mUidStats.valueAt(i);
   4773                     if (uid.mUid != Process.WIFI_UID) {
   4774                         long uidRunningTime = uid.getWifiRunningTime(uSecTime, which);
   4775                         if (uidRunningTime > 0) {
   4776                             Uid.Proc uidProc = uid.getProcessStatsLocked("*wifi*");
   4777                             long time = proc.getUserTime(which);
   4778                             time = (time*uidRunningTime)/totalRunningTime;
   4779                             uidProc.mUserTime += time;
   4780                             proc.mUserTime -= time;
   4781                             time = proc.getSystemTime(which);
   4782                             time = (time*uidRunningTime)/totalRunningTime;
   4783                             uidProc.mSystemTime += time;
   4784                             proc.mSystemTime -= time;
   4785                             time = proc.getForegroundTime(which);
   4786                             time = (time*uidRunningTime)/totalRunningTime;
   4787                             uidProc.mForegroundTime += time;
   4788                             proc.mForegroundTime -= time;
   4789                             for (int sb=0; sb<proc.mSpeedBins.length; sb++) {
   4790                                 SamplingCounter sc = proc.mSpeedBins[sb];
   4791                                 if (sc != null) {
   4792                                     time = sc.getCountLocked(which);
   4793                                     time = (time*uidRunningTime)/totalRunningTime;
   4794                                     SamplingCounter uidSc = uidProc.mSpeedBins[sb];
   4795                                     if (uidSc == null) {
   4796                                         uidSc = new SamplingCounter(mUnpluggables);
   4797                                         uidProc.mSpeedBins[sb] = uidSc;
   4798                                     }
   4799                                     uidSc.mCount.addAndGet((int)time);
   4800                                     sc.mCount.addAndGet((int)-time);
   4801                                 }
   4802                             }
   4803                             totalRunningTime -= uidRunningTime;
   4804                         }
   4805                     }
   4806                 }
   4807             }
   4808         }
   4809     }
   4810 
   4811     public void shutdownLocked() {
   4812         writeSyncLocked();
   4813         mShuttingDown = true;
   4814     }
   4815 
   4816     Parcel mPendingWrite = null;
   4817     final ReentrantLock mWriteLock = new ReentrantLock();
   4818 
   4819     public void writeAsyncLocked() {
   4820         writeLocked(false);
   4821     }
   4822 
   4823     public void writeSyncLocked() {
   4824         writeLocked(true);
   4825     }
   4826 
   4827     void writeLocked(boolean sync) {
   4828         if (mFile == null) {
   4829             Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
   4830             return;
   4831         }
   4832 
   4833         if (mShuttingDown) {
   4834             return;
   4835         }
   4836 
   4837         Parcel out = Parcel.obtain();
   4838         writeSummaryToParcel(out);
   4839         mLastWriteTime = SystemClock.elapsedRealtime();
   4840 
   4841         if (mPendingWrite != null) {
   4842             mPendingWrite.recycle();
   4843         }
   4844         mPendingWrite = out;
   4845 
   4846         if (sync) {
   4847             commitPendingDataToDisk();
   4848         } else {
   4849             Thread thr = new Thread("BatteryStats-Write") {
   4850                 @Override
   4851                 public void run() {
   4852                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
   4853                     commitPendingDataToDisk();
   4854                 }
   4855             };
   4856             thr.start();
   4857         }
   4858     }
   4859 
   4860     public void commitPendingDataToDisk() {
   4861         final Parcel next;
   4862         synchronized (this) {
   4863             next = mPendingWrite;
   4864             mPendingWrite = null;
   4865             if (next == null) {
   4866                 return;
   4867             }
   4868 
   4869             mWriteLock.lock();
   4870         }
   4871 
   4872         try {
   4873             FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
   4874             stream.write(next.marshall());
   4875             stream.flush();
   4876             FileUtils.sync(stream);
   4877             stream.close();
   4878             mFile.commit();
   4879         } catch (IOException e) {
   4880             Slog.w("BatteryStats", "Error writing battery statistics", e);
   4881             mFile.rollback();
   4882         } finally {
   4883             next.recycle();
   4884             mWriteLock.unlock();
   4885         }
   4886     }
   4887 
   4888     static byte[] readFully(FileInputStream stream) throws java.io.IOException {
   4889         int pos = 0;
   4890         int avail = stream.available();
   4891         byte[] data = new byte[avail];
   4892         while (true) {
   4893             int amt = stream.read(data, pos, data.length-pos);
   4894             //Log.i("foo", "Read " + amt + " bytes at " + pos
   4895             //        + " of avail " + data.length);
   4896             if (amt <= 0) {
   4897                 //Log.i("foo", "**** FINISHED READING: pos=" + pos
   4898                 //        + " len=" + data.length);
   4899                 return data;
   4900             }
   4901             pos += amt;
   4902             avail = stream.available();
   4903             if (avail > data.length-pos) {
   4904                 byte[] newData = new byte[pos+avail];
   4905                 System.arraycopy(data, 0, newData, 0, pos);
   4906                 data = newData;
   4907             }
   4908         }
   4909     }
   4910 
   4911     public void readLocked() {
   4912         if (mFile == null) {
   4913             Slog.w("BatteryStats", "readLocked: no file associated with this instance");
   4914             return;
   4915         }
   4916 
   4917         mUidStats.clear();
   4918 
   4919         try {
   4920             File file = mFile.chooseForRead();
   4921             if (!file.exists()) {
   4922                 return;
   4923             }
   4924             FileInputStream stream = new FileInputStream(file);
   4925 
   4926             byte[] raw = readFully(stream);
   4927             Parcel in = Parcel.obtain();
   4928             in.unmarshall(raw, 0, raw.length);
   4929             in.setDataPosition(0);
   4930             stream.close();
   4931 
   4932             readSummaryFromParcel(in);
   4933         } catch(java.io.IOException e) {
   4934             Slog.e("BatteryStats", "Error reading battery statistics", e);
   4935         }
   4936 
   4937         long now = SystemClock.elapsedRealtime();
   4938         if (USE_OLD_HISTORY) {
   4939             addHistoryRecordLocked(now, HistoryItem.CMD_START);
   4940         }
   4941         addHistoryBufferLocked(now, HistoryItem.CMD_START);
   4942     }
   4943 
   4944     public int describeContents() {
   4945         return 0;
   4946     }
   4947 
   4948     void readHistory(Parcel in, boolean andOldHistory) {
   4949         final long historyBaseTime = in.readLong();
   4950 
   4951         mHistoryBuffer.setDataSize(0);
   4952         mHistoryBuffer.setDataPosition(0);
   4953 
   4954         int bufSize = in.readInt();
   4955         int curPos = in.dataPosition();
   4956         if (bufSize >= (MAX_MAX_HISTORY_BUFFER*3)) {
   4957             Slog.w(TAG, "File corrupt: history data buffer too large " + bufSize);
   4958         } else if ((bufSize&~3) != bufSize) {
   4959             Slog.w(TAG, "File corrupt: history data buffer not aligned " + bufSize);
   4960         } else {
   4961             if (DEBUG_HISTORY) Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
   4962                     + " bytes at " + curPos);
   4963             mHistoryBuffer.appendFrom(in, curPos, bufSize);
   4964             in.setDataPosition(curPos + bufSize);
   4965         }
   4966 
   4967         if (andOldHistory) {
   4968             readOldHistory(in);
   4969         }
   4970 
   4971         if (DEBUG_HISTORY) {
   4972             StringBuilder sb = new StringBuilder(128);
   4973             sb.append("****************** OLD mHistoryBaseTime: ");
   4974             TimeUtils.formatDuration(mHistoryBaseTime, sb);
   4975             Slog.i(TAG, sb.toString());
   4976         }
   4977         mHistoryBaseTime = historyBaseTime;
   4978         if (DEBUG_HISTORY) {
   4979             StringBuilder sb = new StringBuilder(128);
   4980             sb.append("****************** NEW mHistoryBaseTime: ");
   4981             TimeUtils.formatDuration(mHistoryBaseTime, sb);
   4982             Slog.i(TAG, sb.toString());
   4983         }
   4984 
   4985         // We are just arbitrarily going to insert 1 minute from the sample of
   4986         // the last run until samples in this run.
   4987         if (mHistoryBaseTime > 0) {
   4988             long oldnow = SystemClock.elapsedRealtime();
   4989             mHistoryBaseTime = (mHistoryBaseTime - oldnow) + 60*1000;
   4990             if (DEBUG_HISTORY) {
   4991                 StringBuilder sb = new StringBuilder(128);
   4992                 sb.append("****************** ADJUSTED mHistoryBaseTime: ");
   4993                 TimeUtils.formatDuration(mHistoryBaseTime, sb);
   4994                 Slog.i(TAG, sb.toString());
   4995             }
   4996         }
   4997     }
   4998 
   4999     void readOldHistory(Parcel in) {
   5000         if (!USE_OLD_HISTORY) {
   5001             return;
   5002         }
   5003         mHistory = mHistoryEnd = mHistoryCache = null;
   5004         long time;
   5005         while (in.dataAvail() > 0 && (time=in.readLong()) >= 0) {
   5006             HistoryItem rec = new HistoryItem(time, in);
   5007             addHistoryRecordLocked(rec);
   5008         }
   5009     }
   5010 
   5011     void writeHistory(Parcel out, boolean andOldHistory) {
   5012         if (DEBUG_HISTORY) {
   5013             StringBuilder sb = new StringBuilder(128);
   5014             sb.append("****************** WRITING mHistoryBaseTime: ");
   5015             TimeUtils.formatDuration(mHistoryBaseTime, sb);
   5016             sb.append(" mLastHistoryTime: ");
   5017             TimeUtils.formatDuration(mLastHistoryTime, sb);
   5018             Slog.i(TAG, sb.toString());
   5019         }
   5020         out.writeLong(mHistoryBaseTime + mLastHistoryTime);
   5021         out.writeInt(mHistoryBuffer.dataSize());
   5022         if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
   5023                 + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
   5024         out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
   5025 
   5026         if (andOldHistory) {
   5027             writeOldHistory(out);
   5028         }
   5029     }
   5030 
   5031     void writeOldHistory(Parcel out) {
   5032         if (!USE_OLD_HISTORY) {
   5033             return;
   5034         }
   5035         HistoryItem rec = mHistory;
   5036         while (rec != null) {
   5037             if (rec.time >= 0) rec.writeToParcel(out, 0);
   5038             rec = rec.next;
   5039         }
   5040         out.writeLong(-1);
   5041     }
   5042 
   5043     private void readSummaryFromParcel(Parcel in) {
   5044         final int version = in.readInt();
   5045         if (version != VERSION) {
   5046             Slog.w("BatteryStats", "readFromParcel: version got " + version
   5047                 + ", expected " + VERSION + "; erasing old stats");
   5048             return;
   5049         }
   5050 
   5051         readHistory(in, true);
   5052 
   5053         mStartCount = in.readInt();
   5054         mBatteryUptime = in.readLong();
   5055         mBatteryRealtime = in.readLong();
   5056         mUptime = in.readLong();
   5057         mRealtime = in.readLong();
   5058         mDischargeUnplugLevel = in.readInt();
   5059         mDischargeCurrentLevel = in.readInt();
   5060         mLowDischargeAmountSinceCharge = in.readInt();
   5061         mHighDischargeAmountSinceCharge = in.readInt();
   5062         mDischargeAmountScreenOnSinceCharge = in.readInt();
   5063         mDischargeAmountScreenOffSinceCharge = in.readInt();
   5064 
   5065         mStartCount++;
   5066 
   5067         mScreenOn = false;
   5068         mScreenOnTimer.readSummaryFromParcelLocked(in);
   5069         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
   5070             mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
   5071         }
   5072         mInputEventCounter.readSummaryFromParcelLocked(in);
   5073         mPhoneOn = false;
   5074         mPhoneOnTimer.readSummaryFromParcelLocked(in);
   5075         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
   5076             mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
   5077         }
   5078         mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
   5079         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
   5080             mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
   5081         }
   5082         mWifiOn = false;
   5083         mWifiOnTimer.readSummaryFromParcelLocked(in);
   5084         mGlobalWifiRunning = false;
   5085         mGlobalWifiRunningTimer.readSummaryFromParcelLocked(in);
   5086         mBluetoothOn = false;
   5087         mBluetoothOnTimer.readSummaryFromParcelLocked(in);
   5088 
   5089         int NKW = in.readInt();
   5090         if (NKW > 10000) {
   5091             Slog.w(TAG, "File corrupt: too many kernel wake locks " + NKW);
   5092             return;
   5093         }
   5094         for (int ikw = 0; ikw < NKW; ikw++) {
   5095             if (in.readInt() != 0) {
   5096                 String kwltName = in.readString();
   5097                 getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
   5098             }
   5099         }
   5100 
   5101         sNumSpeedSteps = in.readInt();
   5102 
   5103         final int NU = in.readInt();
   5104         if (NU > 10000) {
   5105             Slog.w(TAG, "File corrupt: too many uids " + NU);
   5106             return;
   5107         }
   5108         for (int iu = 0; iu < NU; iu++) {
   5109             int uid = in.readInt();
   5110             Uid u = new Uid(uid);
   5111             mUidStats.put(uid, u);
   5112 
   5113             u.mWifiRunning = false;
   5114             if (in.readInt() != 0) {
   5115                 u.mWifiRunningTimer.readSummaryFromParcelLocked(in);
   5116             }
   5117             u.mFullWifiLockOut = false;
   5118             if (in.readInt() != 0) {
   5119                 u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
   5120             }
   5121             u.mScanWifiLockOut = false;
   5122             if (in.readInt() != 0) {
   5123                 u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
   5124             }
   5125             u.mWifiMulticastEnabled = false;
   5126             if (in.readInt() != 0) {
   5127                 u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
   5128             }
   5129             u.mAudioTurnedOn = false;
   5130             if (in.readInt() != 0) {
   5131                 u.mAudioTurnedOnTimer.readSummaryFromParcelLocked(in);
   5132             }
   5133             u.mVideoTurnedOn = false;
   5134             if (in.readInt() != 0) {
   5135                 u.mVideoTurnedOnTimer.readSummaryFromParcelLocked(in);
   5136             }
   5137 
   5138             if (in.readInt() != 0) {
   5139                 if (u.mUserActivityCounters == null) {
   5140                     u.initUserActivityLocked();
   5141                 }
   5142                 for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
   5143                     u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
   5144                 }
   5145             }
   5146 
   5147             int NW = in.readInt();
   5148             if (NW > 100) {
   5149                 Slog.w(TAG, "File corrupt: too many wake locks " + NW);
   5150                 return;
   5151             }
   5152             for (int iw = 0; iw < NW; iw++) {
   5153                 String wlName = in.readString();
   5154                 if (in.readInt() != 0) {
   5155                     u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
   5156                 }
   5157                 if (in.readInt() != 0) {
   5158                     u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
   5159                 }
   5160                 if (in.readInt() != 0) {
   5161                     u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
   5162                 }
   5163             }
   5164 
   5165             int NP = in.readInt();
   5166             if (NP > 1000) {
   5167                 Slog.w(TAG, "File corrupt: too many sensors " + NP);
   5168                 return;
   5169             }
   5170             for (int is = 0; is < NP; is++) {
   5171                 int seNumber = in.readInt();
   5172                 if (in.readInt() != 0) {
   5173                     u.getSensorTimerLocked(seNumber, true)
   5174                             .readSummaryFromParcelLocked(in);
   5175                 }
   5176             }
   5177 
   5178             NP = in.readInt();
   5179             if (NP > 1000) {
   5180                 Slog.w(TAG, "File corrupt: too many processes " + NP);
   5181                 return;
   5182             }
   5183             for (int ip = 0; ip < NP; ip++) {
   5184                 String procName = in.readString();
   5185                 Uid.Proc p = u.getProcessStatsLocked(procName);
   5186                 p.mUserTime = p.mLoadedUserTime = in.readLong();
   5187                 p.mSystemTime = p.mLoadedSystemTime = in.readLong();
   5188                 p.mStarts = p.mLoadedStarts = in.readInt();
   5189                 int NSB = in.readInt();
   5190                 if (NSB > 100) {
   5191                     Slog.w(TAG, "File corrupt: too many speed bins " + NSB);
   5192                     return;
   5193                 }
   5194                 p.mSpeedBins = new SamplingCounter[NSB];
   5195                 for (int i=0; i<NSB; i++) {
   5196                     if (in.readInt() != 0) {
   5197                         p.mSpeedBins[i] = new SamplingCounter(mUnpluggables);
   5198                         p.mSpeedBins[i].readSummaryFromParcelLocked(in);
   5199                     }
   5200                 }
   5201                 if (!p.readExcessivePowerFromParcelLocked(in)) {
   5202                     return;
   5203                 }
   5204             }
   5205 
   5206             NP = in.readInt();
   5207             if (NP > 10000) {
   5208                 Slog.w(TAG, "File corrupt: too many packages " + NP);
   5209                 return;
   5210             }
   5211             for (int ip = 0; ip < NP; ip++) {
   5212                 String pkgName = in.readString();
   5213                 Uid.Pkg p = u.getPackageStatsLocked(pkgName);
   5214                 p.mWakeups = p.mLoadedWakeups = in.readInt();
   5215                 final int NS = in.readInt();
   5216                 if (NS > 1000) {
   5217                     Slog.w(TAG, "File corrupt: too many services " + NS);
   5218                     return;
   5219                 }
   5220                 for (int is = 0; is < NS; is++) {
   5221                     String servName = in.readString();
   5222                     Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
   5223                     s.mStartTime = s.mLoadedStartTime = in.readLong();
   5224                     s.mStarts = s.mLoadedStarts = in.readInt();
   5225                     s.mLaunches = s.mLoadedLaunches = in.readInt();
   5226                 }
   5227             }
   5228 
   5229             u.mLoadedTcpBytesReceived = in.readLong();
   5230             u.mLoadedTcpBytesSent = in.readLong();
   5231         }
   5232     }
   5233 
   5234     /**
   5235      * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
   5236      * disk.  This format does not allow a lossless round-trip.
   5237      *
   5238      * @param out the Parcel to be written to.
   5239      */
   5240     public void writeSummaryToParcel(Parcel out) {
   5241         // Need to update with current kernel wake lock counts.
   5242         updateKernelWakelocksLocked();
   5243 
   5244         final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
   5245         final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
   5246         final long NOW = getBatteryUptimeLocked(NOW_SYS);
   5247         final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
   5248 
   5249         out.writeInt(VERSION);
   5250 
   5251         writeHistory(out, true);
   5252 
   5253         out.writeInt(mStartCount);
   5254         out.writeLong(computeBatteryUptime(NOW_SYS, STATS_SINCE_CHARGED));
   5255         out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
   5256         out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
   5257         out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
   5258         out.writeInt(mDischargeUnplugLevel);
   5259         out.writeInt(mDischargeCurrentLevel);
   5260         out.writeInt(getLowDischargeAmountSinceCharge());
   5261         out.writeInt(getHighDischargeAmountSinceCharge());
   5262         out.writeInt(getDischargeAmountScreenOnSinceCharge());
   5263         out.writeInt(getDischargeAmountScreenOffSinceCharge());
   5264 
   5265         mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
   5266         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
   5267             mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
   5268         }
   5269         mInputEventCounter.writeSummaryFromParcelLocked(out);
   5270         mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
   5271         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
   5272             mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
   5273         }
   5274         mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
   5275         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
   5276             mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
   5277         }
   5278         mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
   5279         mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
   5280         mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
   5281 
   5282         out.writeInt(mKernelWakelockStats.size());
   5283         for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
   5284             Timer kwlt = ent.getValue();
   5285             if (kwlt != null) {
   5286                 out.writeInt(1);
   5287                 out.writeString(ent.getKey());
   5288                 ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
   5289             } else {
   5290                 out.writeInt(0);
   5291             }
   5292         }
   5293 
   5294         out.writeInt(sNumSpeedSteps);
   5295         final int NU = mUidStats.size();
   5296         out.writeInt(NU);
   5297         for (int iu = 0; iu < NU; iu++) {
   5298             out.writeInt(mUidStats.keyAt(iu));
   5299             Uid u = mUidStats.valueAt(iu);
   5300 
   5301             if (u.mWifiRunningTimer != null) {
   5302                 out.writeInt(1);
   5303                 u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
   5304             } else {
   5305                 out.writeInt(0);
   5306             }
   5307             if (u.mFullWifiLockTimer != null) {
   5308                 out.writeInt(1);
   5309                 u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
   5310             } else {
   5311                 out.writeInt(0);
   5312             }
   5313             if (u.mScanWifiLockTimer != null) {
   5314                 out.writeInt(1);
   5315                 u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
   5316             } else {
   5317                 out.writeInt(0);
   5318             }
   5319             if (u.mWifiMulticastTimer != null) {
   5320                 out.writeInt(1);
   5321                 u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
   5322             } else {
   5323                 out.writeInt(0);
   5324             }
   5325             if (u.mAudioTurnedOnTimer != null) {
   5326                 out.writeInt(1);
   5327                 u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
   5328             } else {
   5329                 out.writeInt(0);
   5330             }
   5331             if (u.mVideoTurnedOnTimer != null) {
   5332                 out.writeInt(1);
   5333                 u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
   5334             } else {
   5335                 out.writeInt(0);
   5336             }
   5337 
   5338             if (u.mUserActivityCounters == null) {
   5339                 out.writeInt(0);
   5340             } else {
   5341                 out.writeInt(1);
   5342                 for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
   5343                     u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
   5344                 }
   5345             }
   5346 
   5347             int NW = u.mWakelockStats.size();
   5348             out.writeInt(NW);
   5349             if (NW > 0) {
   5350                 for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
   5351                         : u.mWakelockStats.entrySet()) {
   5352                     out.writeString(ent.getKey());
   5353                     Uid.Wakelock wl = ent.getValue();
   5354                     if (wl.mTimerFull != null) {
   5355                         out.writeInt(1);
   5356                         wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
   5357                     } else {
   5358                         out.writeInt(0);
   5359                     }
   5360                     if (wl.mTimerPartial != null) {
   5361                         out.writeInt(1);
   5362                         wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
   5363                     } else {
   5364                         out.writeInt(0);
   5365                     }
   5366                     if (wl.mTimerWindow != null) {
   5367                         out.writeInt(1);
   5368                         wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
   5369                     } else {
   5370                         out.writeInt(0);
   5371                     }
   5372                 }
   5373             }
   5374 
   5375             int NSE = u.mSensorStats.size();
   5376             out.writeInt(NSE);
   5377             if (NSE > 0) {
   5378                 for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
   5379                         : u.mSensorStats.entrySet()) {
   5380                     out.writeInt(ent.getKey());
   5381                     Uid.Sensor se = ent.getValue();
   5382                     if (se.mTimer != null) {
   5383                         out.writeInt(1);
   5384                         se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
   5385                     } else {
   5386                         out.writeInt(0);
   5387                     }
   5388                 }
   5389             }
   5390 
   5391             int NP = u.mProcessStats.size();
   5392             out.writeInt(NP);
   5393             if (NP > 0) {
   5394                 for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
   5395                     : u.mProcessStats.entrySet()) {
   5396                     out.writeString(ent.getKey());
   5397                     Uid.Proc ps = ent.getValue();
   5398                     out.writeLong(ps.mUserTime);
   5399                     out.writeLong(ps.mSystemTime);
   5400                     out.writeInt(ps.mStarts);
   5401                     final int N = ps.mSpeedBins.length;
   5402                     out.writeInt(N);
   5403                     for (int i=0; i<N; i++) {
   5404                         if (ps.mSpeedBins[i] != null) {
   5405                             out.writeInt(1);
   5406                             ps.mSpeedBins[i].writeSummaryFromParcelLocked(out);
   5407                         } else {
   5408                             out.writeInt(0);
   5409                         }
   5410                     }
   5411                     ps.writeExcessivePowerToParcelLocked(out);
   5412                 }
   5413             }
   5414 
   5415             NP = u.mPackageStats.size();
   5416             out.writeInt(NP);
   5417             if (NP > 0) {
   5418                 for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
   5419                     : u.mPackageStats.entrySet()) {
   5420                     out.writeString(ent.getKey());
   5421                     Uid.Pkg ps = ent.getValue();
   5422                     out.writeInt(ps.mWakeups);
   5423                     final int NS = ps.mServiceStats.size();
   5424                     out.writeInt(NS);
   5425                     if (NS > 0) {
   5426                         for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
   5427                                 : ps.mServiceStats.entrySet()) {
   5428                             out.writeString(sent.getKey());
   5429                             BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
   5430                             long time = ss.getStartTimeToNowLocked(NOW);
   5431                             out.writeLong(time);
   5432                             out.writeInt(ss.mStarts);
   5433                             out.writeInt(ss.mLaunches);
   5434                         }
   5435                     }
   5436                 }
   5437             }
   5438 
   5439             out.writeLong(u.getTcpBytesReceived(STATS_SINCE_CHARGED));
   5440             out.writeLong(u.getTcpBytesSent(STATS_SINCE_CHARGED));
   5441         }
   5442     }
   5443 
   5444     public void readFromParcel(Parcel in) {
   5445         readFromParcelLocked(in);
   5446     }
   5447 
   5448     void readFromParcelLocked(Parcel in) {
   5449         int magic = in.readInt();
   5450         if (magic != MAGIC) {
   5451             throw new ParcelFormatException("Bad magic number");
   5452         }
   5453 
   5454         readHistory(in, false);
   5455 
   5456         mStartCount = in.readInt();
   5457         mBatteryUptime = in.readLong();
   5458         mBatteryLastUptime = 0;
   5459         mBatteryRealtime = in.readLong();
   5460         mBatteryLastRealtime = 0;
   5461         mScreenOn = false;
   5462         mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables, in);
   5463         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
   5464             mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i,
   5465                     null, mUnpluggables, in);
   5466         }
   5467         mInputEventCounter = new Counter(mUnpluggables, in);
   5468         mPhoneOn = false;
   5469         mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
   5470         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
   5471             mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
   5472                     null, mUnpluggables, in);
   5473         }
   5474         mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables, in);
   5475         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
   5476             mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
   5477                     null, mUnpluggables, in);
   5478         }
   5479         mWifiOn = false;
   5480         mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
   5481         mGlobalWifiRunning = false;
   5482         mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
   5483         mBluetoothOn = false;
   5484         mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
   5485         mUptime = in.readLong();
   5486         mUptimeStart = in.readLong();
   5487         mLastUptime = 0;
   5488         mRealtime = in.readLong();
   5489         mRealtimeStart = in.readLong();
   5490         mLastRealtime = 0;
   5491         mOnBattery = in.readInt() != 0;
   5492         mOnBatteryInternal = false; // we are no longer really running.
   5493         mTrackBatteryPastUptime = in.readLong();
   5494         mTrackBatteryUptimeStart = in.readLong();
   5495         mTrackBatteryPastRealtime = in.readLong();
   5496         mTrackBatteryRealtimeStart = in.readLong();
   5497         mUnpluggedBatteryUptime = in.readLong();
   5498         mUnpluggedBatteryRealtime = in.readLong();
   5499         mDischargeUnplugLevel = in.readInt();
   5500         mDischargeCurrentLevel = in.readInt();
   5501         mLowDischargeAmountSinceCharge = in.readInt();
   5502         mHighDischargeAmountSinceCharge = in.readInt();
   5503         mDischargeAmountScreenOn = in.readInt();
   5504         mDischargeAmountScreenOnSinceCharge = in.readInt();
   5505         mDischargeAmountScreenOff = in.readInt();
   5506         mDischargeAmountScreenOffSinceCharge = in.readInt();
   5507         mLastWriteTime = in.readLong();
   5508 
   5509         mMobileDataRx[STATS_LAST] = in.readLong();
   5510         mMobileDataRx[STATS_SINCE_UNPLUGGED] = -1;
   5511         mMobileDataTx[STATS_LAST] = in.readLong();
   5512         mMobileDataTx[STATS_SINCE_UNPLUGGED] = -1;
   5513         mTotalDataRx[STATS_LAST] = in.readLong();
   5514         mTotalDataRx[STATS_SINCE_UNPLUGGED] = -1;
   5515         mTotalDataTx[STATS_LAST] = in.readLong();
   5516         mTotalDataTx[STATS_SINCE_UNPLUGGED] = -1;
   5517 
   5518         mRadioDataUptime = in.readLong();
   5519         mRadioDataStart = -1;
   5520 
   5521         mBluetoothPingCount = in.readInt();
   5522         mBluetoothPingStart = -1;
   5523 
   5524         mKernelWakelockStats.clear();
   5525         int NKW = in.readInt();
   5526         for (int ikw = 0; ikw < NKW; ikw++) {
   5527             if (in.readInt() != 0) {
   5528                 String wakelockName = in.readString();
   5529                 in.readInt(); // Extra 0/1 written by Timer.writeTimerToParcel
   5530                 SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
   5531                 mKernelWakelockStats.put(wakelockName, kwlt);
   5532             }
   5533         }
   5534 
   5535         mPartialTimers.clear();
   5536         mFullTimers.clear();
   5537         mWindowTimers.clear();
   5538         mWifiRunningTimers.clear();
   5539         mFullWifiLockTimers.clear();
   5540         mScanWifiLockTimers.clear();
   5541         mWifiMulticastTimers.clear();
   5542 
   5543         sNumSpeedSteps = in.readInt();
   5544 
   5545         int numUids = in.readInt();
   5546         mUidStats.clear();
   5547         for (int i = 0; i < numUids; i++) {
   5548             int uid = in.readInt();
   5549             Uid u = new Uid(uid);
   5550             u.readFromParcelLocked(mUnpluggables, in);
   5551             mUidStats.append(uid, u);
   5552         }
   5553     }
   5554 
   5555     public void writeToParcel(Parcel out, int flags) {
   5556         writeToParcelLocked(out, true, flags);
   5557     }
   5558 
   5559     public void writeToParcelWithoutUids(Parcel out, int flags) {
   5560         writeToParcelLocked(out, false, flags);
   5561     }
   5562 
   5563     @SuppressWarnings("unused")
   5564     void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
   5565         // Need to update with current kernel wake lock counts.
   5566         updateKernelWakelocksLocked();
   5567 
   5568         final long uSecUptime = SystemClock.uptimeMillis() * 1000;
   5569         final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
   5570         final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
   5571         final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
   5572 
   5573         out.writeInt(MAGIC);
   5574 
   5575         writeHistory(out, false);
   5576 
   5577         out.writeInt(mStartCount);
   5578         out.writeLong(mBatteryUptime);
   5579         out.writeLong(mBatteryRealtime);
   5580         mScreenOnTimer.writeToParcel(out, batteryRealtime);
   5581         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
   5582             mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
   5583         }
   5584         mInputEventCounter.writeToParcel(out);
   5585         mPhoneOnTimer.writeToParcel(out, batteryRealtime);
   5586         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
   5587             mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
   5588         }
   5589         mPhoneSignalScanningTimer.writeToParcel(out, batteryRealtime);
   5590         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
   5591             mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
   5592         }
   5593         mWifiOnTimer.writeToParcel(out, batteryRealtime);
   5594         mGlobalWifiRunningTimer.writeToParcel(out, batteryRealtime);
   5595         mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
   5596         out.writeLong(mUptime);
   5597         out.writeLong(mUptimeStart);
   5598         out.writeLong(mRealtime);
   5599         out.writeLong(mRealtimeStart);
   5600         out.writeInt(mOnBattery ? 1 : 0);
   5601         out.writeLong(batteryUptime);
   5602         out.writeLong(mTrackBatteryUptimeStart);
   5603         out.writeLong(batteryRealtime);
   5604         out.writeLong(mTrackBatteryRealtimeStart);
   5605         out.writeLong(mUnpluggedBatteryUptime);
   5606         out.writeLong(mUnpluggedBatteryRealtime);
   5607         out.writeInt(mDischargeUnplugLevel);
   5608         out.writeInt(mDischargeCurrentLevel);
   5609         out.writeInt(mLowDischargeAmountSinceCharge);
   5610         out.writeInt(mHighDischargeAmountSinceCharge);
   5611         out.writeInt(mDischargeAmountScreenOn);
   5612         out.writeInt(mDischargeAmountScreenOnSinceCharge);
   5613         out.writeInt(mDischargeAmountScreenOff);
   5614         out.writeInt(mDischargeAmountScreenOffSinceCharge);
   5615         out.writeLong(mLastWriteTime);
   5616 
   5617         out.writeLong(getMobileTcpBytesReceived(STATS_SINCE_UNPLUGGED));
   5618         out.writeLong(getMobileTcpBytesSent(STATS_SINCE_UNPLUGGED));
   5619         out.writeLong(getTotalTcpBytesReceived(STATS_SINCE_UNPLUGGED));
   5620         out.writeLong(getTotalTcpBytesSent(STATS_SINCE_UNPLUGGED));
   5621 
   5622         // Write radio uptime for data
   5623         out.writeLong(getRadioDataUptime());
   5624 
   5625         out.writeInt(getBluetoothPingCount());
   5626 
   5627         if (inclUids) {
   5628             out.writeInt(mKernelWakelockStats.size());
   5629             for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
   5630                 SamplingTimer kwlt = ent.getValue();
   5631                 if (kwlt != null) {
   5632                     out.writeInt(1);
   5633                     out.writeString(ent.getKey());
   5634                     Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
   5635                 } else {
   5636                     out.writeInt(0);
   5637                 }
   5638             }
   5639         } else {
   5640             out.writeInt(0);
   5641         }
   5642 
   5643         out.writeInt(sNumSpeedSteps);
   5644 
   5645         if (inclUids) {
   5646             int size = mUidStats.size();
   5647             out.writeInt(size);
   5648             for (int i = 0; i < size; i++) {
   5649                 out.writeInt(mUidStats.keyAt(i));
   5650                 Uid uid = mUidStats.valueAt(i);
   5651 
   5652                 uid.writeToParcelLocked(out, batteryRealtime);
   5653             }
   5654         } else {
   5655             out.writeInt(0);
   5656         }
   5657     }
   5658 
   5659     public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
   5660         new Parcelable.Creator<BatteryStatsImpl>() {
   5661         public BatteryStatsImpl createFromParcel(Parcel in) {
   5662             return new BatteryStatsImpl(in);
   5663         }
   5664 
   5665         public BatteryStatsImpl[] newArray(int size) {
   5666             return new BatteryStatsImpl[size];
   5667         }
   5668     };
   5669 
   5670     public void prepareForDumpLocked() {
   5671         // Need to retrieve current kernel wake lock stats before printing.
   5672         updateKernelWakelocksLocked();
   5673     }
   5674 
   5675     public void dumpLocked(PrintWriter pw) {
   5676         if (DEBUG) {
   5677             Printer pr = new PrintWriterPrinter(pw);
   5678             pr.println("*** Screen timer:");
   5679             mScreenOnTimer.logState(pr, "  ");
   5680             for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
   5681                 pr.println("*** Screen brightness #" + i + ":");
   5682                 mScreenBrightnessTimer[i].logState(pr, "  ");
   5683             }
   5684             pr.println("*** Input event counter:");
   5685             mInputEventCounter.logState(pr, "  ");
   5686             pr.println("*** Phone timer:");
   5687             mPhoneOnTimer.logState(pr, "  ");
   5688             for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
   5689                 pr.println("*** Signal strength #" + i + ":");
   5690                 mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
   5691             }
   5692             pr.println("*** Signal scanning :");
   5693             mPhoneSignalScanningTimer.logState(pr, "  ");
   5694             for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
   5695                 pr.println("*** Data connection type #" + i + ":");
   5696                 mPhoneDataConnectionsTimer[i].logState(pr, "  ");
   5697             }
   5698             pr.println("*** Wifi timer:");
   5699             mWifiOnTimer.logState(pr, "  ");
   5700             pr.println("*** WifiRunning timer:");
   5701             mGlobalWifiRunningTimer.logState(pr, "  ");
   5702             pr.println("*** Bluetooth timer:");
   5703             mBluetoothOnTimer.logState(pr, "  ");
   5704             pr.println("*** Mobile ifaces:");
   5705             pr.println(mMobileIfaces.toString());
   5706         }
   5707         super.dumpLocked(pw);
   5708     }
   5709 
   5710     private NetworkStats mNetworkSummaryCache;
   5711     private NetworkStats mNetworkDetailCache;
   5712 
   5713     private NetworkStats getNetworkStatsSummary() {
   5714         // NOTE: calls from BatteryStatsService already hold this lock
   5715         synchronized (this) {
   5716             if (mNetworkSummaryCache == null
   5717                     || mNetworkSummaryCache.getElapsedRealtimeAge() > SECOND_IN_MILLIS) {
   5718                 mNetworkSummaryCache = null;
   5719 
   5720                 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
   5721                     try {
   5722                         mNetworkSummaryCache = mNetworkStatsFactory.readNetworkStatsSummaryDev();
   5723                     } catch (IllegalStateException e) {
   5724                         Log.wtf(TAG, "problem reading network stats", e);
   5725                     }
   5726                 }
   5727 
   5728                 if (mNetworkSummaryCache == null) {
   5729                     mNetworkSummaryCache = new NetworkStats(SystemClock.elapsedRealtime(), 0);
   5730                 }
   5731             }
   5732             return mNetworkSummaryCache;
   5733         }
   5734     }
   5735 
   5736     private NetworkStats getNetworkStatsDetailGroupedByUid() {
   5737         // NOTE: calls from BatteryStatsService already hold this lock
   5738         synchronized (this) {
   5739             if (mNetworkDetailCache == null
   5740                     || mNetworkDetailCache.getElapsedRealtimeAge() > SECOND_IN_MILLIS) {
   5741                 mNetworkDetailCache = null;
   5742 
   5743                 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
   5744                     try {
   5745                         mNetworkDetailCache = mNetworkStatsFactory
   5746                                 .readNetworkStatsDetail().groupedByUid();
   5747                     } catch (IllegalStateException e) {
   5748                         Log.wtf(TAG, "problem reading network stats", e);
   5749                     }
   5750                 }
   5751 
   5752                 if (mNetworkDetailCache == null) {
   5753                     mNetworkDetailCache = new NetworkStats(SystemClock.elapsedRealtime(), 0);
   5754                 }
   5755             }
   5756             return mNetworkDetailCache;
   5757         }
   5758     }
   5759 }
   5760