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