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