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