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