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