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