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