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