BatteryStatsImpl.java revision 32907cfb38bda2d3c052cf5139c5b592678fedbb
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.BatteryStats;
24import android.os.Parcel;
25import android.os.ParcelFormatException;
26import android.os.Parcelable;
27import android.os.Process;
28import android.os.SystemClock;
29import android.telephony.ServiceState;
30import android.telephony.SignalStrength;
31import android.telephony.TelephonyManager;
32import android.util.Log;
33import android.util.PrintWriterPrinter;
34import android.util.Printer;
35import android.util.Slog;
36import android.util.SparseArray;
37
38import java.io.BufferedReader;
39import java.io.File;
40import java.io.FileInputStream;
41import java.io.FileOutputStream;
42import java.io.FileReader;
43import java.io.IOException;
44import java.io.PrintWriter;
45import java.util.ArrayList;
46import java.util.HashMap;
47import java.util.Iterator;
48import java.util.Map;
49import java.util.concurrent.atomic.AtomicInteger;
50
51/**
52 * All information we are collecting about things that can happen that impact
53 * battery life.  All times are represented in microseconds except where indicated
54 * otherwise.
55 */
56public final class BatteryStatsImpl extends BatteryStats {
57    private static final String TAG = "BatteryStatsImpl";
58    private static final boolean DEBUG = false;
59    private static final boolean DEBUG_HISTORY = false;
60
61    // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
62    private static final int MAGIC = 0xBA757475; // 'BATSTATS'
63
64    // Current on-disk Parcel version
65    private static final int VERSION = 44;
66
67    // The maximum number of names wakelocks we will keep track of
68    // per uid; once the limit is reached, we batch the remaining wakelocks
69    // in to one common name.
70    private static final int MAX_WAKELOCKS_PER_UID = 20;
71
72    private static final String BATCHED_WAKELOCK_NAME = "*overflow*";
73
74    private static int sNumSpeedSteps;
75
76    private final JournaledFile mFile;
77
78    /**
79     * The statistics we have collected organized by uids.
80     */
81    final SparseArray<BatteryStatsImpl.Uid> mUidStats =
82        new SparseArray<BatteryStatsImpl.Uid>();
83
84    // A set of pools of currently active timers.  When a timer is queried, we will divide the
85    // elapsed time by the number of active timers to arrive at that timer's share of the time.
86    // In order to do this, we must refresh each timer whenever the number of active timers
87    // changes.
88    final ArrayList<StopwatchTimer> mPartialTimers = new ArrayList<StopwatchTimer>();
89    final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<StopwatchTimer>();
90    final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<StopwatchTimer>();
91    final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers
92            = new SparseArray<ArrayList<StopwatchTimer>>();
93
94    // These are the objects that will want to do something when the device
95    // is unplugged from power.
96    final ArrayList<Unpluggable> mUnpluggables = new ArrayList<Unpluggable>();
97
98    BatteryHistoryRecord mHistory;
99    BatteryHistoryRecord mHistoryEnd;
100    BatteryHistoryRecord mHistoryCache;
101    final BatteryHistoryRecord mHistoryCur = new BatteryHistoryRecord();
102
103    int mStartCount;
104
105    long mBatteryUptime;
106    long mBatteryLastUptime;
107    long mBatteryRealtime;
108    long mBatteryLastRealtime;
109
110    long mUptime;
111    long mUptimeStart;
112    long mLastUptime;
113    long mRealtime;
114    long mRealtimeStart;
115    long mLastRealtime;
116
117    boolean mScreenOn;
118    StopwatchTimer mScreenOnTimer;
119
120    int mScreenBrightnessBin = -1;
121    final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
122
123    Counter mInputEventCounter;
124
125    boolean mPhoneOn;
126    StopwatchTimer mPhoneOnTimer;
127
128    boolean mAudioOn;
129    StopwatchTimer mAudioOnTimer;
130
131    boolean mVideoOn;
132    StopwatchTimer mVideoOnTimer;
133
134    int mPhoneSignalStrengthBin = -1;
135    final StopwatchTimer[] mPhoneSignalStrengthsTimer =
136            new StopwatchTimer[NUM_SIGNAL_STRENGTH_BINS];
137
138    StopwatchTimer mPhoneSignalScanningTimer;
139
140    int mPhoneDataConnectionType = -1;
141    final StopwatchTimer[] mPhoneDataConnectionsTimer =
142            new StopwatchTimer[NUM_DATA_CONNECTION_TYPES];
143
144    boolean mWifiOn;
145    StopwatchTimer mWifiOnTimer;
146    int mWifiOnUid = -1;
147
148    boolean mWifiRunning;
149    StopwatchTimer mWifiRunningTimer;
150
151    boolean mBluetoothOn;
152    StopwatchTimer mBluetoothOnTimer;
153
154    /** Bluetooth headset object */
155    BluetoothHeadset mBtHeadset;
156
157    /**
158     * These provide time bases that discount the time the device is plugged
159     * in to power.
160     */
161    boolean mOnBattery;
162    boolean mOnBatteryInternal;
163    long mTrackBatteryPastUptime;
164    long mTrackBatteryUptimeStart;
165    long mTrackBatteryPastRealtime;
166    long mTrackBatteryRealtimeStart;
167
168    long mUnpluggedBatteryUptime;
169    long mUnpluggedBatteryRealtime;
170
171    /*
172     * These keep track of battery levels (1-100) at the last plug event and the last unplug event.
173     */
174    int mDischargeStartLevel;
175    int mDischargeCurrentLevel;
176
177    long mLastWriteTime = 0; // Milliseconds
178
179    // Mobile data transferred while on battery
180    private long[] mMobileDataTx = new long[4];
181    private long[] mMobileDataRx = new long[4];
182    private long[] mTotalDataTx = new long[4];
183    private long[] mTotalDataRx = new long[4];
184
185    private long mRadioDataUptime;
186    private long mRadioDataStart;
187
188    private int mBluetoothPingCount;
189    private int mBluetoothPingStart = -1;
190
191    private int mPhoneServiceState = -1;
192
193    /*
194     * Holds a SamplingTimer associated with each kernel wakelock name being tracked.
195     */
196    private final HashMap<String, SamplingTimer> mKernelWakelockStats =
197            new HashMap<String, SamplingTimer>();
198
199    public Map<String, ? extends SamplingTimer> getKernelWakelockStats() {
200        return mKernelWakelockStats;
201    }
202
203    private static int sKernelWakelockUpdateVersion = 0;
204
205    private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
206        Process.PROC_TAB_TERM|Process.PROC_OUT_STRING,                // 0: name
207        Process.PROC_TAB_TERM|Process.PROC_OUT_LONG,                  // 1: count
208        Process.PROC_TAB_TERM,
209        Process.PROC_TAB_TERM,
210        Process.PROC_TAB_TERM,
211        Process.PROC_TAB_TERM|Process.PROC_OUT_LONG,                  // 5: totalTime
212    };
213
214    private final String[] mProcWakelocksName = new String[3];
215    private final long[] mProcWakelocksData = new long[3];
216
217    /*
218     * Used as a buffer for reading in data from /proc/wakelocks before it is processed and added
219     * to mKernelWakelockStats.
220     */
221    private final Map<String, KernelWakelockStats> mProcWakelockFileStats =
222            new HashMap<String, KernelWakelockStats>();
223
224    private HashMap<String, Integer> mUidCache = new HashMap<String, Integer>();
225
226    // For debugging
227    public BatteryStatsImpl() {
228        mFile = null;
229    }
230
231    public static interface Unpluggable {
232        void unplug(long batteryUptime, long batteryRealtime);
233        void plug(long batteryUptime, long batteryRealtime);
234    }
235
236    /**
237     * State for keeping track of counting information.
238     */
239    public static class Counter extends BatteryStats.Counter implements Unpluggable {
240        final AtomicInteger mCount = new AtomicInteger();
241        int mLoadedCount;
242        int mLastCount;
243        int mUnpluggedCount;
244        int mPluggedCount;
245
246        Counter(ArrayList<Unpluggable> unpluggables, Parcel in) {
247            mPluggedCount = in.readInt();
248            mCount.set(mPluggedCount);
249            mLoadedCount = in.readInt();
250            mLastCount = in.readInt();
251            mUnpluggedCount = in.readInt();
252            unpluggables.add(this);
253        }
254
255        Counter(ArrayList<Unpluggable> unpluggables) {
256            unpluggables.add(this);
257        }
258
259        public void writeToParcel(Parcel out) {
260            out.writeInt(mCount.get());
261            out.writeInt(mLoadedCount);
262            out.writeInt(mLastCount);
263            out.writeInt(mUnpluggedCount);
264        }
265
266        public void unplug(long batteryUptime, long batteryRealtime) {
267            mUnpluggedCount = mPluggedCount;
268            mCount.set(mPluggedCount);
269        }
270
271        public void plug(long batteryUptime, long batteryRealtime) {
272            mPluggedCount = mCount.get();
273        }
274
275        /**
276         * Writes a possibly null Counter to a Parcel.
277         *
278         * @param out the Parcel to be written to.
279         * @param counter a Counter, or null.
280         */
281        public static void writeCounterToParcel(Parcel out, Counter counter) {
282            if (counter == null) {
283                out.writeInt(0); // indicates null
284                return;
285            }
286            out.writeInt(1); // indicates non-null
287
288            counter.writeToParcel(out);
289        }
290
291        @Override
292        public int getCountLocked(int which) {
293            int val;
294            if (which == STATS_LAST) {
295                val = mLastCount;
296            } else {
297                val = mCount.get();
298                if (which == STATS_UNPLUGGED) {
299                    val -= mUnpluggedCount;
300                } else if (which != STATS_TOTAL) {
301                    val -= mLoadedCount;
302                }
303            }
304
305            return val;
306        }
307
308        public void logState(Printer pw, String prefix) {
309            pw.println(prefix + "mCount=" + mCount.get()
310                    + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
311                    + " mUnpluggedCount=" + mUnpluggedCount
312                    + " mPluggedCount=" + mPluggedCount);
313        }
314
315        void stepAtomic() {
316            mCount.incrementAndGet();
317        }
318
319        void writeSummaryFromParcelLocked(Parcel out) {
320            int count = mCount.get();
321            out.writeInt(count);
322            out.writeInt(count - mLoadedCount);
323        }
324
325        void readSummaryFromParcelLocked(Parcel in) {
326            mLoadedCount = in.readInt();
327            mCount.set(mLoadedCount);
328            mLastCount = in.readInt();
329            mUnpluggedCount = mPluggedCount = mLoadedCount;
330        }
331    }
332
333    public static class SamplingCounter extends Counter {
334
335        SamplingCounter(ArrayList<Unpluggable> unpluggables, Parcel in) {
336            super(unpluggables, in);
337        }
338
339        SamplingCounter(ArrayList<Unpluggable> unpluggables) {
340            super(unpluggables);
341        }
342
343        public void addCountAtomic(long count) {
344            mCount.addAndGet((int)count);
345        }
346    }
347
348    /**
349     * State for keeping track of timing information.
350     */
351    public static abstract class Timer extends BatteryStats.Timer implements Unpluggable {
352        final int mType;
353
354
355        int mCount;
356        int mLoadedCount;
357        int mLastCount;
358        int mUnpluggedCount;
359
360        // Times are in microseconds for better accuracy when dividing by the
361        // lock count, and are in "battery realtime" units.
362
363        /**
364         * The total time we have accumulated since the start of the original
365         * boot, to the last time something interesting happened in the
366         * current run.
367         */
368        long mTotalTime;
369
370        /**
371         * The total time we loaded for the previous runs.  Subtract this from
372         * mTotalTime to find the time for the current run of the system.
373         */
374        long mLoadedTime;
375
376        /**
377         * The run time of the last run of the system, as loaded from the
378         * saved data.
379         */
380        long mLastTime;
381
382        /**
383         * The value of mTotalTime when unplug() was last called.  Subtract
384         * this from mTotalTime to find the time since the last unplug from
385         * power.
386         */
387        long mUnpluggedTime;
388
389        /**
390         * Constructs from a parcel.
391         * @param type
392         * @param unpluggables
393         * @param powerType
394         * @param in
395         */
396        Timer(int type, ArrayList<Unpluggable> unpluggables, Parcel in) {
397            mType = type;
398
399            mCount = in.readInt();
400            mLoadedCount = in.readInt();
401            mLastCount = in.readInt();
402            mUnpluggedCount = in.readInt();
403            mTotalTime = in.readLong();
404            mLoadedTime = in.readLong();
405            mLastTime = in.readLong();
406            mUnpluggedTime = in.readLong();
407            unpluggables.add(this);
408        }
409
410        Timer(int type, ArrayList<Unpluggable> unpluggables) {
411            mType = type;
412            unpluggables.add(this);
413        }
414
415        protected abstract long computeRunTimeLocked(long curBatteryRealtime);
416
417        protected abstract int computeCurrentCountLocked();
418
419
420        public void writeToParcel(Parcel out, long batteryRealtime) {
421            out.writeInt(mCount);
422            out.writeInt(mLoadedCount);
423            out.writeInt(mLastCount);
424            out.writeInt(mUnpluggedCount);
425            out.writeLong(computeRunTimeLocked(batteryRealtime));
426            out.writeLong(mLoadedTime);
427            out.writeLong(mLastTime);
428            out.writeLong(mUnpluggedTime);
429        }
430
431        public void unplug(long batteryUptime, long batteryRealtime) {
432            if (DEBUG && mType < 0) {
433                Log.v(TAG, "unplug #" + mType + ": realtime=" + batteryRealtime
434                        + " old mUnpluggedTime=" + mUnpluggedTime
435                        + " old mUnpluggedCount=" + mUnpluggedCount);
436            }
437            mUnpluggedTime = computeRunTimeLocked(batteryRealtime);
438            mUnpluggedCount = mCount;
439            if (DEBUG && mType < 0) {
440                Log.v(TAG, "unplug #" + mType
441                        + ": new mUnpluggedTime=" + mUnpluggedTime
442                        + " new mUnpluggedCount=" + mUnpluggedCount);
443            }
444        }
445
446        public void plug(long batteryUptime, long batteryRealtime) {
447            if (DEBUG && mType < 0) {
448                Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime
449                        + " old mTotalTime=" + mTotalTime);
450            }
451            mTotalTime = computeRunTimeLocked(batteryRealtime);
452            mCount = computeCurrentCountLocked();
453            if (DEBUG && mType < 0) {
454                Log.v(TAG, "plug #" + mType
455                        + ": new mTotalTime=" + mTotalTime);
456            }
457        }
458
459        /**
460         * Writes a possibly null Timer to a Parcel.
461         *
462         * @param out the Parcel to be written to.
463         * @param timer a Timer, or null.
464         */
465        public static void writeTimerToParcel(Parcel out, Timer timer,
466                long batteryRealtime) {
467            if (timer == null) {
468                out.writeInt(0); // indicates null
469                return;
470            }
471            out.writeInt(1); // indicates non-null
472
473            timer.writeToParcel(out, batteryRealtime);
474        }
475
476        @Override
477        public long getTotalTimeLocked(long batteryRealtime, int which) {
478            long val;
479            if (which == STATS_LAST) {
480                val = mLastTime;
481            } else {
482                val = computeRunTimeLocked(batteryRealtime);
483                if (which == STATS_UNPLUGGED) {
484                    val -= mUnpluggedTime;
485                } else if (which != STATS_TOTAL) {
486                    val -= mLoadedTime;
487                }
488            }
489
490            return val;
491        }
492
493        @Override
494        public int getCountLocked(int which) {
495            int val;
496            if (which == STATS_LAST) {
497                val = mLastCount;
498            } else {
499                val = computeCurrentCountLocked();
500                if (which == STATS_UNPLUGGED) {
501                    val -= mUnpluggedCount;
502                } else if (which != STATS_TOTAL) {
503                    val -= mLoadedCount;
504                }
505            }
506
507            return val;
508        }
509
510        public void logState(Printer pw, String prefix) {
511            pw.println(prefix + " mCount=" + mCount
512                    + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
513                    + " mUnpluggedCount=" + mUnpluggedCount);
514            pw.println(prefix + "mTotalTime=" + mTotalTime
515                    + " mLoadedTime=" + mLoadedTime);
516            pw.println(prefix + "mLastTime=" + mLastTime
517                    + " mUnpluggedTime=" + mUnpluggedTime);
518        }
519
520
521        void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
522            long runTime = computeRunTimeLocked(batteryRealtime);
523            // Divide by 1000 for backwards compatibility
524            out.writeLong((runTime + 500) / 1000);
525            out.writeLong(((runTime - mLoadedTime) + 500) / 1000);
526            out.writeInt(mCount);
527            out.writeInt(mCount - mLoadedCount);
528        }
529
530        void readSummaryFromParcelLocked(Parcel in) {
531            // Multiply by 1000 for backwards compatibility
532            mTotalTime = mLoadedTime = in.readLong() * 1000;
533            mLastTime = in.readLong() * 1000;
534            mUnpluggedTime = mTotalTime;
535            mCount = mLoadedCount = in.readInt();
536            mLastCount = in.readInt();
537            mUnpluggedCount = mCount;
538        }
539    }
540
541    public static final class SamplingTimer extends Timer {
542
543        /**
544         * The most recent reported count from /proc/wakelocks.
545         */
546        int mCurrentReportedCount;
547
548        /**
549         * The reported count from /proc/wakelocks when unplug() was last
550         * called.
551         */
552        int mUnpluggedReportedCount;
553
554        /**
555         * The most recent reported total_time from /proc/wakelocks.
556         */
557        long mCurrentReportedTotalTime;
558
559
560        /**
561         * The reported total_time from /proc/wakelocks when unplug() was last
562         * called.
563         */
564        long mUnpluggedReportedTotalTime;
565
566        /**
567         * Whether we are currently in a discharge cycle.
568         */
569        boolean mInDischarge;
570
571        /**
572         * Whether we are currently recording reported values.
573         */
574        boolean mTrackingReportedValues;
575
576        /*
577         * A sequnce counter, incremented once for each update of the stats.
578         */
579        int mUpdateVersion;
580
581        SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge, Parcel in) {
582            super(0, unpluggables, in);
583            mCurrentReportedCount = in.readInt();
584            mUnpluggedReportedCount = in.readInt();
585            mCurrentReportedTotalTime = in.readLong();
586            mUnpluggedReportedTotalTime = in.readLong();
587            mTrackingReportedValues = in.readInt() == 1;
588            mInDischarge = inDischarge;
589        }
590
591        SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge,
592                boolean trackReportedValues) {
593            super(0, unpluggables);
594            mTrackingReportedValues = trackReportedValues;
595            mInDischarge = inDischarge;
596        }
597
598        public void setStale() {
599            mTrackingReportedValues = false;
600            mUnpluggedReportedTotalTime = 0;
601            mUnpluggedReportedCount = 0;
602        }
603
604        public void setUpdateVersion(int version) {
605            mUpdateVersion = version;
606        }
607
608        public int getUpdateVersion() {
609            return mUpdateVersion;
610        }
611
612        public void updateCurrentReportedCount(int count) {
613            if (mInDischarge && mUnpluggedReportedCount == 0) {
614                // Updating the reported value for the first time.
615                mUnpluggedReportedCount = count;
616                // If we are receiving an update update mTrackingReportedValues;
617                mTrackingReportedValues = true;
618            }
619            mCurrentReportedCount = count;
620        }
621
622        public void updateCurrentReportedTotalTime(long totalTime) {
623            if (mInDischarge && mUnpluggedReportedTotalTime == 0) {
624                // Updating the reported value for the first time.
625                mUnpluggedReportedTotalTime = totalTime;
626                // If we are receiving an update update mTrackingReportedValues;
627                mTrackingReportedValues = true;
628            }
629            mCurrentReportedTotalTime = totalTime;
630        }
631
632        public void unplug(long batteryUptime, long batteryRealtime) {
633            super.unplug(batteryUptime, batteryRealtime);
634            if (mTrackingReportedValues) {
635                mUnpluggedReportedTotalTime = mCurrentReportedTotalTime;
636                mUnpluggedReportedCount = mCurrentReportedCount;
637            }
638            mInDischarge = true;
639        }
640
641        public void plug(long batteryUptime, long batteryRealtime) {
642            super.plug(batteryUptime, batteryRealtime);
643            mInDischarge = false;
644        }
645
646        public void logState(Printer pw, String prefix) {
647            super.logState(pw, prefix);
648            pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount
649                    + " mUnpluggedReportedCount=" + mUnpluggedReportedCount
650                    + " mCurrentReportedTotalTime=" + mCurrentReportedTotalTime
651                    + " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTime);
652        }
653
654        protected long computeRunTimeLocked(long curBatteryRealtime) {
655            return mTotalTime + (mInDischarge && mTrackingReportedValues
656                    ? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0);
657        }
658
659        protected int computeCurrentCountLocked() {
660            return mCount + (mInDischarge && mTrackingReportedValues
661                    ? mCurrentReportedCount - mUnpluggedReportedCount : 0);
662        }
663
664        public void writeToParcel(Parcel out, long batteryRealtime) {
665            super.writeToParcel(out, batteryRealtime);
666            out.writeInt(mCurrentReportedCount);
667            out.writeInt(mUnpluggedReportedCount);
668            out.writeLong(mCurrentReportedTotalTime);
669            out.writeLong(mUnpluggedReportedTotalTime);
670            out.writeInt(mTrackingReportedValues ? 1 : 0);
671        }
672
673        void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
674            super.writeSummaryFromParcelLocked(out, batteryRealtime);
675            out.writeLong(mCurrentReportedTotalTime);
676            out.writeInt(mCurrentReportedCount);
677            out.writeInt(mTrackingReportedValues ? 1 : 0);
678        }
679
680        void readSummaryFromParcelLocked(Parcel in) {
681            super.readSummaryFromParcelLocked(in);
682            mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong();
683            mUnpluggedReportedCount = mCurrentReportedCount = in.readInt();
684            mTrackingReportedValues = in.readInt() == 1;
685        }
686    }
687
688    /**
689     * State for keeping track of timing information.
690     */
691    public static final class StopwatchTimer extends Timer {
692        final ArrayList<StopwatchTimer> mTimerPool;
693        int mNesting;
694
695
696        /**
697         * The last time at which we updated the timer.  If mNesting is > 0,
698         * subtract this from the current battery time to find the amount of
699         * time we have been running since we last computed an update.
700         */
701        long mUpdateTime;
702
703        /**
704         * The total time at which the timer was acquired, to determine if
705         * was actually held for an interesting duration.
706         */
707        long mAcquireTime;
708
709        long mTimeout;
710
711        StopwatchTimer(int type, ArrayList<StopwatchTimer> timerPool,
712                ArrayList<Unpluggable> unpluggables, Parcel in) {
713            super(type, unpluggables, in);
714            mTimerPool = timerPool;
715            mUpdateTime = in.readLong();
716        }
717
718        StopwatchTimer(int type, ArrayList<StopwatchTimer> timerPool,
719                ArrayList<Unpluggable> unpluggables) {
720            super(type, unpluggables);
721            mTimerPool = timerPool;
722        }
723
724        void setTimeout(long timeout) {
725            mTimeout = timeout;
726        }
727
728        public void writeToParcel(Parcel out, long batteryRealtime) {
729            super.writeToParcel(out, batteryRealtime);
730            out.writeLong(mUpdateTime);
731        }
732
733        public void plug(long batteryUptime, long batteryRealtime) {
734            if (mNesting > 0) {
735                if (DEBUG && mType < 0) {
736                    Log.v(TAG, "old mUpdateTime=" + mUpdateTime);
737                }
738                super.plug(batteryUptime, batteryRealtime);
739                mUpdateTime = batteryRealtime;
740                if (DEBUG && mType < 0) {
741                    Log.v(TAG, "new mUpdateTime=" + mUpdateTime);
742                }
743            }
744        }
745
746        public void logState(Printer pw, String prefix) {
747            super.logState(pw, prefix);
748            pw.println(prefix + "mNesting=" + mNesting + "mUpdateTime=" + mUpdateTime
749                    + " mAcquireTime=" + mAcquireTime);
750        }
751
752        void startRunningLocked(BatteryStatsImpl stats) {
753            if (mNesting++ == 0) {
754                mUpdateTime = stats.getBatteryRealtimeLocked(
755                        SystemClock.elapsedRealtime() * 1000);
756                if (mTimerPool != null) {
757                    // Accumulate time to all currently active timers before adding
758                    // this new one to the pool.
759                    refreshTimersLocked(stats, mTimerPool);
760                    // Add this timer to the active pool
761                    mTimerPool.add(this);
762                }
763                // Increment the count
764                mCount++;
765                mAcquireTime = mTotalTime;
766                if (DEBUG && mType < 0) {
767                    Log.v(TAG, "start #" + mType + ": mUpdateTime=" + mUpdateTime
768                            + " mTotalTime=" + mTotalTime + " mCount=" + mCount
769                            + " mAcquireTime=" + mAcquireTime);
770                }
771            }
772        }
773
774        boolean isRunningLocked() {
775            return mNesting > 0;
776        }
777
778        void stopRunningLocked(BatteryStatsImpl stats) {
779            // Ignore attempt to stop a timer that isn't running
780            if (mNesting == 0) {
781                return;
782            }
783            if (--mNesting == 0) {
784                if (mTimerPool != null) {
785                    // Accumulate time to all active counters, scaled by the total
786                    // active in the pool, before taking this one out of the pool.
787                    refreshTimersLocked(stats, mTimerPool);
788                    // Remove this timer from the active pool
789                    mTimerPool.remove(this);
790                } else {
791                    final long realtime = SystemClock.elapsedRealtime() * 1000;
792                    final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
793                    mNesting = 1;
794                    mTotalTime = computeRunTimeLocked(batteryRealtime);
795                    mNesting = 0;
796                }
797
798                if (DEBUG && mType < 0) {
799                    Log.v(TAG, "stop #" + mType + ": mUpdateTime=" + mUpdateTime
800                            + " mTotalTime=" + mTotalTime + " mCount=" + mCount
801                            + " mAcquireTime=" + mAcquireTime);
802                }
803
804                if (mTotalTime == mAcquireTime) {
805                    // If there was no change in the time, then discard this
806                    // count.  A somewhat cheezy strategy, but hey.
807                    mCount--;
808                }
809            }
810        }
811
812        // Update the total time for all other running Timers with the same type as this Timer
813        // due to a change in timer count
814        private static void refreshTimersLocked(final BatteryStatsImpl stats,
815                final ArrayList<StopwatchTimer> pool) {
816            final long realtime = SystemClock.elapsedRealtime() * 1000;
817            final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
818            final int N = pool.size();
819            for (int i=N-1; i>= 0; i--) {
820                final StopwatchTimer t = pool.get(i);
821                long heldTime = batteryRealtime - t.mUpdateTime;
822                if (heldTime > 0) {
823                    t.mTotalTime += heldTime / N;
824                }
825                t.mUpdateTime = batteryRealtime;
826            }
827        }
828
829        @Override
830        protected long computeRunTimeLocked(long curBatteryRealtime) {
831            if (mTimeout > 0 && curBatteryRealtime > mUpdateTime + mTimeout) {
832                curBatteryRealtime = mUpdateTime + mTimeout;
833            }
834            return mTotalTime + (mNesting > 0
835                    ? (curBatteryRealtime - mUpdateTime)
836                            / (mTimerPool != null ? mTimerPool.size() : 1)
837                    : 0);
838        }
839
840        @Override
841        protected int computeCurrentCountLocked() {
842            return mCount;
843        }
844
845        void readSummaryFromParcelLocked(Parcel in) {
846            super.readSummaryFromParcelLocked(in);
847            mNesting = 0;
848        }
849    }
850
851    private final Map<String, KernelWakelockStats> readKernelWakelockStats() {
852
853        byte[] buffer = new byte[4096];
854        int len;
855
856        try {
857            FileInputStream is = new FileInputStream("/proc/wakelocks");
858            len = is.read(buffer);
859            is.close();
860
861            if (len > 0) {
862                int i;
863                for (i=0; i<len; i++) {
864                    if (buffer[i] == '\0') {
865                        len = i;
866                        break;
867                    }
868                }
869            }
870        } catch (java.io.FileNotFoundException e) {
871            return null;
872        } catch (java.io.IOException e) {
873            return null;
874        }
875
876        return parseProcWakelocks(buffer, len);
877    }
878
879    private final Map<String, KernelWakelockStats> parseProcWakelocks(
880            byte[] wlBuffer, int len) {
881        String name;
882        int count;
883        long totalTime;
884        int startIndex, endIndex;
885        int numUpdatedWlNames = 0;
886
887        // Advance past the first line.
888        int i;
889        for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++);
890        startIndex = endIndex = i + 1;
891
892        synchronized(this) {
893            Map<String, KernelWakelockStats> m = mProcWakelockFileStats;
894
895            sKernelWakelockUpdateVersion++;
896            while (endIndex < len) {
897                for (endIndex=startIndex;
898                        endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
899                        endIndex++);
900                // Don't go over the end of the buffer
901                if (endIndex < len) {
902                    endIndex++; // endIndex is an exclusive upper bound.
903                }
904
905                String[] nameStringArray = mProcWakelocksName;
906                long[] wlData = mProcWakelocksData;
907                // Stomp out any bad characters since this is from a circular buffer
908                // A corruption is seen sometimes that results in the vm crashing
909                // This should prevent crashes and the line will probably fail to parse
910                for (int j = startIndex; j < endIndex; j++) {
911                    if ((wlBuffer[j] & 0x80) != 0) wlBuffer[j] = (byte) '?';
912                }
913                boolean parsed = Process.parseProcLine(wlBuffer, startIndex, endIndex,
914                        PROC_WAKELOCKS_FORMAT, nameStringArray, wlData, null);
915
916                name = nameStringArray[0];
917                count = (int) wlData[1];
918                // convert nanoseconds to microseconds with rounding.
919                totalTime = (wlData[2] + 500) / 1000;
920
921                if (parsed && name.length() > 0) {
922                    if (!m.containsKey(name)) {
923                        m.put(name, new KernelWakelockStats(count, totalTime,
924                                sKernelWakelockUpdateVersion));
925                        numUpdatedWlNames++;
926                    } else {
927                        KernelWakelockStats kwlStats = m.get(name);
928                        if (kwlStats.mVersion == sKernelWakelockUpdateVersion) {
929                            kwlStats.mCount += count;
930                            kwlStats.mTotalTime += totalTime;
931                        } else {
932                            kwlStats.mCount = count;
933                            kwlStats.mTotalTime = totalTime;
934                            kwlStats.mVersion = sKernelWakelockUpdateVersion;
935                            numUpdatedWlNames++;
936                        }
937                    }
938                }
939                startIndex = endIndex;
940            }
941
942            if (m.size() != numUpdatedWlNames) {
943                // Don't report old data.
944                Iterator<KernelWakelockStats> itr = m.values().iterator();
945                while (itr.hasNext()) {
946                    if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
947                        itr.remove();
948                    }
949                }
950            }
951            return m;
952        }
953    }
954
955    private class KernelWakelockStats {
956        public int mCount;
957        public long mTotalTime;
958        public int mVersion;
959
960        KernelWakelockStats(int count, long totalTime, int version) {
961            mCount = count;
962            mTotalTime = totalTime;
963            mVersion = version;
964        }
965    }
966
967    /*
968     * Get the KernelWakelockTimer associated with name, and create a new one if one
969     * doesn't already exist.
970     */
971    public SamplingTimer getKernelWakelockTimerLocked(String name) {
972        SamplingTimer kwlt = mKernelWakelockStats.get(name);
973        if (kwlt == null) {
974            kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
975                    true /* track reported values */);
976            mKernelWakelockStats.put(name, kwlt);
977        }
978        return kwlt;
979    }
980
981    private void doDataPlug(long[] dataTransfer, long currentBytes) {
982        dataTransfer[STATS_LAST] = dataTransfer[STATS_UNPLUGGED];
983        dataTransfer[STATS_UNPLUGGED] = -1;
984    }
985
986    private void doDataUnplug(long[] dataTransfer, long currentBytes) {
987        dataTransfer[STATS_UNPLUGGED] = currentBytes;
988    }
989
990    /**
991     * Radio uptime in microseconds when transferring data. This value is very approximate.
992     * @return
993     */
994    private long getCurrentRadioDataUptime() {
995        try {
996            File awakeTimeFile = new File("/sys/devices/virtual/net/rmnet0/awake_time_ms");
997            if (!awakeTimeFile.exists()) return 0;
998            BufferedReader br = new BufferedReader(new FileReader(awakeTimeFile));
999            String line = br.readLine();
1000            br.close();
1001            return Long.parseLong(line) * 1000;
1002        } catch (NumberFormatException nfe) {
1003            // Nothing
1004        } catch (IOException ioe) {
1005            // Nothing
1006        }
1007        return 0;
1008    }
1009
1010    /**
1011     * @deprecated use getRadioDataUptime
1012     */
1013    public long getRadioDataUptimeMs() {
1014        return getRadioDataUptime() / 1000;
1015    }
1016
1017    /**
1018     * Returns the duration that the cell radio was up for data transfers.
1019     */
1020    public long getRadioDataUptime() {
1021        if (mRadioDataStart == -1) {
1022            return mRadioDataUptime;
1023        } else {
1024            return getCurrentRadioDataUptime() - mRadioDataStart;
1025        }
1026    }
1027
1028    private int getCurrentBluetoothPingCount() {
1029        if (mBtHeadset != null) {
1030            return mBtHeadset.getBatteryUsageHint();
1031        }
1032        return -1;
1033    }
1034
1035    public int getBluetoothPingCount() {
1036        if (mBluetoothPingStart == -1) {
1037            return mBluetoothPingCount;
1038        } else if (mBtHeadset != null) {
1039            return getCurrentBluetoothPingCount() - mBluetoothPingStart;
1040        }
1041        return 0;
1042    }
1043
1044    public void setBtHeadset(BluetoothHeadset headset) {
1045        if (headset != null && mBtHeadset == null && isOnBattery() && mBluetoothPingStart == -1) {
1046            mBluetoothPingStart = getCurrentBluetoothPingCount();
1047        }
1048        mBtHeadset = headset;
1049    }
1050
1051    void addHistoryRecord(long curTime) {
1052        BatteryHistoryRecord rec = mHistoryCache;
1053        if (rec != null) {
1054            mHistoryCache = rec.next;
1055        } else {
1056            rec = new BatteryHistoryRecord();
1057        }
1058        rec.time = curTime;
1059        rec.batteryLevel = mHistoryCur.batteryLevel;
1060        rec.states = mHistoryCur.states;
1061        addHistoryRecord(rec);
1062    }
1063
1064    void addHistoryRecord(BatteryHistoryRecord rec) {
1065        rec.next = null;
1066        if (mHistoryEnd != null) {
1067            mHistoryEnd.next = rec;
1068            mHistoryEnd = rec;
1069        } else {
1070            mHistory = mHistoryEnd = rec;
1071        }
1072    }
1073
1074    void clearHistory() {
1075        if (mHistory != null) {
1076            mHistoryEnd.next = mHistoryCache;
1077            mHistoryCache = mHistory;
1078            mHistory = mHistoryEnd = null;
1079        }
1080    }
1081
1082    public void doUnplug(long batteryUptime, long batteryRealtime) {
1083        for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
1084            Uid u = mUidStats.valueAt(iu);
1085            u.mStartedTcpBytesReceived = TrafficStats.getUidRxBytes(u.mUid);
1086            u.mStartedTcpBytesSent = TrafficStats.getUidTxBytes(u.mUid);
1087            u.mTcpBytesReceivedAtLastUnplug = u.mCurrentTcpBytesReceived;
1088            u.mTcpBytesSentAtLastUnplug = u.mCurrentTcpBytesSent;
1089        }
1090        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
1091            mUnpluggables.get(i).unplug(batteryUptime, batteryRealtime);
1092        }
1093        // Track total mobile data
1094        doDataUnplug(mMobileDataRx, TrafficStats.getMobileRxBytes());
1095        doDataUnplug(mMobileDataTx, TrafficStats.getMobileTxBytes());
1096        doDataUnplug(mTotalDataRx, TrafficStats.getTotalRxBytes());
1097        doDataUnplug(mTotalDataTx, TrafficStats.getTotalTxBytes());
1098        // Track radio awake time
1099        mRadioDataStart = getCurrentRadioDataUptime();
1100        mRadioDataUptime = 0;
1101        // Track bt headset ping count
1102        mBluetoothPingStart = getCurrentBluetoothPingCount();
1103        mBluetoothPingCount = 0;
1104    }
1105
1106    public void doPlug(long batteryUptime, long batteryRealtime) {
1107        for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
1108            Uid u = mUidStats.valueAt(iu);
1109            if (u.mStartedTcpBytesReceived >= 0) {
1110                u.mCurrentTcpBytesReceived = u.computeCurrentTcpBytesReceived();
1111                u.mStartedTcpBytesReceived = -1;
1112            }
1113            if (u.mStartedTcpBytesSent >= 0) {
1114                u.mCurrentTcpBytesSent = u.computeCurrentTcpBytesSent();
1115                u.mStartedTcpBytesSent = -1;
1116            }
1117        }
1118        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
1119            mUnpluggables.get(i).plug(batteryUptime, batteryRealtime);
1120        }
1121        doDataPlug(mMobileDataRx, TrafficStats.getMobileRxBytes());
1122        doDataPlug(mMobileDataTx, TrafficStats.getMobileTxBytes());
1123        doDataPlug(mTotalDataRx, TrafficStats.getTotalRxBytes());
1124        doDataPlug(mTotalDataTx, TrafficStats.getTotalTxBytes());
1125        // Track radio awake time
1126        mRadioDataUptime = getRadioDataUptime();
1127        mRadioDataStart = -1;
1128
1129        // Track bt headset ping count
1130        mBluetoothPingCount = getBluetoothPingCount();
1131        mBluetoothPingStart = -1;
1132    }
1133
1134    int mGpsNesting;
1135
1136    public void noteStartGps(int uid) {
1137        if (mGpsNesting == 0) {
1138            mHistoryCur.states |= BatteryHistoryRecord.STATE_GPS_ON_FLAG;
1139            if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
1140                    + Integer.toHexString(mHistoryCur.states));
1141            addHistoryRecord(SystemClock.elapsedRealtime());
1142        }
1143        mGpsNesting++;
1144        getUidStatsLocked(uid).noteStartGps();
1145    }
1146
1147    public void noteStopGps(int uid) {
1148        mGpsNesting--;
1149        if (mGpsNesting == 0) {
1150            mHistoryCur.states &= ~BatteryHistoryRecord.STATE_GPS_ON_FLAG;
1151            if (DEBUG_HISTORY) Slog.v(TAG, "Stop GPS to: "
1152                    + Integer.toHexString(mHistoryCur.states));
1153            addHistoryRecord(SystemClock.elapsedRealtime());
1154        }
1155        getUidStatsLocked(uid).noteStopGps();
1156    }
1157
1158    public void noteScreenOnLocked() {
1159        if (!mScreenOn) {
1160            mHistoryCur.states |= BatteryHistoryRecord.STATE_SCREEN_ON_FLAG;
1161            if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
1162                    + Integer.toHexString(mHistoryCur.states));
1163            addHistoryRecord(SystemClock.elapsedRealtime());
1164            mGpsNesting++;
1165            mScreenOn = true;
1166            mScreenOnTimer.startRunningLocked(this);
1167            if (mScreenBrightnessBin >= 0) {
1168                mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
1169            }
1170        }
1171    }
1172
1173    public void noteScreenOffLocked() {
1174        if (mScreenOn) {
1175            mHistoryCur.states &= ~BatteryHistoryRecord.STATE_SCREEN_ON_FLAG;
1176            if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
1177                    + Integer.toHexString(mHistoryCur.states));
1178            addHistoryRecord(SystemClock.elapsedRealtime());
1179            mScreenOn = false;
1180            mScreenOnTimer.stopRunningLocked(this);
1181            if (mScreenBrightnessBin >= 0) {
1182                mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
1183            }
1184        }
1185    }
1186
1187    public void noteScreenBrightnessLocked(int brightness) {
1188        // Bin the brightness.
1189        int bin = brightness / (256/NUM_SCREEN_BRIGHTNESS_BINS);
1190        if (bin < 0) bin = 0;
1191        else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
1192        if (mScreenBrightnessBin != bin) {
1193            mHistoryCur.states = (mHistoryCur.states&~BatteryHistoryRecord.STATE_SCREEN_MASK)
1194                    | (bin << BatteryHistoryRecord.STATE_SCREEN_SHIFT);
1195            if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
1196                    + Integer.toHexString(mHistoryCur.states));
1197            addHistoryRecord(SystemClock.elapsedRealtime());
1198            if (mScreenOn) {
1199                if (mScreenBrightnessBin >= 0) {
1200                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
1201                }
1202                mScreenBrightnessTimer[bin].startRunningLocked(this);
1203            }
1204            mScreenBrightnessBin = bin;
1205        }
1206    }
1207
1208    public void noteInputEventAtomic() {
1209        mInputEventCounter.stepAtomic();
1210    }
1211
1212    public void noteUserActivityLocked(int uid, int event) {
1213        getUidStatsLocked(uid).noteUserActivityLocked(event);
1214    }
1215
1216    public void notePhoneOnLocked() {
1217        if (!mPhoneOn) {
1218            mHistoryCur.states |= BatteryHistoryRecord.STATE_PHONE_ON_FLAG;
1219            if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
1220                    + Integer.toHexString(mHistoryCur.states));
1221            addHistoryRecord(SystemClock.elapsedRealtime());
1222            mPhoneOn = true;
1223            mPhoneOnTimer.startRunningLocked(this);
1224        }
1225    }
1226
1227    public void notePhoneOffLocked() {
1228        if (mPhoneOn) {
1229            mHistoryCur.states &= ~BatteryHistoryRecord.STATE_PHONE_ON_FLAG;
1230            if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
1231                    + Integer.toHexString(mHistoryCur.states));
1232            addHistoryRecord(SystemClock.elapsedRealtime());
1233            mPhoneOn = false;
1234            mPhoneOnTimer.stopRunningLocked(this);
1235        }
1236    }
1237
1238    /**
1239     * Telephony stack updates the phone state.
1240     * @param state phone state from ServiceState.getState()
1241     */
1242    public void notePhoneStateLocked(int state) {
1243        int bin = mPhoneSignalStrengthBin;
1244        boolean isAirplaneMode = state == ServiceState.STATE_POWER_OFF;
1245        // Stop all timers
1246        if (isAirplaneMode || state == ServiceState.STATE_OUT_OF_SERVICE) {
1247            for (int i = 0; i < NUM_SIGNAL_STRENGTH_BINS; i++) {
1248                while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
1249                    mPhoneSignalStrengthsTimer[i].stopRunningLocked(this);
1250                }
1251            }
1252        }
1253        // Stop Signal Scanning timer, in case we're going into service
1254        while (mPhoneSignalScanningTimer.isRunningLocked()) {
1255            mPhoneSignalScanningTimer.stopRunningLocked(this);
1256        }
1257
1258        // If we're back in service or continuing in service, restart the old timer.
1259        if (state == ServiceState.STATE_IN_SERVICE) {
1260            if (bin == -1) bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1261            if (!mPhoneSignalStrengthsTimer[bin].isRunningLocked()) {
1262                mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
1263            }
1264        } else if (state == ServiceState.STATE_OUT_OF_SERVICE) {
1265            mPhoneSignalStrengthBin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1266            if (!mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].isRunningLocked()) {
1267                mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].startRunningLocked(this);
1268            }
1269            if (!mPhoneSignalScanningTimer.isRunningLocked()) {
1270                mPhoneSignalScanningTimer.startRunningLocked(this);
1271            }
1272        }
1273
1274        if (mPhoneServiceState != state) {
1275            mHistoryCur.states = (mHistoryCur.states&~BatteryHistoryRecord.STATE_PHONE_STATE_MASK)
1276                    | (state << BatteryHistoryRecord.STATE_PHONE_STATE_SHIFT);
1277            if (DEBUG_HISTORY) Slog.v(TAG, "Phone state " + bin + " to: "
1278                    + Integer.toHexString(mHistoryCur.states));
1279            addHistoryRecord(SystemClock.elapsedRealtime());
1280            mPhoneServiceState = state;
1281        }
1282    }
1283
1284    public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
1285        // Bin the strength.
1286        int bin;
1287        if (mPhoneServiceState == ServiceState.STATE_POWER_OFF
1288                || mPhoneServiceState == ServiceState.STATE_OUT_OF_SERVICE) {
1289            // Ignore any signal strength changes when radio was turned off or out of service.
1290            return;
1291        }
1292        if (!signalStrength.isGsm()) {
1293            int dBm = signalStrength.getCdmaDbm();
1294            if (dBm >= -75) bin = SIGNAL_STRENGTH_GREAT;
1295            else if (dBm >= -85) bin = SIGNAL_STRENGTH_GOOD;
1296            else if (dBm >= -95)  bin = SIGNAL_STRENGTH_MODERATE;
1297            else if (dBm >= -100)  bin = SIGNAL_STRENGTH_POOR;
1298            else bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1299        } else {
1300            int asu = signalStrength.getGsmSignalStrength();
1301            if (asu < 0 || asu >= 99) bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1302            else if (asu >= 16) bin = SIGNAL_STRENGTH_GREAT;
1303            else if (asu >= 8)  bin = SIGNAL_STRENGTH_GOOD;
1304            else if (asu >= 4)  bin = SIGNAL_STRENGTH_MODERATE;
1305            else bin = SIGNAL_STRENGTH_POOR;
1306        }
1307        if (mPhoneSignalStrengthBin != bin) {
1308            mHistoryCur.states = (mHistoryCur.states&~BatteryHistoryRecord.STATE_SIGNAL_STRENGTH_MASK)
1309                    | (bin << BatteryHistoryRecord.STATE_SIGNAL_STRENGTH_SHIFT);
1310            if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + bin + " to: "
1311                    + Integer.toHexString(mHistoryCur.states));
1312            addHistoryRecord(SystemClock.elapsedRealtime());
1313            if (mPhoneSignalStrengthBin >= 0) {
1314                mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this);
1315            }
1316            mPhoneSignalStrengthBin = bin;
1317            mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
1318        }
1319    }
1320
1321    public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData) {
1322        int bin = DATA_CONNECTION_NONE;
1323        if (hasData) {
1324            switch (dataType) {
1325                case TelephonyManager.NETWORK_TYPE_EDGE:
1326                    bin = DATA_CONNECTION_EDGE;
1327                    break;
1328                case TelephonyManager.NETWORK_TYPE_GPRS:
1329                    bin = DATA_CONNECTION_GPRS;
1330                    break;
1331                case TelephonyManager.NETWORK_TYPE_UMTS:
1332                    bin = DATA_CONNECTION_UMTS;
1333                    break;
1334                default:
1335                    bin = DATA_CONNECTION_OTHER;
1336                    break;
1337            }
1338        }
1339        if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
1340        if (mPhoneDataConnectionType != bin) {
1341            mHistoryCur.states = (mHistoryCur.states&~BatteryHistoryRecord.STATE_DATA_CONNECTION_MASK)
1342                    | (bin << BatteryHistoryRecord.STATE_DATA_CONNECTION_SHIFT);
1343            if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
1344                    + Integer.toHexString(mHistoryCur.states));
1345            addHistoryRecord(SystemClock.elapsedRealtime());
1346            if (mPhoneDataConnectionType >= 0) {
1347                mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this);
1348            }
1349            mPhoneDataConnectionType = bin;
1350            mPhoneDataConnectionsTimer[bin].startRunningLocked(this);
1351        }
1352    }
1353
1354    public void noteWifiOnLocked(int uid) {
1355        if (!mWifiOn) {
1356            mHistoryCur.states |= BatteryHistoryRecord.STATE_WIFI_ON_FLAG;
1357            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
1358                    + Integer.toHexString(mHistoryCur.states));
1359            addHistoryRecord(SystemClock.elapsedRealtime());
1360            mWifiOn = true;
1361            mWifiOnTimer.startRunningLocked(this);
1362        }
1363        if (mWifiOnUid != uid) {
1364            if (mWifiOnUid >= 0) {
1365                getUidStatsLocked(mWifiOnUid).noteWifiTurnedOffLocked();
1366            }
1367            mWifiOnUid = uid;
1368            getUidStatsLocked(uid).noteWifiTurnedOnLocked();
1369        }
1370    }
1371
1372    public void noteWifiOffLocked(int uid) {
1373        if (mWifiOn) {
1374            mHistoryCur.states &= ~BatteryHistoryRecord.STATE_WIFI_ON_FLAG;
1375            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
1376                    + Integer.toHexString(mHistoryCur.states));
1377            addHistoryRecord(SystemClock.elapsedRealtime());
1378            mWifiOn = false;
1379            mWifiOnTimer.stopRunningLocked(this);
1380        }
1381        if (mWifiOnUid >= 0) {
1382            getUidStatsLocked(mWifiOnUid).noteWifiTurnedOffLocked();
1383            mWifiOnUid = -1;
1384        }
1385    }
1386
1387    public void noteAudioOnLocked(int uid) {
1388        if (!mAudioOn) {
1389            mHistoryCur.states |= BatteryHistoryRecord.STATE_AUDIO_ON_FLAG;
1390            if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
1391                    + Integer.toHexString(mHistoryCur.states));
1392            addHistoryRecord(SystemClock.elapsedRealtime());
1393            mAudioOn = true;
1394            mAudioOnTimer.startRunningLocked(this);
1395        }
1396        getUidStatsLocked(uid).noteAudioTurnedOnLocked();
1397    }
1398
1399    public void noteAudioOffLocked(int uid) {
1400        if (mAudioOn) {
1401            mHistoryCur.states &= ~BatteryHistoryRecord.STATE_AUDIO_ON_FLAG;
1402            if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
1403                    + Integer.toHexString(mHistoryCur.states));
1404            addHistoryRecord(SystemClock.elapsedRealtime());
1405            mAudioOn = false;
1406            mAudioOnTimer.stopRunningLocked(this);
1407        }
1408        getUidStatsLocked(uid).noteAudioTurnedOffLocked();
1409    }
1410
1411    public void noteVideoOnLocked(int uid) {
1412        if (!mVideoOn) {
1413            mHistoryCur.states |= BatteryHistoryRecord.STATE_VIDEO_ON_FLAG;
1414            if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
1415                    + Integer.toHexString(mHistoryCur.states));
1416            addHistoryRecord(SystemClock.elapsedRealtime());
1417            mVideoOn = true;
1418            mVideoOnTimer.startRunningLocked(this);
1419        }
1420        getUidStatsLocked(uid).noteVideoTurnedOnLocked();
1421    }
1422
1423    public void noteVideoOffLocked(int uid) {
1424        if (mVideoOn) {
1425            mHistoryCur.states &= ~BatteryHistoryRecord.STATE_VIDEO_ON_FLAG;
1426            if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
1427                    + Integer.toHexString(mHistoryCur.states));
1428            addHistoryRecord(SystemClock.elapsedRealtime());
1429            mVideoOn = false;
1430            mVideoOnTimer.stopRunningLocked(this);
1431        }
1432        getUidStatsLocked(uid).noteVideoTurnedOffLocked();
1433    }
1434
1435    public void noteWifiRunningLocked() {
1436        if (!mWifiRunning) {
1437            mHistoryCur.states |= BatteryHistoryRecord.STATE_WIFI_RUNNING_FLAG;
1438            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
1439                    + Integer.toHexString(mHistoryCur.states));
1440            addHistoryRecord(SystemClock.elapsedRealtime());
1441            mWifiRunning = true;
1442            mWifiRunningTimer.startRunningLocked(this);
1443        }
1444    }
1445
1446    public void noteWifiStoppedLocked() {
1447        if (mWifiRunning) {
1448            mHistoryCur.states &= ~BatteryHistoryRecord.STATE_WIFI_RUNNING_FLAG;
1449            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
1450                    + Integer.toHexString(mHistoryCur.states));
1451            addHistoryRecord(SystemClock.elapsedRealtime());
1452            mWifiRunning = false;
1453            mWifiRunningTimer.stopRunningLocked(this);
1454        }
1455    }
1456
1457    public void noteBluetoothOnLocked() {
1458        if (!mBluetoothOn) {
1459            mHistoryCur.states |= BatteryHistoryRecord.STATE_BLUETOOTH_ON_FLAG;
1460            if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth on to: "
1461                    + Integer.toHexString(mHistoryCur.states));
1462            addHistoryRecord(SystemClock.elapsedRealtime());
1463            mBluetoothOn = true;
1464            mBluetoothOnTimer.startRunningLocked(this);
1465        }
1466    }
1467
1468    public void noteBluetoothOffLocked() {
1469        if (mBluetoothOn) {
1470            mHistoryCur.states &= ~BatteryHistoryRecord.STATE_BLUETOOTH_ON_FLAG;
1471            if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth off to: "
1472                    + Integer.toHexString(mHistoryCur.states));
1473            addHistoryRecord(SystemClock.elapsedRealtime());
1474            mBluetoothOn = false;
1475            mBluetoothOnTimer.stopRunningLocked(this);
1476        }
1477    }
1478
1479    int mWifiFullLockNesting = 0;
1480
1481    public void noteFullWifiLockAcquiredLocked(int uid) {
1482        if (mWifiFullLockNesting == 0) {
1483            mHistoryCur.states |= BatteryHistoryRecord.STATE_WIFI_FULL_LOCK_FLAG;
1484            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
1485                    + Integer.toHexString(mHistoryCur.states));
1486            addHistoryRecord(SystemClock.elapsedRealtime());
1487        }
1488        mWifiFullLockNesting++;
1489        getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
1490    }
1491
1492    public void noteFullWifiLockReleasedLocked(int uid) {
1493        mWifiFullLockNesting--;
1494        if (mWifiFullLockNesting == 0) {
1495            mHistoryCur.states &= ~BatteryHistoryRecord.STATE_WIFI_FULL_LOCK_FLAG;
1496            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
1497                    + Integer.toHexString(mHistoryCur.states));
1498            addHistoryRecord(SystemClock.elapsedRealtime());
1499        }
1500        getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
1501    }
1502
1503    int mWifiScanLockNesting = 0;
1504
1505    public void noteScanWifiLockAcquiredLocked(int uid) {
1506        if (mWifiScanLockNesting == 0) {
1507            mHistoryCur.states |= BatteryHistoryRecord.STATE_WIFI_SCAN_LOCK_FLAG;
1508            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock on to: "
1509                    + Integer.toHexString(mHistoryCur.states));
1510            addHistoryRecord(SystemClock.elapsedRealtime());
1511        }
1512        mWifiScanLockNesting++;
1513        getUidStatsLocked(uid).noteScanWifiLockAcquiredLocked();
1514    }
1515
1516    public void noteScanWifiLockReleasedLocked(int uid) {
1517        mWifiScanLockNesting--;
1518        if (mWifiScanLockNesting == 0) {
1519            mHistoryCur.states &= ~BatteryHistoryRecord.STATE_WIFI_SCAN_LOCK_FLAG;
1520            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock off to: "
1521                    + Integer.toHexString(mHistoryCur.states));
1522            addHistoryRecord(SystemClock.elapsedRealtime());
1523        }
1524        getUidStatsLocked(uid).noteScanWifiLockReleasedLocked();
1525    }
1526
1527    int mWifiMulticastNesting = 0;
1528
1529    public void noteWifiMulticastEnabledLocked(int uid) {
1530        if (mWifiMulticastNesting == 0) {
1531            mHistoryCur.states |= BatteryHistoryRecord.STATE_WIFI_MULTICAST_ON_FLAG;
1532            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
1533                    + Integer.toHexString(mHistoryCur.states));
1534            addHistoryRecord(SystemClock.elapsedRealtime());
1535        }
1536        mWifiMulticastNesting++;
1537        getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
1538    }
1539
1540    public void noteWifiMulticastDisabledLocked(int uid) {
1541        mWifiMulticastNesting--;
1542        if (mWifiMulticastNesting == 0) {
1543            mHistoryCur.states &= ~BatteryHistoryRecord.STATE_WIFI_MULTICAST_ON_FLAG;
1544            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
1545                    + Integer.toHexString(mHistoryCur.states));
1546            addHistoryRecord(SystemClock.elapsedRealtime());
1547        }
1548        getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
1549    }
1550
1551    @Override public long getScreenOnTime(long batteryRealtime, int which) {
1552        return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
1553    }
1554
1555    @Override public long getScreenBrightnessTime(int brightnessBin,
1556            long batteryRealtime, int which) {
1557        return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
1558                batteryRealtime, which);
1559    }
1560
1561    @Override public int getInputEventCount(int which) {
1562        return mInputEventCounter.getCountLocked(which);
1563    }
1564
1565    @Override public long getPhoneOnTime(long batteryRealtime, int which) {
1566        return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
1567    }
1568
1569    @Override public long getPhoneSignalStrengthTime(int strengthBin,
1570            long batteryRealtime, int which) {
1571        return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
1572                batteryRealtime, which);
1573    }
1574
1575    @Override public long getPhoneSignalScanningTime(
1576            long batteryRealtime, int which) {
1577        return mPhoneSignalScanningTimer.getTotalTimeLocked(
1578                batteryRealtime, which);
1579    }
1580
1581    @Override public int getPhoneSignalStrengthCount(int dataType, int which) {
1582        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
1583    }
1584
1585    @Override public long getPhoneDataConnectionTime(int dataType,
1586            long batteryRealtime, int which) {
1587        return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
1588                batteryRealtime, which);
1589    }
1590
1591    @Override public int getPhoneDataConnectionCount(int dataType, int which) {
1592        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
1593    }
1594
1595    @Override public long getWifiOnTime(long batteryRealtime, int which) {
1596        return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
1597    }
1598
1599    @Override public long getWifiRunningTime(long batteryRealtime, int which) {
1600        return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
1601    }
1602
1603    @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
1604        return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
1605    }
1606
1607    @Override public boolean getIsOnBattery() {
1608        return mOnBattery;
1609    }
1610
1611    @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
1612        return mUidStats;
1613    }
1614
1615    /**
1616     * The statistics associated with a particular uid.
1617     */
1618    public final class Uid extends BatteryStats.Uid {
1619
1620        final int mUid;
1621        long mLoadedTcpBytesReceived;
1622        long mLoadedTcpBytesSent;
1623        long mCurrentTcpBytesReceived;
1624        long mCurrentTcpBytesSent;
1625        long mTcpBytesReceivedAtLastUnplug;
1626        long mTcpBytesSentAtLastUnplug;
1627
1628        // These are not saved/restored when parcelling, since we want
1629        // to return from the parcel with a snapshot of the state.
1630        long mStartedTcpBytesReceived = -1;
1631        long mStartedTcpBytesSent = -1;
1632
1633        boolean mWifiTurnedOn;
1634        StopwatchTimer mWifiTurnedOnTimer;
1635
1636        boolean mFullWifiLockOut;
1637        StopwatchTimer mFullWifiLockTimer;
1638
1639        boolean mScanWifiLockOut;
1640        StopwatchTimer mScanWifiLockTimer;
1641
1642        boolean mWifiMulticastEnabled;
1643        StopwatchTimer mWifiMulticastTimer;
1644
1645        boolean mAudioTurnedOn;
1646        StopwatchTimer mAudioTurnedOnTimer;
1647
1648        boolean mVideoTurnedOn;
1649        StopwatchTimer mVideoTurnedOnTimer;
1650
1651        Counter[] mUserActivityCounters;
1652
1653        /**
1654         * The statistics we have collected for this uid's wake locks.
1655         */
1656        final HashMap<String, Wakelock> mWakelockStats = new HashMap<String, Wakelock>();
1657
1658        /**
1659         * The statistics we have collected for this uid's sensor activations.
1660         */
1661        final HashMap<Integer, Sensor> mSensorStats = new HashMap<Integer, Sensor>();
1662
1663        /**
1664         * The statistics we have collected for this uid's processes.
1665         */
1666        final HashMap<String, Proc> mProcessStats = new HashMap<String, Proc>();
1667
1668        /**
1669         * The statistics we have collected for this uid's processes.
1670         */
1671        final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
1672
1673        public Uid(int uid) {
1674            mUid = uid;
1675            mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables);
1676            mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables);
1677            mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables);
1678            mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
1679                    null, mUnpluggables);
1680            mAudioTurnedOnTimer = new StopwatchTimer(AUDIO_TURNED_ON, null, mUnpluggables);
1681            mVideoTurnedOnTimer = new StopwatchTimer(VIDEO_TURNED_ON, null, mUnpluggables);
1682        }
1683
1684        @Override
1685        public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
1686            return mWakelockStats;
1687        }
1688
1689        @Override
1690        public Map<Integer, ? extends BatteryStats.Uid.Sensor> getSensorStats() {
1691            return mSensorStats;
1692        }
1693
1694        @Override
1695        public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
1696            return mProcessStats;
1697        }
1698
1699        @Override
1700        public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
1701            return mPackageStats;
1702        }
1703
1704        @Override
1705        public int getUid() {
1706            return mUid;
1707        }
1708
1709        @Override
1710        public long getTcpBytesReceived(int which) {
1711            if (which == STATS_LAST) {
1712                return mLoadedTcpBytesReceived;
1713            } else {
1714                long current = computeCurrentTcpBytesReceived();
1715                if (which == STATS_UNPLUGGED) {
1716                    current -= mTcpBytesReceivedAtLastUnplug;
1717                } else if (which == STATS_TOTAL) {
1718                    current += mLoadedTcpBytesReceived;
1719                }
1720                return current;
1721            }
1722        }
1723
1724        public long computeCurrentTcpBytesReceived() {
1725            return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
1726                    ? (TrafficStats.getUidRxBytes(mUid) - mStartedTcpBytesReceived) : 0);
1727        }
1728
1729        @Override
1730        public long getTcpBytesSent(int which) {
1731            if (which == STATS_LAST) {
1732                return mLoadedTcpBytesSent;
1733            } else {
1734                long current = computeCurrentTcpBytesSent();
1735                if (which == STATS_UNPLUGGED) {
1736                    current -= mTcpBytesSentAtLastUnplug;
1737                } else if (which == STATS_TOTAL) {
1738                    current += mLoadedTcpBytesSent;
1739                }
1740                return current;
1741            }
1742        }
1743
1744        @Override
1745        public void noteWifiTurnedOnLocked() {
1746            if (!mWifiTurnedOn) {
1747                mWifiTurnedOn = true;
1748                mWifiTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
1749            }
1750        }
1751
1752        @Override
1753        public void noteWifiTurnedOffLocked() {
1754            if (mWifiTurnedOn) {
1755                mWifiTurnedOn = false;
1756                mWifiTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
1757            }
1758        }
1759
1760        @Override
1761        public void noteFullWifiLockAcquiredLocked() {
1762            if (!mFullWifiLockOut) {
1763                mFullWifiLockOut = true;
1764                mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
1765            }
1766        }
1767
1768        @Override
1769        public void noteVideoTurnedOnLocked() {
1770            if (!mVideoTurnedOn) {
1771                mVideoTurnedOn = true;
1772                mVideoTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
1773            }
1774        }
1775
1776        @Override
1777        public void noteVideoTurnedOffLocked() {
1778            if (mVideoTurnedOn) {
1779                mVideoTurnedOn = false;
1780                mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
1781            }
1782        }
1783
1784        @Override
1785        public void noteAudioTurnedOnLocked() {
1786            if (!mAudioTurnedOn) {
1787                mAudioTurnedOn = true;
1788                mAudioTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
1789            }
1790        }
1791
1792        @Override
1793        public void noteAudioTurnedOffLocked() {
1794            if (mAudioTurnedOn) {
1795                mAudioTurnedOn = false;
1796                mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
1797            }
1798        }
1799
1800        @Override
1801        public void noteFullWifiLockReleasedLocked() {
1802            if (mFullWifiLockOut) {
1803                mFullWifiLockOut = false;
1804                mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
1805            }
1806        }
1807
1808        @Override
1809        public void noteScanWifiLockAcquiredLocked() {
1810            if (!mScanWifiLockOut) {
1811                mScanWifiLockOut = true;
1812                mScanWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
1813            }
1814        }
1815
1816        @Override
1817        public void noteScanWifiLockReleasedLocked() {
1818            if (mScanWifiLockOut) {
1819                mScanWifiLockOut = false;
1820                mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
1821            }
1822        }
1823
1824        @Override
1825        public void noteWifiMulticastEnabledLocked() {
1826            if (!mWifiMulticastEnabled) {
1827                mWifiMulticastEnabled = true;
1828                mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
1829            }
1830        }
1831
1832        @Override
1833        public void noteWifiMulticastDisabledLocked() {
1834            if (mWifiMulticastEnabled) {
1835                mWifiMulticastEnabled = false;
1836                mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
1837            }
1838        }
1839
1840        @Override
1841        public long getWifiTurnedOnTime(long batteryRealtime, int which) {
1842            return mWifiTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
1843        }
1844
1845        @Override
1846        public long getAudioTurnedOnTime(long batteryRealtime, int which) {
1847            return mAudioTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
1848        }
1849
1850        @Override
1851        public long getVideoTurnedOnTime(long batteryRealtime, int which) {
1852            return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
1853        }
1854
1855        @Override
1856        public long getFullWifiLockTime(long batteryRealtime, int which) {
1857            return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
1858        }
1859
1860        @Override
1861        public long getScanWifiLockTime(long batteryRealtime, int which) {
1862            return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
1863        }
1864
1865        @Override
1866        public long getWifiMulticastTime(long batteryRealtime, int which) {
1867            return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime,
1868                                                          which);
1869        }
1870
1871        @Override
1872        public void noteUserActivityLocked(int type) {
1873            if (mUserActivityCounters == null) {
1874                initUserActivityLocked();
1875            }
1876            if (type < 0) type = 0;
1877            else if (type >= NUM_USER_ACTIVITY_TYPES) type = NUM_USER_ACTIVITY_TYPES-1;
1878            mUserActivityCounters[type].stepAtomic();
1879        }
1880
1881        @Override
1882        public boolean hasUserActivity() {
1883            return mUserActivityCounters != null;
1884        }
1885
1886        @Override
1887        public int getUserActivityCount(int type, int which) {
1888            if (mUserActivityCounters == null) {
1889                return 0;
1890            }
1891            return mUserActivityCounters[type].getCountLocked(which);
1892        }
1893
1894        void initUserActivityLocked() {
1895            mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
1896            for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
1897                mUserActivityCounters[i] = new Counter(mUnpluggables);
1898            }
1899        }
1900
1901        public long computeCurrentTcpBytesSent() {
1902            return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
1903                    ? (TrafficStats.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
1904        }
1905
1906        void writeToParcelLocked(Parcel out, long batteryRealtime) {
1907            out.writeInt(mWakelockStats.size());
1908            for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
1909                out.writeString(wakelockEntry.getKey());
1910                Uid.Wakelock wakelock = wakelockEntry.getValue();
1911                wakelock.writeToParcelLocked(out, batteryRealtime);
1912            }
1913
1914            out.writeInt(mSensorStats.size());
1915            for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
1916                out.writeInt(sensorEntry.getKey());
1917                Uid.Sensor sensor = sensorEntry.getValue();
1918                sensor.writeToParcelLocked(out, batteryRealtime);
1919            }
1920
1921            out.writeInt(mProcessStats.size());
1922            for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
1923                out.writeString(procEntry.getKey());
1924                Uid.Proc proc = procEntry.getValue();
1925                proc.writeToParcelLocked(out);
1926            }
1927
1928            out.writeInt(mPackageStats.size());
1929            for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
1930                out.writeString(pkgEntry.getKey());
1931                Uid.Pkg pkg = pkgEntry.getValue();
1932                pkg.writeToParcelLocked(out);
1933            }
1934
1935            out.writeLong(mLoadedTcpBytesReceived);
1936            out.writeLong(mLoadedTcpBytesSent);
1937            out.writeLong(computeCurrentTcpBytesReceived());
1938            out.writeLong(computeCurrentTcpBytesSent());
1939            out.writeLong(mTcpBytesReceivedAtLastUnplug);
1940            out.writeLong(mTcpBytesSentAtLastUnplug);
1941            mWifiTurnedOnTimer.writeToParcel(out, batteryRealtime);
1942            mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
1943            mAudioTurnedOnTimer.writeToParcel(out, batteryRealtime);
1944            mVideoTurnedOnTimer.writeToParcel(out, batteryRealtime);
1945            mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
1946            mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
1947            if (mUserActivityCounters == null) {
1948                out.writeInt(0);
1949            } else {
1950                out.writeInt(1);
1951                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
1952                    mUserActivityCounters[i].writeToParcel(out);
1953                }
1954            }
1955        }
1956
1957        void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
1958            int numWakelocks = in.readInt();
1959            mWakelockStats.clear();
1960            for (int j = 0; j < numWakelocks; j++) {
1961                String wakelockName = in.readString();
1962                Uid.Wakelock wakelock = new Wakelock();
1963                wakelock.readFromParcelLocked(unpluggables, in);
1964                if (mWakelockStats.size() < MAX_WAKELOCKS_PER_UID) {
1965                    // We will just drop some random set of wakelocks if
1966                    // the previous run of the system was an older version
1967                    // that didn't impose a limit.
1968                    mWakelockStats.put(wakelockName, wakelock);
1969                }
1970            }
1971
1972            int numSensors = in.readInt();
1973            mSensorStats.clear();
1974            for (int k = 0; k < numSensors; k++) {
1975                int sensorNumber = in.readInt();
1976                Uid.Sensor sensor = new Sensor(sensorNumber);
1977                sensor.readFromParcelLocked(mUnpluggables, in);
1978                mSensorStats.put(sensorNumber, sensor);
1979            }
1980
1981            int numProcs = in.readInt();
1982            mProcessStats.clear();
1983            for (int k = 0; k < numProcs; k++) {
1984                String processName = in.readString();
1985                Uid.Proc proc = new Proc();
1986                proc.readFromParcelLocked(in);
1987                mProcessStats.put(processName, proc);
1988            }
1989
1990            int numPkgs = in.readInt();
1991            mPackageStats.clear();
1992            for (int l = 0; l < numPkgs; l++) {
1993                String packageName = in.readString();
1994                Uid.Pkg pkg = new Pkg();
1995                pkg.readFromParcelLocked(in);
1996                mPackageStats.put(packageName, pkg);
1997            }
1998
1999            mLoadedTcpBytesReceived = in.readLong();
2000            mLoadedTcpBytesSent = in.readLong();
2001            mCurrentTcpBytesReceived = in.readLong();
2002            mCurrentTcpBytesSent = in.readLong();
2003            mTcpBytesReceivedAtLastUnplug = in.readLong();
2004            mTcpBytesSentAtLastUnplug = in.readLong();
2005            mWifiTurnedOn = false;
2006            mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables, in);
2007            mFullWifiLockOut = false;
2008            mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables, in);
2009            mAudioTurnedOn = false;
2010            mAudioTurnedOnTimer = new StopwatchTimer(AUDIO_TURNED_ON, null, mUnpluggables, in);
2011            mVideoTurnedOn = false;
2012            mVideoTurnedOnTimer = new StopwatchTimer(VIDEO_TURNED_ON, null, mUnpluggables, in);
2013            mScanWifiLockOut = false;
2014            mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables, in);
2015            mWifiMulticastEnabled = false;
2016            mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
2017                    null, mUnpluggables, in);
2018            if (in.readInt() == 0) {
2019                mUserActivityCounters = null;
2020            } else {
2021                mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
2022                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2023                    mUserActivityCounters[i] = new Counter(mUnpluggables, in);
2024                }
2025            }
2026        }
2027
2028        /**
2029         * The statistics associated with a particular wake lock.
2030         */
2031        public final class Wakelock extends BatteryStats.Uid.Wakelock {
2032            /**
2033             * How long (in ms) this uid has been keeping the device partially awake.
2034             */
2035            StopwatchTimer mTimerPartial;
2036
2037            /**
2038             * How long (in ms) this uid has been keeping the device fully awake.
2039             */
2040            StopwatchTimer mTimerFull;
2041
2042            /**
2043             * How long (in ms) this uid has had a window keeping the device awake.
2044             */
2045            StopwatchTimer mTimerWindow;
2046
2047            /**
2048             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
2049             * proper timer pool from the given BatteryStatsImpl object.
2050             *
2051             * @param in the Parcel to be read from.
2052             * return a new Timer, or null.
2053             */
2054            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
2055                    ArrayList<Unpluggable> unpluggables, Parcel in) {
2056                if (in.readInt() == 0) {
2057                    return null;
2058                }
2059
2060                return new StopwatchTimer(type, pool, unpluggables, in);
2061            }
2062
2063            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
2064                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
2065                        mPartialTimers, unpluggables, in);
2066                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
2067                        mFullTimers, unpluggables, in);
2068                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
2069                        mWindowTimers, unpluggables, in);
2070            }
2071
2072            void writeToParcelLocked(Parcel out, long batteryRealtime) {
2073                Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
2074                Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
2075                Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
2076            }
2077
2078            @Override
2079            public Timer getWakeTime(int type) {
2080                switch (type) {
2081                case WAKE_TYPE_FULL: return mTimerFull;
2082                case WAKE_TYPE_PARTIAL: return mTimerPartial;
2083                case WAKE_TYPE_WINDOW: return mTimerWindow;
2084                default: throw new IllegalArgumentException("type = " + type);
2085                }
2086            }
2087        }
2088
2089        public final class Sensor extends BatteryStats.Uid.Sensor {
2090            final int mHandle;
2091            StopwatchTimer mTimer;
2092
2093            public Sensor(int handle) {
2094                mHandle = handle;
2095            }
2096
2097            private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
2098                    Parcel in) {
2099                if (in.readInt() == 0) {
2100                    return null;
2101                }
2102
2103                ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
2104                if (pool == null) {
2105                    pool = new ArrayList<StopwatchTimer>();
2106                    mSensorTimers.put(mHandle, pool);
2107                }
2108                return new StopwatchTimer(0, pool, unpluggables, in);
2109            }
2110
2111            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
2112                mTimer = readTimerFromParcel(unpluggables, in);
2113            }
2114
2115            void writeToParcelLocked(Parcel out, long batteryRealtime) {
2116                Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
2117            }
2118
2119            @Override
2120            public Timer getSensorTime() {
2121                return mTimer;
2122            }
2123
2124            @Override
2125            public int getHandle() {
2126                return mHandle;
2127            }
2128        }
2129
2130        /**
2131         * The statistics associated with a particular process.
2132         */
2133        public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
2134            /**
2135             * Total time (in 1/100 sec) spent executing in user code.
2136             */
2137            long mUserTime;
2138
2139            /**
2140             * Total time (in 1/100 sec) spent executing in kernel code.
2141             */
2142            long mSystemTime;
2143
2144            /**
2145             * Number of times the process has been started.
2146             */
2147            int mStarts;
2148
2149            /**
2150             * Amount of time the process was running in the foreground.
2151             */
2152            long mForegroundTime;
2153
2154            /**
2155             * The amount of user time loaded from a previous save.
2156             */
2157            long mLoadedUserTime;
2158
2159            /**
2160             * The amount of system time loaded from a previous save.
2161             */
2162            long mLoadedSystemTime;
2163
2164            /**
2165             * The number of times the process has started from a previous save.
2166             */
2167            int mLoadedStarts;
2168
2169            /**
2170             * The amount of foreground time loaded from a previous save.
2171             */
2172            long mLoadedForegroundTime;
2173
2174            /**
2175             * The amount of user time loaded from the previous run.
2176             */
2177            long mLastUserTime;
2178
2179            /**
2180             * The amount of system time loaded from the previous run.
2181             */
2182            long mLastSystemTime;
2183
2184            /**
2185             * The number of times the process has started from the previous run.
2186             */
2187            int mLastStarts;
2188
2189            /**
2190             * The amount of foreground time loaded from the previous run
2191             */
2192            long mLastForegroundTime;
2193
2194            /**
2195             * The amount of user time when last unplugged.
2196             */
2197            long mUnpluggedUserTime;
2198
2199            /**
2200             * The amount of system time when last unplugged.
2201             */
2202            long mUnpluggedSystemTime;
2203
2204            /**
2205             * The number of times the process has started before unplugged.
2206             */
2207            int mUnpluggedStarts;
2208
2209            /**
2210             * The amount of foreground time since unplugged.
2211             */
2212            long mUnpluggedForegroundTime;
2213
2214            SamplingCounter[] mSpeedBins;
2215
2216            Proc() {
2217                mUnpluggables.add(this);
2218                mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
2219                for (int i = 0; i < mSpeedBins.length; i++) {
2220                    mSpeedBins[i] = new SamplingCounter(mUnpluggables);
2221                }
2222            }
2223
2224            public void unplug(long batteryUptime, long batteryRealtime) {
2225                mUnpluggedUserTime = mUserTime;
2226                mUnpluggedSystemTime = mSystemTime;
2227                mUnpluggedStarts = mStarts;
2228                mUnpluggedForegroundTime = mForegroundTime;
2229            }
2230
2231            public void plug(long batteryUptime, long batteryRealtime) {
2232            }
2233
2234            void writeToParcelLocked(Parcel out) {
2235                final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
2236                final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
2237
2238                out.writeLong(mUserTime);
2239                out.writeLong(mSystemTime);
2240                out.writeLong(mForegroundTime);
2241                out.writeInt(mStarts);
2242                out.writeLong(mLoadedUserTime);
2243                out.writeLong(mLoadedSystemTime);
2244                out.writeLong(mLoadedForegroundTime);
2245                out.writeInt(mLoadedStarts);
2246                out.writeLong(mLastUserTime);
2247                out.writeLong(mLastSystemTime);
2248                out.writeLong(mLastForegroundTime);
2249                out.writeInt(mLastStarts);
2250                out.writeLong(mUnpluggedUserTime);
2251                out.writeLong(mUnpluggedSystemTime);
2252                out.writeLong(mUnpluggedForegroundTime);
2253                out.writeInt(mUnpluggedStarts);
2254
2255                out.writeInt(mSpeedBins.length);
2256                for (int i = 0; i < mSpeedBins.length; i++) {
2257                    mSpeedBins[i].writeToParcel(out);
2258                }
2259            }
2260
2261            void readFromParcelLocked(Parcel in) {
2262                mUserTime = in.readLong();
2263                mSystemTime = in.readLong();
2264                mForegroundTime = in.readLong();
2265                mStarts = in.readInt();
2266                mLoadedUserTime = in.readLong();
2267                mLoadedSystemTime = in.readLong();
2268                mLoadedForegroundTime = in.readLong();
2269                mLoadedStarts = in.readInt();
2270                mLastUserTime = in.readLong();
2271                mLastSystemTime = in.readLong();
2272                mLastForegroundTime = in.readLong();
2273                mLastStarts = in.readInt();
2274                mUnpluggedUserTime = in.readLong();
2275                mUnpluggedSystemTime = in.readLong();
2276                mUnpluggedForegroundTime = in.readLong();
2277                mUnpluggedStarts = in.readInt();
2278
2279                int bins = in.readInt();
2280                mSpeedBins = new SamplingCounter[bins];
2281                for (int i = 0; i < bins; i++) {
2282                    mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
2283                }
2284            }
2285
2286            public BatteryStatsImpl getBatteryStats() {
2287                return BatteryStatsImpl.this;
2288            }
2289
2290            public void addCpuTimeLocked(int utime, int stime) {
2291                mUserTime += utime;
2292                mSystemTime += stime;
2293            }
2294
2295            public void addForegroundTimeLocked(long ttime) {
2296                mForegroundTime += ttime;
2297            }
2298
2299            public void incStartsLocked() {
2300                mStarts++;
2301            }
2302
2303            @Override
2304            public long getUserTime(int which) {
2305                long val;
2306                if (which == STATS_LAST) {
2307                    val = mLastUserTime;
2308                } else {
2309                    val = mUserTime;
2310                    if (which == STATS_CURRENT) {
2311                        val -= mLoadedUserTime;
2312                    } else if (which == STATS_UNPLUGGED) {
2313                        val -= mUnpluggedUserTime;
2314                    }
2315                }
2316                return val;
2317            }
2318
2319            @Override
2320            public long getSystemTime(int which) {
2321                long val;
2322                if (which == STATS_LAST) {
2323                    val = mLastSystemTime;
2324                } else {
2325                    val = mSystemTime;
2326                    if (which == STATS_CURRENT) {
2327                        val -= mLoadedSystemTime;
2328                    } else if (which == STATS_UNPLUGGED) {
2329                        val -= mUnpluggedSystemTime;
2330                    }
2331                }
2332                return val;
2333            }
2334
2335            @Override
2336            public long getForegroundTime(int which) {
2337                long val;
2338                if (which == STATS_LAST) {
2339                    val = mLastForegroundTime;
2340                } else {
2341                    val = mForegroundTime;
2342                    if (which == STATS_CURRENT) {
2343                        val -= mLoadedForegroundTime;
2344                    } else if (which == STATS_UNPLUGGED) {
2345                        val -= mUnpluggedForegroundTime;
2346                    }
2347                }
2348                return val;
2349            }
2350
2351            @Override
2352            public int getStarts(int which) {
2353                int val;
2354                if (which == STATS_LAST) {
2355                    val = mLastStarts;
2356                } else {
2357                    val = mStarts;
2358                    if (which == STATS_CURRENT) {
2359                        val -= mLoadedStarts;
2360                    } else if (which == STATS_UNPLUGGED) {
2361                        val -= mUnpluggedStarts;
2362                    }
2363                }
2364                return val;
2365            }
2366
2367            /* Called by ActivityManagerService when CPU times are updated. */
2368            public void addSpeedStepTimes(long[] values) {
2369                for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
2370                    mSpeedBins[i].addCountAtomic(values[i]);
2371                }
2372            }
2373
2374            @Override
2375            public long getTimeAtCpuSpeedStep(int speedStep, int which) {
2376                if (speedStep < mSpeedBins.length) {
2377                    return mSpeedBins[speedStep].getCountLocked(which);
2378                } else {
2379                    return 0;
2380                }
2381            }
2382        }
2383
2384        /**
2385         * The statistics associated with a particular package.
2386         */
2387        public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
2388            /**
2389             * Number of times this package has done something that could wake up the
2390             * device from sleep.
2391             */
2392            int mWakeups;
2393
2394            /**
2395             * Number of things that could wake up the device loaded from a
2396             * previous save.
2397             */
2398            int mLoadedWakeups;
2399
2400            /**
2401             * Number of things that could wake up the device as of the
2402             * last run.
2403             */
2404            int mLastWakeups;
2405
2406            /**
2407             * Number of things that could wake up the device as of the
2408             * last run.
2409             */
2410            int mUnpluggedWakeups;
2411
2412            /**
2413             * The statics we have collected for this package's services.
2414             */
2415            final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
2416
2417            Pkg() {
2418                mUnpluggables.add(this);
2419            }
2420
2421            public void unplug(long batteryUptime, long batteryRealtime) {
2422                mUnpluggedWakeups = mWakeups;
2423            }
2424
2425            public void plug(long batteryUptime, long batteryRealtime) {
2426            }
2427
2428            void readFromParcelLocked(Parcel in) {
2429                mWakeups = in.readInt();
2430                mLoadedWakeups = in.readInt();
2431                mLastWakeups = in.readInt();
2432                mUnpluggedWakeups = in.readInt();
2433
2434                int numServs = in.readInt();
2435                mServiceStats.clear();
2436                for (int m = 0; m < numServs; m++) {
2437                    String serviceName = in.readString();
2438                    Uid.Pkg.Serv serv = new Serv();
2439                    mServiceStats.put(serviceName, serv);
2440
2441                    serv.readFromParcelLocked(in);
2442                }
2443            }
2444
2445            void writeToParcelLocked(Parcel out) {
2446                out.writeInt(mWakeups);
2447                out.writeInt(mLoadedWakeups);
2448                out.writeInt(mLastWakeups);
2449                out.writeInt(mUnpluggedWakeups);
2450
2451                out.writeInt(mServiceStats.size());
2452                for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
2453                    out.writeString(servEntry.getKey());
2454                    Uid.Pkg.Serv serv = servEntry.getValue();
2455
2456                    serv.writeToParcelLocked(out);
2457                }
2458            }
2459
2460            @Override
2461            public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
2462                return mServiceStats;
2463            }
2464
2465            @Override
2466            public int getWakeups(int which) {
2467                int val;
2468                if (which == STATS_LAST) {
2469                    val = mLastWakeups;
2470                } else {
2471                    val = mWakeups;
2472                    if (which == STATS_CURRENT) {
2473                        val -= mLoadedWakeups;
2474                    } else if (which == STATS_UNPLUGGED) {
2475                        val -= mUnpluggedWakeups;
2476                    }
2477                }
2478
2479                return val;
2480            }
2481
2482            /**
2483             * The statistics associated with a particular service.
2484             */
2485            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
2486                /**
2487                 * Total time (ms in battery uptime) the service has been left started.
2488                 */
2489                long mStartTime;
2490
2491                /**
2492                 * If service has been started and not yet stopped, this is
2493                 * when it was started.
2494                 */
2495                long mRunningSince;
2496
2497                /**
2498                 * True if we are currently running.
2499                 */
2500                boolean mRunning;
2501
2502                /**
2503                 * Total number of times startService() has been called.
2504                 */
2505                int mStarts;
2506
2507                /**
2508                 * Total time (ms in battery uptime) the service has been left launched.
2509                 */
2510                long mLaunchedTime;
2511
2512                /**
2513                 * If service has been launched and not yet exited, this is
2514                 * when it was launched (ms in battery uptime).
2515                 */
2516                long mLaunchedSince;
2517
2518                /**
2519                 * True if we are currently launched.
2520                 */
2521                boolean mLaunched;
2522
2523                /**
2524                 * Total number times the service has been launched.
2525                 */
2526                int mLaunches;
2527
2528                /**
2529                 * The amount of time spent started loaded from a previous save
2530                 * (ms in battery uptime).
2531                 */
2532                long mLoadedStartTime;
2533
2534                /**
2535                 * The number of starts loaded from a previous save.
2536                 */
2537                int mLoadedStarts;
2538
2539                /**
2540                 * The number of launches loaded from a previous save.
2541                 */
2542                int mLoadedLaunches;
2543
2544                /**
2545                 * The amount of time spent started as of the last run (ms
2546                 * in battery uptime).
2547                 */
2548                long mLastStartTime;
2549
2550                /**
2551                 * The number of starts as of the last run.
2552                 */
2553                int mLastStarts;
2554
2555                /**
2556                 * The number of launches as of the last run.
2557                 */
2558                int mLastLaunches;
2559
2560                /**
2561                 * The amount of time spent started when last unplugged (ms
2562                 * in battery uptime).
2563                 */
2564                long mUnpluggedStartTime;
2565
2566                /**
2567                 * The number of starts when last unplugged.
2568                 */
2569                int mUnpluggedStarts;
2570
2571                /**
2572                 * The number of launches when last unplugged.
2573                 */
2574                int mUnpluggedLaunches;
2575
2576                Serv() {
2577                    mUnpluggables.add(this);
2578                }
2579
2580                public void unplug(long batteryUptime, long batteryRealtime) {
2581                    mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
2582                    mUnpluggedStarts = mStarts;
2583                    mUnpluggedLaunches = mLaunches;
2584                }
2585
2586                public void plug(long batteryUptime, long batteryRealtime) {
2587                }
2588
2589                void readFromParcelLocked(Parcel in) {
2590                    mStartTime = in.readLong();
2591                    mRunningSince = in.readLong();
2592                    mRunning = in.readInt() != 0;
2593                    mStarts = in.readInt();
2594                    mLaunchedTime = in.readLong();
2595                    mLaunchedSince = in.readLong();
2596                    mLaunched = in.readInt() != 0;
2597                    mLaunches = in.readInt();
2598                    mLoadedStartTime = in.readLong();
2599                    mLoadedStarts = in.readInt();
2600                    mLoadedLaunches = in.readInt();
2601                    mLastStartTime = in.readLong();
2602                    mLastStarts = in.readInt();
2603                    mLastLaunches = in.readInt();
2604                    mUnpluggedStartTime = in.readLong();
2605                    mUnpluggedStarts = in.readInt();
2606                    mUnpluggedLaunches = in.readInt();
2607                }
2608
2609                void writeToParcelLocked(Parcel out) {
2610                    out.writeLong(mStartTime);
2611                    out.writeLong(mRunningSince);
2612                    out.writeInt(mRunning ? 1 : 0);
2613                    out.writeInt(mStarts);
2614                    out.writeLong(mLaunchedTime);
2615                    out.writeLong(mLaunchedSince);
2616                    out.writeInt(mLaunched ? 1 : 0);
2617                    out.writeInt(mLaunches);
2618                    out.writeLong(mLoadedStartTime);
2619                    out.writeInt(mLoadedStarts);
2620                    out.writeInt(mLoadedLaunches);
2621                    out.writeLong(mLastStartTime);
2622                    out.writeInt(mLastStarts);
2623                    out.writeInt(mLastLaunches);
2624                    out.writeLong(mUnpluggedStartTime);
2625                    out.writeInt(mUnpluggedStarts);
2626                    out.writeInt(mUnpluggedLaunches);
2627                }
2628
2629                long getLaunchTimeToNowLocked(long batteryUptime) {
2630                    if (!mLaunched) return mLaunchedTime;
2631                    return mLaunchedTime + batteryUptime - mLaunchedSince;
2632                }
2633
2634                long getStartTimeToNowLocked(long batteryUptime) {
2635                    if (!mRunning) return mStartTime;
2636                    return mStartTime + batteryUptime - mRunningSince;
2637                }
2638
2639                public void startLaunchedLocked() {
2640                    if (!mLaunched) {
2641                        mLaunches++;
2642                        mLaunchedSince = getBatteryUptimeLocked();
2643                        mLaunched = true;
2644                    }
2645                }
2646
2647                public void stopLaunchedLocked() {
2648                    if (mLaunched) {
2649                        long time = getBatteryUptimeLocked() - mLaunchedSince;
2650                        if (time > 0) {
2651                            mLaunchedTime += time;
2652                        } else {
2653                            mLaunches--;
2654                        }
2655                        mLaunched = false;
2656                    }
2657                }
2658
2659                public void startRunningLocked() {
2660                    if (!mRunning) {
2661                        mStarts++;
2662                        mRunningSince = getBatteryUptimeLocked();
2663                        mRunning = true;
2664                    }
2665                }
2666
2667                public void stopRunningLocked() {
2668                    if (mRunning) {
2669                        long time = getBatteryUptimeLocked() - mRunningSince;
2670                        if (time > 0) {
2671                            mStartTime += time;
2672                        } else {
2673                            mStarts--;
2674                        }
2675                        mRunning = false;
2676                    }
2677                }
2678
2679                public BatteryStatsImpl getBatteryStats() {
2680                    return BatteryStatsImpl.this;
2681                }
2682
2683                @Override
2684                public int getLaunches(int which) {
2685                    int val;
2686
2687                    if (which == STATS_LAST) {
2688                        val = mLastLaunches;
2689                    } else {
2690                        val = mLaunches;
2691                        if (which == STATS_CURRENT) {
2692                            val -= mLoadedLaunches;
2693                        } else if (which == STATS_UNPLUGGED) {
2694                            val -= mUnpluggedLaunches;
2695                        }
2696                    }
2697
2698                    return val;
2699                }
2700
2701                @Override
2702                public long getStartTime(long now, int which) {
2703                    long val;
2704                    if (which == STATS_LAST) {
2705                        val = mLastStartTime;
2706                    } else {
2707                        val = getStartTimeToNowLocked(now);
2708                        if (which == STATS_CURRENT) {
2709                            val -= mLoadedStartTime;
2710                        } else if (which == STATS_UNPLUGGED) {
2711                            val -= mUnpluggedStartTime;
2712                        }
2713                    }
2714
2715                    return val;
2716                }
2717
2718                @Override
2719                public int getStarts(int which) {
2720                    int val;
2721                    if (which == STATS_LAST) {
2722                        val = mLastStarts;
2723                    } else {
2724                        val = mStarts;
2725                        if (which == STATS_CURRENT) {
2726                            val -= mLoadedStarts;
2727                        } else if (which == STATS_UNPLUGGED) {
2728                            val -= mUnpluggedStarts;
2729                        }
2730                    }
2731
2732                    return val;
2733                }
2734            }
2735
2736            public BatteryStatsImpl getBatteryStats() {
2737                return BatteryStatsImpl.this;
2738            }
2739
2740            public void incWakeupsLocked() {
2741                mWakeups++;
2742            }
2743
2744            final Serv newServiceStatsLocked() {
2745                return new Serv();
2746            }
2747        }
2748
2749        /**
2750         * Retrieve the statistics object for a particular process, creating
2751         * if needed.
2752         */
2753        public Proc getProcessStatsLocked(String name) {
2754            Proc ps = mProcessStats.get(name);
2755            if (ps == null) {
2756                ps = new Proc();
2757                mProcessStats.put(name, ps);
2758            }
2759
2760            return ps;
2761        }
2762
2763        /**
2764         * Retrieve the statistics object for a particular service, creating
2765         * if needed.
2766         */
2767        public Pkg getPackageStatsLocked(String name) {
2768            Pkg ps = mPackageStats.get(name);
2769            if (ps == null) {
2770                ps = new Pkg();
2771                mPackageStats.put(name, ps);
2772            }
2773
2774            return ps;
2775        }
2776
2777        /**
2778         * Retrieve the statistics object for a particular service, creating
2779         * if needed.
2780         */
2781        public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
2782            Pkg ps = getPackageStatsLocked(pkg);
2783            Pkg.Serv ss = ps.mServiceStats.get(serv);
2784            if (ss == null) {
2785                ss = ps.newServiceStatsLocked();
2786                ps.mServiceStats.put(serv, ss);
2787            }
2788
2789            return ss;
2790        }
2791
2792        public StopwatchTimer getWakeTimerLocked(String name, int type) {
2793            Wakelock wl = mWakelockStats.get(name);
2794            if (wl == null) {
2795                if (mWakelockStats.size() > MAX_WAKELOCKS_PER_UID) {
2796                    name = BATCHED_WAKELOCK_NAME;
2797                    wl = mWakelockStats.get(name);
2798                }
2799                if (wl == null) {
2800                    wl = new Wakelock();
2801                    mWakelockStats.put(name, wl);
2802                }
2803            }
2804            StopwatchTimer t = null;
2805            switch (type) {
2806                case WAKE_TYPE_PARTIAL:
2807                    t = wl.mTimerPartial;
2808                    if (t == null) {
2809                        t = new StopwatchTimer(WAKE_TYPE_PARTIAL, mPartialTimers, mUnpluggables);
2810                        wl.mTimerPartial = t;
2811                    }
2812                    return t;
2813                case WAKE_TYPE_FULL:
2814                    t = wl.mTimerFull;
2815                    if (t == null) {
2816                        t = new StopwatchTimer(WAKE_TYPE_FULL, mFullTimers, mUnpluggables);
2817                        wl.mTimerFull = t;
2818                    }
2819                    return t;
2820                case WAKE_TYPE_WINDOW:
2821                    t = wl.mTimerWindow;
2822                    if (t == null) {
2823                        t = new StopwatchTimer(WAKE_TYPE_WINDOW, mWindowTimers, mUnpluggables);
2824                        wl.mTimerWindow = t;
2825                    }
2826                    return t;
2827                default:
2828                    throw new IllegalArgumentException("type=" + type);
2829            }
2830        }
2831
2832        public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
2833            Sensor se = mSensorStats.get(sensor);
2834            if (se == null) {
2835                if (!create) {
2836                    return null;
2837                }
2838                se = new Sensor(sensor);
2839                mSensorStats.put(sensor, se);
2840            }
2841            StopwatchTimer t = se.mTimer;
2842            if (t != null) {
2843                return t;
2844            }
2845            ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
2846            if (timers == null) {
2847                timers = new ArrayList<StopwatchTimer>();
2848                mSensorTimers.put(sensor, timers);
2849            }
2850            t = new StopwatchTimer(BatteryStats.SENSOR, timers, mUnpluggables);
2851            se.mTimer = t;
2852            return t;
2853        }
2854
2855        public void noteStartWakeLocked(String name, int type) {
2856            StopwatchTimer t = getWakeTimerLocked(name, type);
2857            if (t != null) {
2858                t.startRunningLocked(BatteryStatsImpl.this);
2859            }
2860        }
2861
2862        public void noteStopWakeLocked(String name, int type) {
2863            StopwatchTimer t = getWakeTimerLocked(name, type);
2864            if (t != null) {
2865                t.stopRunningLocked(BatteryStatsImpl.this);
2866            }
2867        }
2868
2869        public void noteStartSensor(int sensor) {
2870            StopwatchTimer t = getSensorTimerLocked(sensor, true);
2871            if (t != null) {
2872                t.startRunningLocked(BatteryStatsImpl.this);
2873            }
2874        }
2875
2876        public void noteStopSensor(int sensor) {
2877            // Don't create a timer if one doesn't already exist
2878            StopwatchTimer t = getSensorTimerLocked(sensor, false);
2879            if (t != null) {
2880                t.stopRunningLocked(BatteryStatsImpl.this);
2881            }
2882        }
2883
2884        public void noteStartGps() {
2885            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
2886            if (t != null) {
2887                t.startRunningLocked(BatteryStatsImpl.this);
2888            }
2889        }
2890
2891        public void noteStopGps() {
2892            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
2893            if (t != null) {
2894                t.stopRunningLocked(BatteryStatsImpl.this);
2895            }
2896        }
2897
2898        public BatteryStatsImpl getBatteryStats() {
2899            return BatteryStatsImpl.this;
2900        }
2901    }
2902
2903    public BatteryStatsImpl(String filename) {
2904        mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
2905        mStartCount++;
2906        mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables);
2907        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
2908            mScreenBrightnessTimer[i] = new StopwatchTimer(-100-i, null, mUnpluggables);
2909        }
2910        mInputEventCounter = new Counter(mUnpluggables);
2911        mPhoneOnTimer = new StopwatchTimer(-2, null, mUnpluggables);
2912        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
2913            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(-200-i, null, mUnpluggables);
2914        }
2915        mPhoneSignalScanningTimer = new StopwatchTimer(-200+1, null, mUnpluggables);
2916        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
2917            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(-300-i, null, mUnpluggables);
2918        }
2919        mWifiOnTimer = new StopwatchTimer(-3, null, mUnpluggables);
2920        mWifiRunningTimer = new StopwatchTimer(-4, null, mUnpluggables);
2921        mBluetoothOnTimer = new StopwatchTimer(-5, null, mUnpluggables);
2922        mAudioOnTimer = new StopwatchTimer(-6, null, mUnpluggables);
2923        mOnBattery = mOnBatteryInternal = false;
2924        mTrackBatteryPastUptime = 0;
2925        mTrackBatteryPastRealtime = 0;
2926        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
2927        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
2928        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
2929        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
2930        mDischargeStartLevel = 0;
2931        mDischargeCurrentLevel = 0;
2932    }
2933
2934    public BatteryStatsImpl(Parcel p) {
2935        mFile = null;
2936        readFromParcel(p);
2937    }
2938
2939    public void setNumSpeedSteps(int steps) {
2940        if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
2941    }
2942
2943    public void setRadioScanningTimeout(long timeout) {
2944        if (mPhoneSignalScanningTimer != null) {
2945            mPhoneSignalScanningTimer.setTimeout(timeout);
2946        }
2947    }
2948
2949    @Override
2950    public BatteryHistoryRecord getHistory() {
2951        return mHistory;
2952    }
2953
2954    @Override
2955    public int getStartCount() {
2956        return mStartCount;
2957    }
2958
2959    public boolean isOnBattery() {
2960        return mOnBattery;
2961    }
2962
2963    public void setOnBattery(boolean onBattery, int level) {
2964        synchronized(this) {
2965            updateKernelWakelocksLocked();
2966            if (mOnBattery != onBattery) {
2967                mOnBattery = mOnBatteryInternal = onBattery;
2968
2969                long uptime = SystemClock.uptimeMillis() * 1000;
2970                long mSecRealtime = SystemClock.elapsedRealtime();
2971                long realtime = mSecRealtime * 1000;
2972                if (onBattery) {
2973                    clearHistory();
2974                    mHistoryCur.batteryLevel = (byte)level;
2975                    mHistoryCur.states &= ~BatteryHistoryRecord.STATE_BATTERY_PLUGGED_FLAG;
2976                    if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
2977                            + Integer.toHexString(mHistoryCur.states));
2978                    addHistoryRecord(mSecRealtime);
2979                    mTrackBatteryUptimeStart = uptime;
2980                    mTrackBatteryRealtimeStart = realtime;
2981                    mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
2982                    mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
2983                    mDischargeCurrentLevel = mDischargeStartLevel = level;
2984                    doUnplug(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
2985                } else {
2986                    mHistoryCur.batteryLevel = (byte)level;
2987                    mHistoryCur.states |= BatteryHistoryRecord.STATE_BATTERY_PLUGGED_FLAG;
2988                    if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
2989                            + Integer.toHexString(mHistoryCur.states));
2990                    addHistoryRecord(mSecRealtime);
2991                    mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
2992                    mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
2993                    mDischargeCurrentLevel = level;
2994                    doPlug(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
2995                }
2996                if ((mLastWriteTime + (60 * 1000)) < mSecRealtime) {
2997                    if (mFile != null) {
2998                        writeLocked();
2999                    }
3000                }
3001            }
3002        }
3003    }
3004
3005    public void recordCurrentLevel(int level) {
3006        if (mDischargeCurrentLevel != level) {
3007            mDischargeCurrentLevel = level;
3008            mHistoryCur.batteryLevel = (byte)level;
3009            addHistoryRecord(SystemClock.elapsedRealtime());
3010        }
3011    }
3012
3013    public void updateKernelWakelocksLocked() {
3014        Map<String, KernelWakelockStats> m = readKernelWakelockStats();
3015
3016        if (m == null) {
3017            // Not crashing might make board bringup easier.
3018            Slog.w(TAG, "Couldn't get kernel wake lock stats");
3019            return;
3020        }
3021
3022        for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
3023            String name = ent.getKey();
3024            KernelWakelockStats kws = ent.getValue();
3025
3026            SamplingTimer kwlt = mKernelWakelockStats.get(name);
3027            if (kwlt == null) {
3028                kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
3029                        true /* track reported values */);
3030                mKernelWakelockStats.put(name, kwlt);
3031            }
3032            kwlt.updateCurrentReportedCount(kws.mCount);
3033            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
3034            kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
3035        }
3036
3037        if (m.size() != mKernelWakelockStats.size()) {
3038            // Set timers to stale if they didn't appear in /proc/wakelocks this time.
3039            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
3040                SamplingTimer st = ent.getValue();
3041                if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
3042                    st.setStale();
3043                }
3044            }
3045        }
3046    }
3047
3048    public long getAwakeTimeBattery() {
3049        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
3050    }
3051
3052    public long getAwakeTimePlugged() {
3053        return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
3054    }
3055
3056    @Override
3057    public long computeUptime(long curTime, int which) {
3058        switch (which) {
3059            case STATS_TOTAL: return mUptime + (curTime-mUptimeStart);
3060            case STATS_LAST: return mLastUptime;
3061            case STATS_CURRENT: return (curTime-mUptimeStart);
3062            case STATS_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
3063        }
3064        return 0;
3065    }
3066
3067    @Override
3068    public long computeRealtime(long curTime, int which) {
3069        switch (which) {
3070            case STATS_TOTAL: return mRealtime + (curTime-mRealtimeStart);
3071            case STATS_LAST: return mLastRealtime;
3072            case STATS_CURRENT: return (curTime-mRealtimeStart);
3073            case STATS_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
3074        }
3075        return 0;
3076    }
3077
3078    @Override
3079    public long computeBatteryUptime(long curTime, int which) {
3080        switch (which) {
3081            case STATS_TOTAL:
3082                return mBatteryUptime + getBatteryUptime(curTime);
3083            case STATS_LAST:
3084                return mBatteryLastUptime;
3085            case STATS_CURRENT:
3086                return getBatteryUptime(curTime);
3087            case STATS_UNPLUGGED:
3088                return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
3089        }
3090        return 0;
3091    }
3092
3093    @Override
3094    public long computeBatteryRealtime(long curTime, int which) {
3095        switch (which) {
3096            case STATS_TOTAL:
3097                return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
3098            case STATS_LAST:
3099                return mBatteryLastRealtime;
3100            case STATS_CURRENT:
3101                return getBatteryRealtimeLocked(curTime);
3102            case STATS_UNPLUGGED:
3103                return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
3104        }
3105        return 0;
3106    }
3107
3108    long getBatteryUptimeLocked(long curTime) {
3109        long time = mTrackBatteryPastUptime;
3110        if (mOnBatteryInternal) {
3111            time += curTime - mTrackBatteryUptimeStart;
3112        }
3113        return time;
3114    }
3115
3116    long getBatteryUptimeLocked() {
3117        return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
3118    }
3119
3120    @Override
3121    public long getBatteryUptime(long curTime) {
3122        return getBatteryUptimeLocked(curTime);
3123    }
3124
3125    long getBatteryRealtimeLocked(long curTime) {
3126        long time = mTrackBatteryPastRealtime;
3127        if (mOnBatteryInternal) {
3128            time += curTime - mTrackBatteryRealtimeStart;
3129        }
3130        return time;
3131    }
3132
3133    @Override
3134    public long getBatteryRealtime(long curTime) {
3135        return getBatteryRealtimeLocked(curTime);
3136    }
3137
3138    private long getTcpBytes(long current, long[] dataBytes, int which) {
3139        if (which == STATS_LAST) {
3140            return dataBytes[STATS_LAST];
3141        } else {
3142            if (which == STATS_UNPLUGGED) {
3143                if (dataBytes[STATS_UNPLUGGED] < 0) {
3144                    return dataBytes[STATS_LAST];
3145                } else {
3146                    return current - dataBytes[STATS_UNPLUGGED];
3147                }
3148            } else if (which == STATS_TOTAL) {
3149                return (current - dataBytes[STATS_CURRENT]) + dataBytes[STATS_TOTAL];
3150            }
3151            return current - dataBytes[STATS_CURRENT];
3152        }
3153    }
3154
3155    /** Only STATS_UNPLUGGED works properly */
3156    public long getMobileTcpBytesSent(int which) {
3157        return getTcpBytes(TrafficStats.getMobileTxBytes(), mMobileDataTx, which);
3158    }
3159
3160    /** Only STATS_UNPLUGGED works properly */
3161    public long getMobileTcpBytesReceived(int which) {
3162        return getTcpBytes(TrafficStats.getMobileRxBytes(), mMobileDataRx, which);
3163    }
3164
3165    /** Only STATS_UNPLUGGED works properly */
3166    public long getTotalTcpBytesSent(int which) {
3167        return getTcpBytes(TrafficStats.getTotalTxBytes(), mTotalDataTx, which);
3168    }
3169
3170    /** Only STATS_UNPLUGGED works properly */
3171    public long getTotalTcpBytesReceived(int which) {
3172        return getTcpBytes(TrafficStats.getTotalRxBytes(), mTotalDataRx, which);
3173    }
3174
3175    @Override
3176    public int getDischargeStartLevel() {
3177        synchronized(this) {
3178            return getDischargeStartLevelLocked();
3179        }
3180    }
3181
3182    public int getDischargeStartLevelLocked() {
3183            return mDischargeStartLevel;
3184    }
3185
3186    @Override
3187    public int getDischargeCurrentLevel() {
3188        synchronized(this) {
3189            return getDischargeCurrentLevelLocked();
3190        }
3191    }
3192
3193    public int getDischargeCurrentLevelLocked() {
3194            return mDischargeCurrentLevel;
3195    }
3196
3197    @Override
3198    public int getCpuSpeedSteps() {
3199        return sNumSpeedSteps;
3200    }
3201
3202    /**
3203     * Retrieve the statistics object for a particular uid, creating if needed.
3204     */
3205    public Uid getUidStatsLocked(int uid) {
3206        Uid u = mUidStats.get(uid);
3207        if (u == null) {
3208            u = new Uid(uid);
3209            mUidStats.put(uid, u);
3210        }
3211        return u;
3212    }
3213
3214    /**
3215     * Remove the statistics object for a particular uid.
3216     */
3217    public void removeUidStatsLocked(int uid) {
3218        mUidStats.remove(uid);
3219    }
3220
3221    /**
3222     * Retrieve the statistics object for a particular process, creating
3223     * if needed.
3224     */
3225    public Uid.Proc getProcessStatsLocked(int uid, String name) {
3226        Uid u = getUidStatsLocked(uid);
3227        return u.getProcessStatsLocked(name);
3228    }
3229
3230    /**
3231     * Retrieve the statistics object for a particular process, given
3232     * the name of the process.
3233     * @param name process name
3234     * @return the statistics object for the process
3235     */
3236    public Uid.Proc getProcessStatsLocked(String name, int pid) {
3237        int uid;
3238        if (mUidCache.containsKey(name)) {
3239            uid = mUidCache.get(name);
3240        } else {
3241            uid = Process.getUidForPid(pid);
3242            mUidCache.put(name, uid);
3243        }
3244        Uid u = getUidStatsLocked(uid);
3245        return u.getProcessStatsLocked(name);
3246    }
3247
3248    /**
3249     * Retrieve the statistics object for a particular process, creating
3250     * if needed.
3251     */
3252    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
3253        Uid u = getUidStatsLocked(uid);
3254        return u.getPackageStatsLocked(pkg);
3255    }
3256
3257    /**
3258     * Retrieve the statistics object for a particular service, creating
3259     * if needed.
3260     */
3261    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
3262        Uid u = getUidStatsLocked(uid);
3263        return u.getServiceStatsLocked(pkg, name);
3264    }
3265
3266    private static JournaledFile makeJournaledFile() {
3267        final String base = "/data/system/device_policies.xml";
3268        return new JournaledFile(new File(base), new File(base + ".tmp"));
3269    }
3270
3271    public void writeLocked() {
3272        if (mFile == null) {
3273            Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
3274            return;
3275        }
3276
3277        try {
3278            FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
3279            Parcel out = Parcel.obtain();
3280            writeSummaryToParcel(out);
3281            stream.write(out.marshall());
3282            out.recycle();
3283
3284            stream.flush();
3285            stream.close();
3286            mFile.commit();
3287
3288            mLastWriteTime = SystemClock.elapsedRealtime();
3289            return;
3290        } catch (IOException e) {
3291            Slog.w("BatteryStats", "Error writing battery statistics", e);
3292        }
3293        mFile.rollback();
3294    }
3295
3296    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
3297        int pos = 0;
3298        int avail = stream.available();
3299        byte[] data = new byte[avail];
3300        while (true) {
3301            int amt = stream.read(data, pos, data.length-pos);
3302            //Log.i("foo", "Read " + amt + " bytes at " + pos
3303            //        + " of avail " + data.length);
3304            if (amt <= 0) {
3305                //Log.i("foo", "**** FINISHED READING: pos=" + pos
3306                //        + " len=" + data.length);
3307                return data;
3308            }
3309            pos += amt;
3310            avail = stream.available();
3311            if (avail > data.length-pos) {
3312                byte[] newData = new byte[pos+avail];
3313                System.arraycopy(data, 0, newData, 0, pos);
3314                data = newData;
3315            }
3316        }
3317    }
3318
3319    public void readLocked() {
3320        if (mFile == null) {
3321            Slog.w("BatteryStats", "readLocked: no file associated with this instance");
3322            return;
3323        }
3324
3325        mUidStats.clear();
3326
3327        try {
3328            File file = mFile.chooseForRead();
3329            if (!file.exists()) {
3330                return;
3331            }
3332            FileInputStream stream = new FileInputStream(file);
3333
3334            byte[] raw = readFully(stream);
3335            Parcel in = Parcel.obtain();
3336            in.unmarshall(raw, 0, raw.length);
3337            in.setDataPosition(0);
3338            stream.close();
3339
3340            readSummaryFromParcel(in);
3341        } catch(java.io.IOException e) {
3342            Slog.e("BatteryStats", "Error reading battery statistics", e);
3343        }
3344    }
3345
3346    public int describeContents() {
3347        return 0;
3348    }
3349
3350    void readHistory(Parcel in) {
3351        mHistory = mHistoryEnd = mHistoryCache = null;
3352        long time;
3353        while ((time=in.readLong()) >= 0) {
3354            BatteryHistoryRecord rec = new BatteryHistoryRecord(time, in);
3355            addHistoryRecord(rec);
3356        }
3357    }
3358
3359    void writeHistory(Parcel out) {
3360        BatteryHistoryRecord rec = mHistory;
3361        while (rec != null) {
3362            if (rec.time >= 0) rec.writeToParcel(out, 0);
3363            rec = rec.next;
3364        }
3365        out.writeLong(-1);
3366    }
3367
3368    private void readSummaryFromParcel(Parcel in) {
3369        final int version = in.readInt();
3370        if (version != VERSION) {
3371            Slog.w("BatteryStats", "readFromParcel: version got " + version
3372                + ", expected " + VERSION + "; erasing old stats");
3373            return;
3374        }
3375
3376        readHistory(in);
3377
3378        mStartCount = in.readInt();
3379        mBatteryUptime = in.readLong();
3380        mBatteryLastUptime = in.readLong();
3381        mBatteryRealtime = in.readLong();
3382        mBatteryLastRealtime = in.readLong();
3383        mUptime = in.readLong();
3384        mLastUptime = in.readLong();
3385        mRealtime = in.readLong();
3386        mLastRealtime = in.readLong();
3387        mDischargeStartLevel = in.readInt();
3388        mDischargeCurrentLevel = in.readInt();
3389
3390        mStartCount++;
3391
3392        mScreenOn = false;
3393        mScreenOnTimer.readSummaryFromParcelLocked(in);
3394        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3395            mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
3396        }
3397        mInputEventCounter.readSummaryFromParcelLocked(in);
3398        mPhoneOn = false;
3399        mPhoneOnTimer.readSummaryFromParcelLocked(in);
3400        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3401            mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
3402        }
3403        mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
3404        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3405            mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
3406        }
3407        mWifiOn = false;
3408        mWifiOnTimer.readSummaryFromParcelLocked(in);
3409        mWifiRunning = false;
3410        mWifiRunningTimer.readSummaryFromParcelLocked(in);
3411        mBluetoothOn = false;
3412        mBluetoothOnTimer.readSummaryFromParcelLocked(in);
3413
3414        int NKW = in.readInt();
3415        if (NKW > 10000) {
3416            Slog.w(TAG, "File corrupt: too many kernel wake locks " + NKW);
3417            return;
3418        }
3419        for (int ikw = 0; ikw < NKW; ikw++) {
3420            if (in.readInt() != 0) {
3421                String kwltName = in.readString();
3422                getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
3423            }
3424        }
3425
3426        sNumSpeedSteps = in.readInt();
3427
3428        final int NU = in.readInt();
3429        if (NU > 10000) {
3430            Slog.w(TAG, "File corrupt: too many uids " + NU);
3431            return;
3432        }
3433        for (int iu = 0; iu < NU; iu++) {
3434            int uid = in.readInt();
3435            Uid u = new Uid(uid);
3436            mUidStats.put(uid, u);
3437
3438            u.mWifiTurnedOn = false;
3439            u.mWifiTurnedOnTimer.readSummaryFromParcelLocked(in);
3440            u.mFullWifiLockOut = false;
3441            u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
3442            u.mAudioTurnedOn = false;
3443            u.mAudioTurnedOnTimer.readSummaryFromParcelLocked(in);
3444            u.mVideoTurnedOn = false;
3445            u.mVideoTurnedOnTimer.readSummaryFromParcelLocked(in);
3446            u.mScanWifiLockOut = false;
3447            u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
3448            u.mWifiMulticastEnabled = false;
3449            u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
3450
3451            if (in.readInt() != 0) {
3452                if (u.mUserActivityCounters == null) {
3453                    u.initUserActivityLocked();
3454                }
3455                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
3456                    u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
3457                }
3458            }
3459
3460            int NW = in.readInt();
3461            if (NW > 10000) {
3462                Slog.w(TAG, "File corrupt: too many wake locks " + NW);
3463                return;
3464            }
3465            for (int iw = 0; iw < NW; iw++) {
3466                String wlName = in.readString();
3467                if (in.readInt() != 0) {
3468                    u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
3469                }
3470                if (in.readInt() != 0) {
3471                    u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
3472                }
3473                if (in.readInt() != 0) {
3474                    u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
3475                }
3476            }
3477
3478            int NP = in.readInt();
3479            if (NP > 10000) {
3480                Slog.w(TAG, "File corrupt: too many sensors " + NP);
3481                return;
3482            }
3483            for (int is = 0; is < NP; is++) {
3484                int seNumber = in.readInt();
3485                if (in.readInt() != 0) {
3486                    u.getSensorTimerLocked(seNumber, true)
3487                            .readSummaryFromParcelLocked(in);
3488                }
3489            }
3490
3491            NP = in.readInt();
3492            if (NP > 10000) {
3493                Slog.w(TAG, "File corrupt: too many processes " + NP);
3494                return;
3495            }
3496            for (int ip = 0; ip < NP; ip++) {
3497                String procName = in.readString();
3498                Uid.Proc p = u.getProcessStatsLocked(procName);
3499                p.mUserTime = p.mLoadedUserTime = in.readLong();
3500                p.mLastUserTime = in.readLong();
3501                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
3502                p.mLastSystemTime = in.readLong();
3503                p.mStarts = p.mLoadedStarts = in.readInt();
3504                p.mLastStarts = in.readInt();
3505            }
3506
3507            NP = in.readInt();
3508            if (NP > 10000) {
3509                Slog.w(TAG, "File corrupt: too many packages " + NP);
3510                return;
3511            }
3512            for (int ip = 0; ip < NP; ip++) {
3513                String pkgName = in.readString();
3514                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
3515                p.mWakeups = p.mLoadedWakeups = in.readInt();
3516                p.mLastWakeups = in.readInt();
3517                final int NS = in.readInt();
3518                for (int is = 0; is < NS; is++) {
3519                    String servName = in.readString();
3520                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
3521                    s.mStartTime = s.mLoadedStartTime = in.readLong();
3522                    s.mLastStartTime = in.readLong();
3523                    s.mStarts = s.mLoadedStarts = in.readInt();
3524                    s.mLastStarts = in.readInt();
3525                    s.mLaunches = s.mLoadedLaunches = in.readInt();
3526                    s.mLastLaunches = in.readInt();
3527                }
3528            }
3529
3530            u.mLoadedTcpBytesReceived = in.readLong();
3531            u.mLoadedTcpBytesSent = in.readLong();
3532        }
3533    }
3534
3535    /**
3536     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
3537     * disk.  This format does not allow a lossless round-trip.
3538     *
3539     * @param out the Parcel to be written to.
3540     */
3541    public void writeSummaryToParcel(Parcel out) {
3542        final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
3543        final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
3544        final long NOW = getBatteryUptimeLocked(NOW_SYS);
3545        final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
3546
3547        out.writeInt(VERSION);
3548
3549        writeHistory(out);
3550
3551        out.writeInt(mStartCount);
3552        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_TOTAL));
3553        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_CURRENT));
3554        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_TOTAL));
3555        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_CURRENT));
3556        out.writeLong(computeUptime(NOW_SYS, STATS_TOTAL));
3557        out.writeLong(computeUptime(NOW_SYS, STATS_CURRENT));
3558        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_TOTAL));
3559        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_CURRENT));
3560        out.writeInt(mDischargeStartLevel);
3561        out.writeInt(mDischargeCurrentLevel);
3562
3563
3564        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3565        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3566            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
3567        }
3568        mInputEventCounter.writeSummaryFromParcelLocked(out);
3569        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3570        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3571            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
3572        }
3573        mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3574        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3575            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
3576        }
3577        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3578        mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3579        mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3580
3581        out.writeInt(mKernelWakelockStats.size());
3582        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
3583            Timer kwlt = ent.getValue();
3584            if (kwlt != null) {
3585                out.writeInt(1);
3586                out.writeString(ent.getKey());
3587                ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
3588            } else {
3589                out.writeInt(0);
3590            }
3591        }
3592
3593        out.writeInt(sNumSpeedSteps);
3594        final int NU = mUidStats.size();
3595        out.writeInt(NU);
3596        for (int iu = 0; iu < NU; iu++) {
3597            out.writeInt(mUidStats.keyAt(iu));
3598            Uid u = mUidStats.valueAt(iu);
3599
3600            u.mWifiTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3601            u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3602            u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3603            u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3604            u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3605            u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3606
3607            if (u.mUserActivityCounters == null) {
3608                out.writeInt(0);
3609            } else {
3610                out.writeInt(1);
3611                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
3612                    u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
3613                }
3614            }
3615
3616            int NW = u.mWakelockStats.size();
3617            out.writeInt(NW);
3618            if (NW > 0) {
3619                for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
3620                        : u.mWakelockStats.entrySet()) {
3621                    out.writeString(ent.getKey());
3622                    Uid.Wakelock wl = ent.getValue();
3623                    if (wl.mTimerFull != null) {
3624                        out.writeInt(1);
3625                        wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
3626                    } else {
3627                        out.writeInt(0);
3628                    }
3629                    if (wl.mTimerPartial != null) {
3630                        out.writeInt(1);
3631                        wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
3632                    } else {
3633                        out.writeInt(0);
3634                    }
3635                    if (wl.mTimerWindow != null) {
3636                        out.writeInt(1);
3637                        wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
3638                    } else {
3639                        out.writeInt(0);
3640                    }
3641                }
3642            }
3643
3644            int NSE = u.mSensorStats.size();
3645            out.writeInt(NSE);
3646            if (NSE > 0) {
3647                for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
3648                        : u.mSensorStats.entrySet()) {
3649                    out.writeInt(ent.getKey());
3650                    Uid.Sensor se = ent.getValue();
3651                    if (se.mTimer != null) {
3652                        out.writeInt(1);
3653                        se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3654                    } else {
3655                        out.writeInt(0);
3656                    }
3657                }
3658            }
3659
3660            int NP = u.mProcessStats.size();
3661            out.writeInt(NP);
3662            if (NP > 0) {
3663                for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
3664                    : u.mProcessStats.entrySet()) {
3665                    out.writeString(ent.getKey());
3666                    Uid.Proc ps = ent.getValue();
3667                    out.writeLong(ps.mUserTime);
3668                    out.writeLong(ps.mUserTime - ps.mLoadedUserTime);
3669                    out.writeLong(ps.mSystemTime);
3670                    out.writeLong(ps.mSystemTime - ps.mLoadedSystemTime);
3671                    out.writeInt(ps.mStarts);
3672                    out.writeInt(ps.mStarts - ps.mLoadedStarts);
3673                }
3674            }
3675
3676            NP = u.mPackageStats.size();
3677            out.writeInt(NP);
3678            if (NP > 0) {
3679                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
3680                    : u.mPackageStats.entrySet()) {
3681                    out.writeString(ent.getKey());
3682                    Uid.Pkg ps = ent.getValue();
3683                    out.writeInt(ps.mWakeups);
3684                    out.writeInt(ps.mWakeups - ps.mLoadedWakeups);
3685                    final int NS = ps.mServiceStats.size();
3686                    out.writeInt(NS);
3687                    if (NS > 0) {
3688                        for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
3689                                : ps.mServiceStats.entrySet()) {
3690                            out.writeString(sent.getKey());
3691                            BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
3692                            long time = ss.getStartTimeToNowLocked(NOW);
3693                            out.writeLong(time);
3694                            out.writeLong(time - ss.mLoadedStartTime);
3695                            out.writeInt(ss.mStarts);
3696                            out.writeInt(ss.mStarts - ss.mLoadedStarts);
3697                            out.writeInt(ss.mLaunches);
3698                            out.writeInt(ss.mLaunches - ss.mLoadedLaunches);
3699                        }
3700                    }
3701                }
3702            }
3703
3704            out.writeLong(u.getTcpBytesReceived(STATS_TOTAL));
3705            out.writeLong(u.getTcpBytesSent(STATS_TOTAL));
3706        }
3707    }
3708
3709    public void readFromParcel(Parcel in) {
3710        readFromParcelLocked(in);
3711    }
3712
3713    void readFromParcelLocked(Parcel in) {
3714        int magic = in.readInt();
3715        if (magic != MAGIC) {
3716            throw new ParcelFormatException("Bad magic number");
3717        }
3718
3719        readHistory(in);
3720
3721        mStartCount = in.readInt();
3722        mBatteryUptime = in.readLong();
3723        mBatteryLastUptime = in.readLong();
3724        mBatteryRealtime = in.readLong();
3725        mBatteryLastRealtime = in.readLong();
3726        mScreenOn = false;
3727        mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables, in);
3728        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3729            mScreenBrightnessTimer[i] = new StopwatchTimer(-100-i, null, mUnpluggables, in);
3730        }
3731        mInputEventCounter = new Counter(mUnpluggables, in);
3732        mPhoneOn = false;
3733        mPhoneOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
3734        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3735            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(-200-i, null, mUnpluggables, in);
3736        }
3737        mPhoneSignalScanningTimer = new StopwatchTimer(-200+1, null, mUnpluggables, in);
3738        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3739            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(-300-i, null, mUnpluggables, in);
3740        }
3741        mWifiOn = false;
3742        mWifiOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
3743        mWifiRunning = false;
3744        mWifiRunningTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
3745        mBluetoothOn = false;
3746        mBluetoothOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
3747        mUptime = in.readLong();
3748        mUptimeStart = in.readLong();
3749        mLastUptime = in.readLong();
3750        mRealtime = in.readLong();
3751        mRealtimeStart = in.readLong();
3752        mLastRealtime = in.readLong();
3753        mOnBattery = in.readInt() != 0;
3754        mOnBatteryInternal = false; // we are no longer really running.
3755        mTrackBatteryPastUptime = in.readLong();
3756        mTrackBatteryUptimeStart = in.readLong();
3757        mTrackBatteryPastRealtime = in.readLong();
3758        mTrackBatteryRealtimeStart = in.readLong();
3759        mUnpluggedBatteryUptime = in.readLong();
3760        mUnpluggedBatteryRealtime = in.readLong();
3761        mDischargeStartLevel = in.readInt();
3762        mDischargeCurrentLevel = in.readInt();
3763        mLastWriteTime = in.readLong();
3764
3765        mMobileDataRx[STATS_LAST] = in.readLong();
3766        mMobileDataRx[STATS_UNPLUGGED] = -1;
3767        mMobileDataTx[STATS_LAST] = in.readLong();
3768        mMobileDataTx[STATS_UNPLUGGED] = -1;
3769        mTotalDataRx[STATS_LAST] = in.readLong();
3770        mTotalDataRx[STATS_UNPLUGGED] = -1;
3771        mTotalDataTx[STATS_LAST] = in.readLong();
3772        mTotalDataTx[STATS_UNPLUGGED] = -1;
3773
3774        mRadioDataUptime = in.readLong();
3775        mRadioDataStart = -1;
3776
3777        mBluetoothPingCount = in.readInt();
3778        mBluetoothPingStart = -1;
3779
3780        mKernelWakelockStats.clear();
3781        int NKW = in.readInt();
3782        for (int ikw = 0; ikw < NKW; ikw++) {
3783            if (in.readInt() != 0) {
3784                String wakelockName = in.readString();
3785                in.readInt(); // Extra 0/1 written by Timer.writeTimerToParcel
3786                SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
3787                mKernelWakelockStats.put(wakelockName, kwlt);
3788            }
3789        }
3790
3791        mPartialTimers.clear();
3792        mFullTimers.clear();
3793        mWindowTimers.clear();
3794
3795        sNumSpeedSteps = in.readInt();
3796
3797        int numUids = in.readInt();
3798        mUidStats.clear();
3799        for (int i = 0; i < numUids; i++) {
3800            int uid = in.readInt();
3801            Uid u = new Uid(uid);
3802            u.readFromParcelLocked(mUnpluggables, in);
3803            mUidStats.append(uid, u);
3804        }
3805    }
3806
3807    public void writeToParcel(Parcel out, int flags) {
3808        writeToParcelLocked(out, flags);
3809    }
3810
3811    @SuppressWarnings("unused")
3812    void writeToParcelLocked(Parcel out, int flags) {
3813        final long uSecUptime = SystemClock.uptimeMillis() * 1000;
3814        final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
3815        final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
3816        final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
3817
3818        out.writeInt(MAGIC);
3819
3820        writeHistory(out);
3821
3822        out.writeInt(mStartCount);
3823        out.writeLong(mBatteryUptime);
3824        out.writeLong(mBatteryLastUptime);
3825        out.writeLong(mBatteryRealtime);
3826        out.writeLong(mBatteryLastRealtime);
3827        mScreenOnTimer.writeToParcel(out, batteryRealtime);
3828        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3829            mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
3830        }
3831        mInputEventCounter.writeToParcel(out);
3832        mPhoneOnTimer.writeToParcel(out, batteryRealtime);
3833        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3834            mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
3835        }
3836        mPhoneSignalScanningTimer.writeToParcel(out, batteryRealtime);
3837        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3838            mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
3839        }
3840        mWifiOnTimer.writeToParcel(out, batteryRealtime);
3841        mWifiRunningTimer.writeToParcel(out, batteryRealtime);
3842        mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
3843        out.writeLong(mUptime);
3844        out.writeLong(mUptimeStart);
3845        out.writeLong(mLastUptime);
3846        out.writeLong(mRealtime);
3847        out.writeLong(mRealtimeStart);
3848        out.writeLong(mLastRealtime);
3849        out.writeInt(mOnBattery ? 1 : 0);
3850        out.writeLong(batteryUptime);
3851        out.writeLong(mTrackBatteryUptimeStart);
3852        out.writeLong(batteryRealtime);
3853        out.writeLong(mTrackBatteryRealtimeStart);
3854        out.writeLong(mUnpluggedBatteryUptime);
3855        out.writeLong(mUnpluggedBatteryRealtime);
3856        out.writeInt(mDischargeStartLevel);
3857        out.writeInt(mDischargeCurrentLevel);
3858        out.writeLong(mLastWriteTime);
3859
3860        out.writeLong(getMobileTcpBytesReceived(STATS_UNPLUGGED));
3861        out.writeLong(getMobileTcpBytesSent(STATS_UNPLUGGED));
3862        out.writeLong(getTotalTcpBytesReceived(STATS_UNPLUGGED));
3863        out.writeLong(getTotalTcpBytesSent(STATS_UNPLUGGED));
3864
3865        // Write radio uptime for data
3866        out.writeLong(getRadioDataUptime());
3867
3868        out.writeInt(getBluetoothPingCount());
3869
3870        out.writeInt(mKernelWakelockStats.size());
3871        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
3872            SamplingTimer kwlt = ent.getValue();
3873            if (kwlt != null) {
3874                out.writeInt(1);
3875                out.writeString(ent.getKey());
3876                Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
3877            } else {
3878                out.writeInt(0);
3879            }
3880        }
3881
3882        out.writeInt(sNumSpeedSteps);
3883
3884        int size = mUidStats.size();
3885        out.writeInt(size);
3886        for (int i = 0; i < size; i++) {
3887            out.writeInt(mUidStats.keyAt(i));
3888            Uid uid = mUidStats.valueAt(i);
3889
3890            uid.writeToParcelLocked(out, batteryRealtime);
3891        }
3892    }
3893
3894    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
3895        new Parcelable.Creator<BatteryStatsImpl>() {
3896        public BatteryStatsImpl createFromParcel(Parcel in) {
3897            return new BatteryStatsImpl(in);
3898        }
3899
3900        public BatteryStatsImpl[] newArray(int size) {
3901            return new BatteryStatsImpl[size];
3902        }
3903    };
3904
3905    public void dumpLocked(PrintWriter pw) {
3906        if (DEBUG) {
3907            Printer pr = new PrintWriterPrinter(pw);
3908            pr.println("*** Screen timer:");
3909            mScreenOnTimer.logState(pr, "  ");
3910            for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3911                pr.println("*** Screen brightness #" + i + ":");
3912                mScreenBrightnessTimer[i].logState(pr, "  ");
3913            }
3914            pr.println("*** Input event counter:");
3915            mInputEventCounter.logState(pr, "  ");
3916            pr.println("*** Phone timer:");
3917            mPhoneOnTimer.logState(pr, "  ");
3918            for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3919                pr.println("*** Signal strength #" + i + ":");
3920                mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
3921            }
3922            pr.println("*** Signal scanning :");
3923            mPhoneSignalScanningTimer.logState(pr, "  ");
3924            for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3925                pr.println("*** Data connection type #" + i + ":");
3926                mPhoneDataConnectionsTimer[i].logState(pr, "  ");
3927            }
3928            pr.println("*** Wifi timer:");
3929            mWifiOnTimer.logState(pr, "  ");
3930            pr.println("*** WifiRunning timer:");
3931            mWifiRunningTimer.logState(pr, "  ");
3932            pr.println("*** Bluetooth timer:");
3933            mBluetoothOnTimer.logState(pr, "  ");
3934        }
3935        super.dumpLocked(pw);
3936    }
3937}
3938