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