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