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