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