BatteryStatsImpl.java revision d8593312296fd2193a070c1a074840d83b7f49cb
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    @Override public long getScreenOnTime(long batteryRealtime, int which) {
1120        return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
1121    }
1122
1123    @Override public long getScreenBrightnessTime(int brightnessBin,
1124            long batteryRealtime, int which) {
1125        return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
1126                batteryRealtime, which);
1127    }
1128
1129    @Override public int getInputEventCount(int which) {
1130        return mInputEventCounter.getCountLocked(which);
1131    }
1132
1133    @Override public long getPhoneOnTime(long batteryRealtime, int which) {
1134        return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
1135    }
1136
1137    @Override public long getPhoneSignalStrengthTime(int strengthBin,
1138            long batteryRealtime, int which) {
1139        return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
1140                batteryRealtime, which);
1141    }
1142
1143    @Override public int getPhoneSignalStrengthCount(int dataType, int which) {
1144        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
1145    }
1146
1147    @Override public long getPhoneDataConnectionTime(int dataType,
1148            long batteryRealtime, int which) {
1149        return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
1150                batteryRealtime, which);
1151    }
1152
1153    @Override public int getPhoneDataConnectionCount(int dataType, int which) {
1154        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
1155    }
1156
1157    @Override public long getWifiOnTime(long batteryRealtime, int which) {
1158        return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
1159    }
1160
1161    @Override public long getWifiRunningTime(long batteryRealtime, int which) {
1162        return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
1163    }
1164
1165    @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
1166        return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
1167    }
1168
1169    @Override public boolean getIsOnBattery() {
1170        return mOnBattery;
1171    }
1172
1173    @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
1174        return mUidStats;
1175    }
1176
1177    /**
1178     * The statistics associated with a particular uid.
1179     */
1180    public final class Uid extends BatteryStats.Uid {
1181
1182        final int mUid;
1183        long mLoadedTcpBytesReceived;
1184        long mLoadedTcpBytesSent;
1185        long mCurrentTcpBytesReceived;
1186        long mCurrentTcpBytesSent;
1187        long mTcpBytesReceivedAtLastUnplug;
1188        long mTcpBytesSentAtLastUnplug;
1189
1190        // These are not saved/restored when parcelling, since we want
1191        // to return from the parcel with a snapshot of the state.
1192        long mStartedTcpBytesReceived = -1;
1193        long mStartedTcpBytesSent = -1;
1194
1195        boolean mWifiTurnedOn;
1196        StopwatchTimer mWifiTurnedOnTimer;
1197
1198        boolean mFullWifiLockOut;
1199        StopwatchTimer mFullWifiLockTimer;
1200
1201        boolean mScanWifiLockOut;
1202        StopwatchTimer mScanWifiLockTimer;
1203
1204        Counter[] mUserActivityCounters;
1205
1206        /**
1207         * The statistics we have collected for this uid's wake locks.
1208         */
1209        final HashMap<String, Wakelock> mWakelockStats = new HashMap<String, Wakelock>();
1210
1211        /**
1212         * The statistics we have collected for this uid's sensor activations.
1213         */
1214        final HashMap<Integer, Sensor> mSensorStats = new HashMap<Integer, Sensor>();
1215
1216        /**
1217         * The statistics we have collected for this uid's processes.
1218         */
1219        final HashMap<String, Proc> mProcessStats = new HashMap<String, Proc>();
1220
1221        /**
1222         * The statistics we have collected for this uid's processes.
1223         */
1224        final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
1225
1226        public Uid(int uid) {
1227            mUid = uid;
1228            mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables);
1229            mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables);
1230            mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables);
1231        }
1232
1233        @Override
1234        public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
1235            return mWakelockStats;
1236        }
1237
1238        @Override
1239        public Map<Integer, ? extends BatteryStats.Uid.Sensor> getSensorStats() {
1240            return mSensorStats;
1241        }
1242
1243        @Override
1244        public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
1245            return mProcessStats;
1246        }
1247
1248        @Override
1249        public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
1250            return mPackageStats;
1251        }
1252
1253        public int getUid() {
1254            return mUid;
1255        }
1256
1257        public long getTcpBytesReceived(int which) {
1258            if (which == STATS_LAST) {
1259                return mLoadedTcpBytesReceived;
1260            } else {
1261                long current = computeCurrentTcpBytesReceived();
1262                if (which == STATS_UNPLUGGED) {
1263                    current -= mTcpBytesReceivedAtLastUnplug;
1264                } else if (which == STATS_TOTAL) {
1265                    current += mLoadedTcpBytesReceived;
1266                }
1267                return current;
1268            }
1269        }
1270
1271        public long computeCurrentTcpBytesReceived() {
1272            return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
1273                    ? (NetStat.getUidRxBytes(mUid) - mStartedTcpBytesReceived) : 0);
1274        }
1275
1276        public long getTcpBytesSent(int which) {
1277            if (which == STATS_LAST) {
1278                return mLoadedTcpBytesSent;
1279            } else {
1280                long current = computeCurrentTcpBytesSent();
1281                if (which == STATS_UNPLUGGED) {
1282                    current -= mTcpBytesSentAtLastUnplug;
1283                } else if (which == STATS_TOTAL) {
1284                    current += mLoadedTcpBytesSent;
1285                }
1286                return current;
1287            }
1288        }
1289
1290        @Override
1291        public void noteWifiTurnedOnLocked() {
1292            if (!mWifiTurnedOn) {
1293                mWifiTurnedOn = true;
1294                mWifiTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
1295            }
1296        }
1297
1298        @Override
1299        public void noteWifiTurnedOffLocked() {
1300            if (mWifiTurnedOn) {
1301                mWifiTurnedOn = false;
1302                mWifiTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
1303            }
1304        }
1305
1306        @Override
1307        public void noteFullWifiLockAcquiredLocked() {
1308            if (!mFullWifiLockOut) {
1309                mFullWifiLockOut = true;
1310                mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
1311            }
1312        }
1313
1314        @Override
1315        public void noteFullWifiLockReleasedLocked() {
1316            if (mFullWifiLockOut) {
1317                mFullWifiLockOut = false;
1318                mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
1319            }
1320        }
1321
1322        @Override
1323        public void noteScanWifiLockAcquiredLocked() {
1324            if (!mScanWifiLockOut) {
1325                mScanWifiLockOut = true;
1326                mScanWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
1327            }
1328        }
1329
1330        @Override
1331        public void noteScanWifiLockReleasedLocked() {
1332            if (mScanWifiLockOut) {
1333                mScanWifiLockOut = false;
1334                mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
1335            }
1336        }
1337
1338        @Override
1339        public long getWifiTurnedOnTime(long batteryRealtime, int which) {
1340            return mWifiTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
1341        }
1342
1343        @Override
1344        public long getFullWifiLockTime(long batteryRealtime, int which) {
1345            return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
1346        }
1347
1348        @Override
1349        public long getScanWifiLockTime(long batteryRealtime, int which) {
1350            return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
1351        }
1352
1353        @Override
1354        public void noteUserActivityLocked(int type) {
1355            if (mUserActivityCounters == null) {
1356                initUserActivityLocked();
1357            }
1358            if (type < 0) type = 0;
1359            else if (type >= NUM_USER_ACTIVITY_TYPES) type = NUM_USER_ACTIVITY_TYPES-1;
1360            mUserActivityCounters[type].stepLocked();
1361        }
1362
1363        @Override
1364        public boolean hasUserActivity() {
1365            return mUserActivityCounters != null;
1366        }
1367
1368        @Override
1369        public int getUserActivityCount(int type, int which) {
1370            if (mUserActivityCounters == null) {
1371                return 0;
1372            }
1373            return mUserActivityCounters[type].getCountLocked(which);
1374        }
1375
1376        void initUserActivityLocked() {
1377            mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
1378            for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
1379                mUserActivityCounters[i] = new Counter(mUnpluggables);
1380            }
1381        }
1382
1383        public long computeCurrentTcpBytesSent() {
1384            return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
1385                    ? (NetStat.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
1386        }
1387
1388        void writeToParcelLocked(Parcel out, long batteryRealtime) {
1389            out.writeInt(mWakelockStats.size());
1390            for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
1391                out.writeString(wakelockEntry.getKey());
1392                Uid.Wakelock wakelock = wakelockEntry.getValue();
1393                wakelock.writeToParcelLocked(out, batteryRealtime);
1394            }
1395
1396            out.writeInt(mSensorStats.size());
1397            for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
1398                out.writeInt(sensorEntry.getKey());
1399                Uid.Sensor sensor = sensorEntry.getValue();
1400                sensor.writeToParcelLocked(out, batteryRealtime);
1401            }
1402
1403            out.writeInt(mProcessStats.size());
1404            for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
1405                out.writeString(procEntry.getKey());
1406                Uid.Proc proc = procEntry.getValue();
1407                proc.writeToParcelLocked(out);
1408            }
1409
1410            out.writeInt(mPackageStats.size());
1411            for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
1412                out.writeString(pkgEntry.getKey());
1413                Uid.Pkg pkg = pkgEntry.getValue();
1414                pkg.writeToParcelLocked(out);
1415            }
1416
1417            out.writeLong(mLoadedTcpBytesReceived);
1418            out.writeLong(mLoadedTcpBytesSent);
1419            out.writeLong(computeCurrentTcpBytesReceived());
1420            out.writeLong(computeCurrentTcpBytesSent());
1421            out.writeLong(mTcpBytesReceivedAtLastUnplug);
1422            out.writeLong(mTcpBytesSentAtLastUnplug);
1423            mWifiTurnedOnTimer.writeToParcel(out, batteryRealtime);
1424            mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
1425            mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
1426            if (mUserActivityCounters == null) {
1427                out.writeInt(0);
1428            } else {
1429                out.writeInt(1);
1430                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
1431                    mUserActivityCounters[i].writeToParcel(out);
1432                }
1433            }
1434        }
1435
1436        void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
1437            int numWakelocks = in.readInt();
1438            mWakelockStats.clear();
1439            for (int j = 0; j < numWakelocks; j++) {
1440                String wakelockName = in.readString();
1441                Uid.Wakelock wakelock = new Wakelock();
1442                wakelock.readFromParcelLocked(unpluggables, in);
1443                mWakelockStats.put(wakelockName, wakelock);
1444            }
1445
1446            int numSensors = in.readInt();
1447            mSensorStats.clear();
1448            for (int k = 0; k < numSensors; k++) {
1449                int sensorNumber = in.readInt();
1450                Uid.Sensor sensor = new Sensor(sensorNumber);
1451                sensor.readFromParcelLocked(mUnpluggables, in);
1452                mSensorStats.put(sensorNumber, sensor);
1453            }
1454
1455            int numProcs = in.readInt();
1456            mProcessStats.clear();
1457            for (int k = 0; k < numProcs; k++) {
1458                String processName = in.readString();
1459                Uid.Proc proc = new Proc();
1460                proc.readFromParcelLocked(in);
1461                mProcessStats.put(processName, proc);
1462            }
1463
1464            int numPkgs = in.readInt();
1465            mPackageStats.clear();
1466            for (int l = 0; l < numPkgs; l++) {
1467                String packageName = in.readString();
1468                Uid.Pkg pkg = new Pkg();
1469                pkg.readFromParcelLocked(in);
1470                mPackageStats.put(packageName, pkg);
1471            }
1472
1473            mLoadedTcpBytesReceived = in.readLong();
1474            mLoadedTcpBytesSent = in.readLong();
1475            mCurrentTcpBytesReceived = in.readLong();
1476            mCurrentTcpBytesSent = in.readLong();
1477            mTcpBytesReceivedAtLastUnplug = in.readLong();
1478            mTcpBytesSentAtLastUnplug = in.readLong();
1479            mWifiTurnedOn = false;
1480            mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables, in);
1481            mFullWifiLockOut = false;
1482            mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables, in);
1483            mScanWifiLockOut = false;
1484            mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables, in);
1485            if (in.readInt() == 0) {
1486                mUserActivityCounters = null;
1487            } else {
1488                mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
1489                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
1490                    mUserActivityCounters[i] = new Counter(mUnpluggables, in);
1491                }
1492            }
1493        }
1494
1495        /**
1496         * The statistics associated with a particular wake lock.
1497         */
1498        public final class Wakelock extends BatteryStats.Uid.Wakelock {
1499            /**
1500             * How long (in ms) this uid has been keeping the device partially awake.
1501             */
1502            StopwatchTimer mTimerPartial;
1503
1504            /**
1505             * How long (in ms) this uid has been keeping the device fully awake.
1506             */
1507            StopwatchTimer mTimerFull;
1508
1509            /**
1510             * How long (in ms) this uid has had a window keeping the device awake.
1511             */
1512            StopwatchTimer mTimerWindow;
1513
1514            /**
1515             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
1516             * proper timer pool from the given BatteryStatsImpl object.
1517             *
1518             * @param in the Parcel to be read from.
1519             * return a new Timer, or null.
1520             */
1521            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
1522                    ArrayList<Unpluggable> unpluggables, Parcel in) {
1523                if (in.readInt() == 0) {
1524                    return null;
1525                }
1526
1527                return new StopwatchTimer(type, pool, unpluggables, in);
1528            }
1529
1530            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
1531                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
1532                        mPartialTimers, unpluggables, in);
1533                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
1534                        mFullTimers, unpluggables, in);
1535                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
1536                        mWindowTimers, unpluggables, in);
1537            }
1538
1539            void writeToParcelLocked(Parcel out, long batteryRealtime) {
1540                Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
1541                Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
1542                Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
1543            }
1544
1545            @Override
1546            public Timer getWakeTime(int type) {
1547                switch (type) {
1548                case WAKE_TYPE_FULL: return mTimerFull;
1549                case WAKE_TYPE_PARTIAL: return mTimerPartial;
1550                case WAKE_TYPE_WINDOW: return mTimerWindow;
1551                default: throw new IllegalArgumentException("type = " + type);
1552                }
1553            }
1554        }
1555
1556        public final class Sensor extends BatteryStats.Uid.Sensor {
1557            final int mHandle;
1558            StopwatchTimer mTimer;
1559
1560            public Sensor(int handle) {
1561                mHandle = handle;
1562            }
1563
1564            private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
1565                    Parcel in) {
1566                if (in.readInt() == 0) {
1567                    return null;
1568                }
1569
1570                ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
1571                if (pool == null) {
1572                    pool = new ArrayList<StopwatchTimer>();
1573                    mSensorTimers.put(mHandle, pool);
1574                }
1575                return new StopwatchTimer(0, pool, unpluggables, in);
1576            }
1577
1578            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
1579                mTimer = readTimerFromParcel(unpluggables, in);
1580            }
1581
1582            void writeToParcelLocked(Parcel out, long batteryRealtime) {
1583                Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
1584            }
1585
1586            @Override
1587            public Timer getSensorTime() {
1588                return mTimer;
1589            }
1590
1591            public int getHandle() {
1592                return mHandle;
1593            }
1594        }
1595
1596        /**
1597         * The statistics associated with a particular process.
1598         */
1599        public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
1600            /**
1601             * Total time (in 1/100 sec) spent executing in user code.
1602             */
1603            long mUserTime;
1604
1605            /**
1606             * Total time (in 1/100 sec) spent executing in kernel code.
1607             */
1608            long mSystemTime;
1609
1610            /**
1611             * Number of times the process has been started.
1612             */
1613            int mStarts;
1614
1615            /**
1616             * The amount of user time loaded from a previous save.
1617             */
1618            long mLoadedUserTime;
1619
1620            /**
1621             * The amount of system time loaded from a previous save.
1622             */
1623            long mLoadedSystemTime;
1624
1625            /**
1626             * The number of times the process has started from a previous save.
1627             */
1628            int mLoadedStarts;
1629
1630            /**
1631             * The amount of user time loaded from the previous run.
1632             */
1633            long mLastUserTime;
1634
1635            /**
1636             * The amount of system time loaded from the previous run.
1637             */
1638            long mLastSystemTime;
1639
1640            /**
1641             * The number of times the process has started from the previous run.
1642             */
1643            int mLastStarts;
1644
1645            /**
1646             * The amount of user time when last unplugged.
1647             */
1648            long mUnpluggedUserTime;
1649
1650            /**
1651             * The amount of system time when last unplugged.
1652             */
1653            long mUnpluggedSystemTime;
1654
1655            /**
1656             * The number of times the process has started before unplugged.
1657             */
1658            int mUnpluggedStarts;
1659
1660            Proc() {
1661                mUnpluggables.add(this);
1662            }
1663
1664            public void unplug(long batteryUptime, long batteryRealtime) {
1665                mUnpluggedUserTime = mUserTime;
1666                mUnpluggedSystemTime = mSystemTime;
1667                mUnpluggedStarts = mStarts;
1668            }
1669
1670            public void plug(long batteryUptime, long batteryRealtime) {
1671            }
1672
1673            void writeToParcelLocked(Parcel out) {
1674                final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
1675                final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
1676
1677                out.writeLong(mUserTime);
1678                out.writeLong(mSystemTime);
1679                out.writeInt(mStarts);
1680                out.writeLong(mLoadedUserTime);
1681                out.writeLong(mLoadedSystemTime);
1682                out.writeInt(mLoadedStarts);
1683                out.writeLong(mLastUserTime);
1684                out.writeLong(mLastSystemTime);
1685                out.writeInt(mLastStarts);
1686                out.writeLong(mUnpluggedUserTime);
1687                out.writeLong(mUnpluggedSystemTime);
1688                out.writeInt(mUnpluggedStarts);
1689            }
1690
1691            void readFromParcelLocked(Parcel in) {
1692                mUserTime = in.readLong();
1693                mSystemTime = in.readLong();
1694                mStarts = in.readInt();
1695                mLoadedUserTime = in.readLong();
1696                mLoadedSystemTime = in.readLong();
1697                mLoadedStarts = in.readInt();
1698                mLastUserTime = in.readLong();
1699                mLastSystemTime = in.readLong();
1700                mLastStarts = in.readInt();
1701                mUnpluggedUserTime = in.readLong();
1702                mUnpluggedSystemTime = in.readLong();
1703                mUnpluggedStarts = in.readInt();
1704            }
1705
1706            public BatteryStatsImpl getBatteryStats() {
1707                return BatteryStatsImpl.this;
1708            }
1709
1710            public void addCpuTimeLocked(int utime, int stime) {
1711                mUserTime += utime;
1712                mSystemTime += stime;
1713            }
1714
1715            public void incStartsLocked() {
1716                mStarts++;
1717            }
1718
1719            @Override
1720            public long getUserTime(int which) {
1721                long val;
1722                if (which == STATS_LAST) {
1723                    val = mLastUserTime;
1724                } else {
1725                    val = mUserTime;
1726                    if (which == STATS_CURRENT) {
1727                        val -= mLoadedUserTime;
1728                    } else if (which == STATS_UNPLUGGED) {
1729                        val -= mUnpluggedUserTime;
1730                    }
1731                }
1732                return val;
1733            }
1734
1735            @Override
1736            public long getSystemTime(int which) {
1737                long val;
1738                if (which == STATS_LAST) {
1739                    val = mLastSystemTime;
1740                } else {
1741                    val = mSystemTime;
1742                    if (which == STATS_CURRENT) {
1743                        val -= mLoadedSystemTime;
1744                    } else if (which == STATS_UNPLUGGED) {
1745                        val -= mUnpluggedSystemTime;
1746                    }
1747                }
1748                return val;
1749            }
1750
1751            @Override
1752            public int getStarts(int which) {
1753                int val;
1754                if (which == STATS_LAST) {
1755                    val = mLastStarts;
1756                } else {
1757                    val = mStarts;
1758                    if (which == STATS_CURRENT) {
1759                        val -= mLoadedStarts;
1760                    } else if (which == STATS_UNPLUGGED) {
1761                        val -= mUnpluggedStarts;
1762                    }
1763                }
1764                return val;
1765            }
1766        }
1767
1768        /**
1769         * The statistics associated with a particular package.
1770         */
1771        public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
1772            /**
1773             * Number of times this package has done something that could wake up the
1774             * device from sleep.
1775             */
1776            int mWakeups;
1777
1778            /**
1779             * Number of things that could wake up the device loaded from a
1780             * previous save.
1781             */
1782            int mLoadedWakeups;
1783
1784            /**
1785             * Number of things that could wake up the device as of the
1786             * last run.
1787             */
1788            int mLastWakeups;
1789
1790            /**
1791             * Number of things that could wake up the device as of the
1792             * last run.
1793             */
1794            int mUnpluggedWakeups;
1795
1796            /**
1797             * The statics we have collected for this package's services.
1798             */
1799            final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
1800
1801            Pkg() {
1802                mUnpluggables.add(this);
1803            }
1804
1805            public void unplug(long batteryUptime, long batteryRealtime) {
1806                mUnpluggedWakeups = mWakeups;
1807            }
1808
1809            public void plug(long batteryUptime, long batteryRealtime) {
1810            }
1811
1812            void readFromParcelLocked(Parcel in) {
1813                mWakeups = in.readInt();
1814                mLoadedWakeups = in.readInt();
1815                mLastWakeups = in.readInt();
1816                mUnpluggedWakeups = in.readInt();
1817
1818                int numServs = in.readInt();
1819                mServiceStats.clear();
1820                for (int m = 0; m < numServs; m++) {
1821                    String serviceName = in.readString();
1822                    Uid.Pkg.Serv serv = new Serv();
1823                    mServiceStats.put(serviceName, serv);
1824
1825                    serv.readFromParcelLocked(in);
1826                }
1827            }
1828
1829            void writeToParcelLocked(Parcel out) {
1830                out.writeInt(mWakeups);
1831                out.writeInt(mLoadedWakeups);
1832                out.writeInt(mLastWakeups);
1833                out.writeInt(mUnpluggedWakeups);
1834
1835                out.writeInt(mServiceStats.size());
1836                for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
1837                    out.writeString(servEntry.getKey());
1838                    Uid.Pkg.Serv serv = servEntry.getValue();
1839
1840                    serv.writeToParcelLocked(out);
1841                }
1842            }
1843
1844            @Override
1845            public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
1846                return mServiceStats;
1847            }
1848
1849            @Override
1850            public int getWakeups(int which) {
1851                int val;
1852                if (which == STATS_LAST) {
1853                    val = mLastWakeups;
1854                } else {
1855                    val = mWakeups;
1856                    if (which == STATS_CURRENT) {
1857                        val -= mLoadedWakeups;
1858                    } else if (which == STATS_UNPLUGGED) {
1859                        val -= mUnpluggedWakeups;
1860                    }
1861                }
1862
1863                return val;
1864            }
1865
1866            /**
1867             * The statistics associated with a particular service.
1868             */
1869            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
1870                /**
1871                 * Total time (ms in battery uptime) the service has been left started.
1872                 */
1873                long mStartTime;
1874
1875                /**
1876                 * If service has been started and not yet stopped, this is
1877                 * when it was started.
1878                 */
1879                long mRunningSince;
1880
1881                /**
1882                 * True if we are currently running.
1883                 */
1884                boolean mRunning;
1885
1886                /**
1887                 * Total number of times startService() has been called.
1888                 */
1889                int mStarts;
1890
1891                /**
1892                 * Total time (ms in battery uptime) the service has been left launched.
1893                 */
1894                long mLaunchedTime;
1895
1896                /**
1897                 * If service has been launched and not yet exited, this is
1898                 * when it was launched (ms in battery uptime).
1899                 */
1900                long mLaunchedSince;
1901
1902                /**
1903                 * True if we are currently launched.
1904                 */
1905                boolean mLaunched;
1906
1907                /**
1908                 * Total number times the service has been launched.
1909                 */
1910                int mLaunches;
1911
1912                /**
1913                 * The amount of time spent started loaded from a previous save
1914                 * (ms in battery uptime).
1915                 */
1916                long mLoadedStartTime;
1917
1918                /**
1919                 * The number of starts loaded from a previous save.
1920                 */
1921                int mLoadedStarts;
1922
1923                /**
1924                 * The number of launches loaded from a previous save.
1925                 */
1926                int mLoadedLaunches;
1927
1928                /**
1929                 * The amount of time spent started as of the last run (ms
1930                 * in battery uptime).
1931                 */
1932                long mLastStartTime;
1933
1934                /**
1935                 * The number of starts as of the last run.
1936                 */
1937                int mLastStarts;
1938
1939                /**
1940                 * The number of launches as of the last run.
1941                 */
1942                int mLastLaunches;
1943
1944                /**
1945                 * The amount of time spent started when last unplugged (ms
1946                 * in battery uptime).
1947                 */
1948                long mUnpluggedStartTime;
1949
1950                /**
1951                 * The number of starts when last unplugged.
1952                 */
1953                int mUnpluggedStarts;
1954
1955                /**
1956                 * The number of launches when last unplugged.
1957                 */
1958                int mUnpluggedLaunches;
1959
1960                Serv() {
1961                    mUnpluggables.add(this);
1962                }
1963
1964                public void unplug(long batteryUptime, long batteryRealtime) {
1965                    mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
1966                    mUnpluggedStarts = mStarts;
1967                    mUnpluggedLaunches = mLaunches;
1968                }
1969
1970                public void plug(long batteryUptime, long batteryRealtime) {
1971                }
1972
1973                void readFromParcelLocked(Parcel in) {
1974                    mStartTime = in.readLong();
1975                    mRunningSince = in.readLong();
1976                    mRunning = in.readInt() != 0;
1977                    mStarts = in.readInt();
1978                    mLaunchedTime = in.readLong();
1979                    mLaunchedSince = in.readLong();
1980                    mLaunched = in.readInt() != 0;
1981                    mLaunches = in.readInt();
1982                    mLoadedStartTime = in.readLong();
1983                    mLoadedStarts = in.readInt();
1984                    mLoadedLaunches = in.readInt();
1985                    mLastStartTime = in.readLong();
1986                    mLastStarts = in.readInt();
1987                    mLastLaunches = in.readInt();
1988                    mUnpluggedStartTime = in.readLong();
1989                    mUnpluggedStarts = in.readInt();
1990                    mUnpluggedLaunches = in.readInt();
1991                }
1992
1993                void writeToParcelLocked(Parcel out) {
1994                    out.writeLong(mStartTime);
1995                    out.writeLong(mRunningSince);
1996                    out.writeInt(mRunning ? 1 : 0);
1997                    out.writeInt(mStarts);
1998                    out.writeLong(mLaunchedTime);
1999                    out.writeLong(mLaunchedSince);
2000                    out.writeInt(mLaunched ? 1 : 0);
2001                    out.writeInt(mLaunches);
2002                    out.writeLong(mLoadedStartTime);
2003                    out.writeInt(mLoadedStarts);
2004                    out.writeInt(mLoadedLaunches);
2005                    out.writeLong(mLastStartTime);
2006                    out.writeInt(mLastStarts);
2007                    out.writeInt(mLastLaunches);
2008                    out.writeLong(mUnpluggedStartTime);
2009                    out.writeInt(mUnpluggedStarts);
2010                    out.writeInt(mUnpluggedLaunches);
2011                }
2012
2013                long getLaunchTimeToNowLocked(long batteryUptime) {
2014                    if (!mLaunched) return mLaunchedTime;
2015                    return mLaunchedTime + batteryUptime - mLaunchedSince;
2016                }
2017
2018                long getStartTimeToNowLocked(long batteryUptime) {
2019                    if (!mRunning) return mStartTime;
2020                    return mStartTime + batteryUptime - mRunningSince;
2021                }
2022
2023                public void startLaunchedLocked() {
2024                    if (!mLaunched) {
2025                        mLaunches++;
2026                        mLaunchedSince = getBatteryUptimeLocked();
2027                        mLaunched = true;
2028                    }
2029                }
2030
2031                public void stopLaunchedLocked() {
2032                    if (mLaunched) {
2033                        long time = getBatteryUptimeLocked() - mLaunchedSince;
2034                        if (time > 0) {
2035                            mLaunchedTime += time;
2036                        } else {
2037                            mLaunches--;
2038                        }
2039                        mLaunched = false;
2040                    }
2041                }
2042
2043                public void startRunningLocked() {
2044                    if (!mRunning) {
2045                        mStarts++;
2046                        mRunningSince = getBatteryUptimeLocked();
2047                        mRunning = true;
2048                    }
2049                }
2050
2051                public void stopRunningLocked() {
2052                    if (mRunning) {
2053                        long time = getBatteryUptimeLocked() - mRunningSince;
2054                        if (time > 0) {
2055                            mStartTime += time;
2056                        } else {
2057                            mStarts--;
2058                        }
2059                        mRunning = false;
2060                    }
2061                }
2062
2063                public BatteryStatsImpl getBatteryStats() {
2064                    return BatteryStatsImpl.this;
2065                }
2066
2067                @Override
2068                public int getLaunches(int which) {
2069                    int val;
2070
2071                    if (which == STATS_LAST) {
2072                        val = mLastLaunches;
2073                    } else {
2074                        val = mLaunches;
2075                        if (which == STATS_CURRENT) {
2076                            val -= mLoadedLaunches;
2077                        } else if (which == STATS_UNPLUGGED) {
2078                            val -= mUnpluggedLaunches;
2079                        }
2080                    }
2081
2082                    return val;
2083                }
2084
2085                @Override
2086                public long getStartTime(long now, int which) {
2087                    long val;
2088                    if (which == STATS_LAST) {
2089                        val = mLastStartTime;
2090                    } else {
2091                        val = getStartTimeToNowLocked(now);
2092                        if (which == STATS_CURRENT) {
2093                            val -= mLoadedStartTime;
2094                        } else if (which == STATS_UNPLUGGED) {
2095                            val -= mUnpluggedStartTime;
2096                        }
2097                    }
2098
2099                    return val;
2100                }
2101
2102                @Override
2103                public int getStarts(int which) {
2104                    int val;
2105                    if (which == STATS_LAST) {
2106                        val = mLastStarts;
2107                    } else {
2108                        val = mStarts;
2109                        if (which == STATS_CURRENT) {
2110                            val -= mLoadedStarts;
2111                        } else if (which == STATS_UNPLUGGED) {
2112                            val -= mUnpluggedStarts;
2113                        }
2114                    }
2115
2116                    return val;
2117                }
2118            }
2119
2120            public BatteryStatsImpl getBatteryStats() {
2121                return BatteryStatsImpl.this;
2122            }
2123
2124            public void incWakeupsLocked() {
2125                mWakeups++;
2126            }
2127
2128            final Serv newServiceStatsLocked() {
2129                return new Serv();
2130            }
2131        }
2132
2133        /**
2134         * Retrieve the statistics object for a particular process, creating
2135         * if needed.
2136         */
2137        public Proc getProcessStatsLocked(String name) {
2138            Proc ps = mProcessStats.get(name);
2139            if (ps == null) {
2140                ps = new Proc();
2141                mProcessStats.put(name, ps);
2142            }
2143
2144            return ps;
2145        }
2146
2147        /**
2148         * Retrieve the statistics object for a particular service, creating
2149         * if needed.
2150         */
2151        public Pkg getPackageStatsLocked(String name) {
2152            Pkg ps = mPackageStats.get(name);
2153            if (ps == null) {
2154                ps = new Pkg();
2155                mPackageStats.put(name, ps);
2156            }
2157
2158            return ps;
2159        }
2160
2161        /**
2162         * Retrieve the statistics object for a particular service, creating
2163         * if needed.
2164         */
2165        public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
2166            Pkg ps = getPackageStatsLocked(pkg);
2167            Pkg.Serv ss = ps.mServiceStats.get(serv);
2168            if (ss == null) {
2169                ss = ps.newServiceStatsLocked();
2170                ps.mServiceStats.put(serv, ss);
2171            }
2172
2173            return ss;
2174        }
2175
2176        public StopwatchTimer getWakeTimerLocked(String name, int type) {
2177            Wakelock wl = mWakelockStats.get(name);
2178            if (wl == null) {
2179                wl = new Wakelock();
2180                mWakelockStats.put(name, wl);
2181            }
2182            StopwatchTimer t = null;
2183            switch (type) {
2184                case WAKE_TYPE_PARTIAL:
2185                    t = wl.mTimerPartial;
2186                    if (t == null) {
2187                        t = new StopwatchTimer(WAKE_TYPE_PARTIAL, mPartialTimers, mUnpluggables);
2188                        wl.mTimerPartial = t;
2189                    }
2190                    return t;
2191                case WAKE_TYPE_FULL:
2192                    t = wl.mTimerFull;
2193                    if (t == null) {
2194                        t = new StopwatchTimer(WAKE_TYPE_FULL, mFullTimers, mUnpluggables);
2195                        wl.mTimerFull = t;
2196                    }
2197                    return t;
2198                case WAKE_TYPE_WINDOW:
2199                    t = wl.mTimerWindow;
2200                    if (t == null) {
2201                        t = new StopwatchTimer(WAKE_TYPE_WINDOW, mWindowTimers, mUnpluggables);
2202                        wl.mTimerWindow = t;
2203                    }
2204                    return t;
2205                default:
2206                    throw new IllegalArgumentException("type=" + type);
2207            }
2208        }
2209
2210        public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
2211            Sensor se = mSensorStats.get(sensor);
2212            if (se == null) {
2213                if (!create) {
2214                    return null;
2215                }
2216                se = new Sensor(sensor);
2217                mSensorStats.put(sensor, se);
2218            }
2219            StopwatchTimer t = se.mTimer;
2220            if (t != null) {
2221                return t;
2222            }
2223            ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
2224            if (timers == null) {
2225                timers = new ArrayList<StopwatchTimer>();
2226                mSensorTimers.put(sensor, timers);
2227            }
2228            t = new StopwatchTimer(BatteryStats.SENSOR, timers, mUnpluggables);
2229            se.mTimer = t;
2230            return t;
2231        }
2232
2233        public void noteStartWakeLocked(String name, int type) {
2234            StopwatchTimer t = getWakeTimerLocked(name, type);
2235            if (t != null) {
2236                t.startRunningLocked(BatteryStatsImpl.this);
2237            }
2238        }
2239
2240        public void noteStopWakeLocked(String name, int type) {
2241            StopwatchTimer t = getWakeTimerLocked(name, type);
2242            if (t != null) {
2243                t.stopRunningLocked(BatteryStatsImpl.this);
2244            }
2245        }
2246
2247        public void noteStartSensor(int sensor) {
2248            StopwatchTimer t = getSensorTimerLocked(sensor, true);
2249            if (t != null) {
2250                t.startRunningLocked(BatteryStatsImpl.this);
2251            }
2252        }
2253
2254        public void noteStopSensor(int sensor) {
2255            // Don't create a timer if one doesn't already exist
2256            StopwatchTimer t = getSensorTimerLocked(sensor, false);
2257            if (t != null) {
2258                t.stopRunningLocked(BatteryStatsImpl.this);
2259            }
2260        }
2261
2262        public void noteStartGps() {
2263            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
2264            if (t != null) {
2265                t.startRunningLocked(BatteryStatsImpl.this);
2266            }
2267        }
2268
2269        public void noteStopGps() {
2270            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
2271            if (t != null) {
2272                t.stopRunningLocked(BatteryStatsImpl.this);
2273            }
2274        }
2275
2276        public BatteryStatsImpl getBatteryStats() {
2277            return BatteryStatsImpl.this;
2278        }
2279    }
2280
2281    public BatteryStatsImpl(String filename) {
2282        mFile = new File(filename);
2283        mBackupFile = new File(filename + ".bak");
2284        mStartCount++;
2285        mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables);
2286        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
2287            mScreenBrightnessTimer[i] = new StopwatchTimer(-100-i, null, mUnpluggables);
2288        }
2289        mInputEventCounter = new Counter(mUnpluggables);
2290        mPhoneOnTimer = new StopwatchTimer(-2, null, mUnpluggables);
2291        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
2292            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(-200-i, null, mUnpluggables);
2293        }
2294        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
2295            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(-300-i, null, mUnpluggables);
2296        }
2297        mWifiOnTimer = new StopwatchTimer(-3, null, mUnpluggables);
2298        mWifiRunningTimer = new StopwatchTimer(-4, null, mUnpluggables);
2299        mBluetoothOnTimer = new StopwatchTimer(-5, null, mUnpluggables);
2300        mOnBattery = mOnBatteryInternal = false;
2301        mTrackBatteryPastUptime = 0;
2302        mTrackBatteryPastRealtime = 0;
2303        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
2304        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
2305        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
2306        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
2307        mDischargeStartLevel = 0;
2308        mDischargeCurrentLevel = 0;
2309    }
2310
2311    public BatteryStatsImpl(Parcel p) {
2312        mFile = mBackupFile = null;
2313        readFromParcel(p);
2314    }
2315
2316    @Override
2317    public int getStartCount() {
2318        return mStartCount;
2319    }
2320
2321    public boolean isOnBattery() {
2322        return mOnBattery;
2323    }
2324
2325    public void setOnBattery(boolean onBattery, int level) {
2326        synchronized(this) {
2327            updateKernelWakelocksLocked();
2328            if (mOnBattery != onBattery) {
2329                mOnBattery = mOnBatteryInternal = onBattery;
2330
2331                long uptime = SystemClock.uptimeMillis() * 1000;
2332                long mSecRealtime = SystemClock.elapsedRealtime();
2333                long realtime = mSecRealtime * 1000;
2334                if (onBattery) {
2335                    mTrackBatteryUptimeStart = uptime;
2336                    mTrackBatteryRealtimeStart = realtime;
2337                    mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
2338                    mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
2339                    mDischargeCurrentLevel = mDischargeStartLevel = level;
2340                    doUnplug(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
2341                } else {
2342                    mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
2343                    mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
2344                    mDischargeCurrentLevel = level;
2345                    doPlug(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
2346                }
2347                if ((mLastWriteTime + (60 * 1000)) < mSecRealtime) {
2348                    if (mFile != null) {
2349                        writeLocked();
2350                    }
2351                }
2352            }
2353        }
2354    }
2355
2356    public void recordCurrentLevel(int level) {
2357        mDischargeCurrentLevel = level;
2358    }
2359
2360    public void updateKernelWakelocksLocked() {
2361        Map<String, KernelWakelockStats> m = readKernelWakelockStats();
2362
2363        if (m == null) {
2364            // Not crashing might make board bringup easier.
2365            Log.w(TAG, "Couldn't get kernel wake lock stats");
2366            return;
2367        }
2368
2369        for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
2370            String name = ent.getKey();
2371            KernelWakelockStats kws = ent.getValue();
2372
2373            SamplingTimer kwlt = mKernelWakelockStats.get(name);
2374            if (kwlt == null) {
2375                kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
2376                        true /* track reported values */);
2377                mKernelWakelockStats.put(name, kwlt);
2378            }
2379            kwlt.updateCurrentReportedCount(kws.mCount);
2380            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
2381            kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
2382        }
2383
2384        if (m.size() != mKernelWakelockStats.size()) {
2385            // Set timers to stale if they didn't appear in /proc/wakelocks this time.
2386            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
2387                SamplingTimer st = ent.getValue();
2388                if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
2389                    st.setStale();
2390                }
2391            }
2392        }
2393    }
2394
2395    public long getAwakeTimeBattery() {
2396        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
2397    }
2398
2399    public long getAwakeTimePlugged() {
2400        return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
2401    }
2402
2403    @Override
2404    public long computeUptime(long curTime, int which) {
2405        switch (which) {
2406            case STATS_TOTAL: return mUptime + (curTime-mUptimeStart);
2407            case STATS_LAST: return mLastUptime;
2408            case STATS_CURRENT: return (curTime-mUptimeStart);
2409            case STATS_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
2410        }
2411        return 0;
2412    }
2413
2414    @Override
2415    public long computeRealtime(long curTime, int which) {
2416        switch (which) {
2417            case STATS_TOTAL: return mRealtime + (curTime-mRealtimeStart);
2418            case STATS_LAST: return mLastRealtime;
2419            case STATS_CURRENT: return (curTime-mRealtimeStart);
2420            case STATS_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
2421        }
2422        return 0;
2423    }
2424
2425    @Override
2426    public long computeBatteryUptime(long curTime, int which) {
2427        switch (which) {
2428            case STATS_TOTAL:
2429                return mBatteryUptime + getBatteryUptime(curTime);
2430            case STATS_LAST:
2431                return mBatteryLastUptime;
2432            case STATS_CURRENT:
2433                return getBatteryUptime(curTime);
2434            case STATS_UNPLUGGED:
2435                return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
2436        }
2437        return 0;
2438    }
2439
2440    @Override
2441    public long computeBatteryRealtime(long curTime, int which) {
2442        switch (which) {
2443            case STATS_TOTAL:
2444                return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
2445            case STATS_LAST:
2446                return mBatteryLastRealtime;
2447            case STATS_CURRENT:
2448                return getBatteryRealtimeLocked(curTime);
2449            case STATS_UNPLUGGED:
2450                return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
2451        }
2452        return 0;
2453    }
2454
2455    long getBatteryUptimeLocked(long curTime) {
2456        long time = mTrackBatteryPastUptime;
2457        if (mOnBatteryInternal) {
2458            time += curTime - mTrackBatteryUptimeStart;
2459        }
2460        return time;
2461    }
2462
2463    long getBatteryUptimeLocked() {
2464        return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
2465    }
2466
2467    @Override
2468    public long getBatteryUptime(long curTime) {
2469        return getBatteryUptimeLocked(curTime);
2470    }
2471
2472    long getBatteryRealtimeLocked(long curTime) {
2473        long time = mTrackBatteryPastRealtime;
2474        if (mOnBatteryInternal) {
2475            time += curTime - mTrackBatteryRealtimeStart;
2476        }
2477        return time;
2478    }
2479
2480    @Override
2481    public long getBatteryRealtime(long curTime) {
2482        return getBatteryRealtimeLocked(curTime);
2483    }
2484
2485    @Override
2486    public int getDischargeStartLevel() {
2487        synchronized(this) {
2488            return getDischargeStartLevelLocked();
2489        }
2490    }
2491
2492    public int getDischargeStartLevelLocked() {
2493            return mDischargeStartLevel;
2494    }
2495
2496    @Override
2497    public int getDischargeCurrentLevel() {
2498        synchronized(this) {
2499            return getDischargeCurrentLevelLocked();
2500        }
2501    }
2502
2503    public int getDischargeCurrentLevelLocked() {
2504            return mDischargeCurrentLevel;
2505    }
2506
2507    /**
2508     * Retrieve the statistics object for a particular uid, creating if needed.
2509     */
2510    public Uid getUidStatsLocked(int uid) {
2511        Uid u = mUidStats.get(uid);
2512        if (u == null) {
2513            u = new Uid(uid);
2514            mUidStats.put(uid, u);
2515        }
2516        return u;
2517    }
2518
2519    /**
2520     * Remove the statistics object for a particular uid.
2521     */
2522    public void removeUidStatsLocked(int uid) {
2523        mUidStats.remove(uid);
2524    }
2525
2526    /**
2527     * Retrieve the statistics object for a particular process, creating
2528     * if needed.
2529     */
2530    public Uid.Proc getProcessStatsLocked(int uid, String name) {
2531        Uid u = getUidStatsLocked(uid);
2532        return u.getProcessStatsLocked(name);
2533    }
2534
2535    /**
2536     * Retrieve the statistics object for a particular process, creating
2537     * if needed.
2538     */
2539    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
2540        Uid u = getUidStatsLocked(uid);
2541        return u.getPackageStatsLocked(pkg);
2542    }
2543
2544    /**
2545     * Retrieve the statistics object for a particular service, creating
2546     * if needed.
2547     */
2548    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
2549        Uid u = getUidStatsLocked(uid);
2550        return u.getServiceStatsLocked(pkg, name);
2551    }
2552
2553    public void writeLocked() {
2554        if ((mFile == null) || (mBackupFile == null)) {
2555            Log.w("BatteryStats", "writeLocked: no file associated with this instance");
2556            return;
2557        }
2558
2559        // Keep the old file around until we know the new one has
2560        // been successfully written.
2561        if (mFile.exists()) {
2562            if (mBackupFile.exists()) {
2563                mBackupFile.delete();
2564            }
2565            mFile.renameTo(mBackupFile);
2566        }
2567
2568        try {
2569            FileOutputStream stream = new FileOutputStream(mFile);
2570            Parcel out = Parcel.obtain();
2571            writeSummaryToParcel(out);
2572            stream.write(out.marshall());
2573            out.recycle();
2574
2575            stream.flush();
2576            stream.close();
2577            mBackupFile.delete();
2578
2579            mLastWriteTime = SystemClock.elapsedRealtime();
2580        } catch (IOException e) {
2581            Log.e("BatteryStats", "Error writing battery statistics", e);
2582        }
2583    }
2584
2585    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
2586        int pos = 0;
2587        int avail = stream.available();
2588        byte[] data = new byte[avail];
2589        while (true) {
2590            int amt = stream.read(data, pos, data.length-pos);
2591            //Log.i("foo", "Read " + amt + " bytes at " + pos
2592            //        + " of avail " + data.length);
2593            if (amt <= 0) {
2594                //Log.i("foo", "**** FINISHED READING: pos=" + pos
2595                //        + " len=" + data.length);
2596                return data;
2597            }
2598            pos += amt;
2599            avail = stream.available();
2600            if (avail > data.length-pos) {
2601                byte[] newData = new byte[pos+avail];
2602                System.arraycopy(data, 0, newData, 0, pos);
2603                data = newData;
2604            }
2605        }
2606    }
2607
2608    public void readLocked() {
2609        if ((mFile == null) || (mBackupFile == null)) {
2610            Log.w("BatteryStats", "readLocked: no file associated with this instance");
2611            return;
2612        }
2613
2614        mUidStats.clear();
2615
2616        FileInputStream stream = null;
2617        if (mBackupFile.exists()) {
2618            try {
2619                stream = new FileInputStream(mBackupFile);
2620            } catch (java.io.IOException e) {
2621                // We'll try for the normal settings file.
2622            }
2623        }
2624
2625        try {
2626            if (stream == null) {
2627                if (!mFile.exists()) {
2628                    return;
2629                }
2630                stream = new FileInputStream(mFile);
2631            }
2632
2633            byte[] raw = readFully(stream);
2634            Parcel in = Parcel.obtain();
2635            in.unmarshall(raw, 0, raw.length);
2636            in.setDataPosition(0);
2637            stream.close();
2638
2639            readSummaryFromParcel(in);
2640        } catch(java.io.IOException e) {
2641            Log.e("BatteryStats", "Error reading battery statistics", e);
2642        }
2643    }
2644
2645    public int describeContents() {
2646        return 0;
2647    }
2648
2649    private void readSummaryFromParcel(Parcel in) {
2650        final int version = in.readInt();
2651        if (version != VERSION) {
2652            Log.w("BatteryStats", "readFromParcel: version got " + version
2653                + ", expected " + VERSION + "; erasing old stats");
2654            return;
2655        }
2656
2657        mStartCount = in.readInt();
2658        mBatteryUptime = in.readLong();
2659        mBatteryLastUptime = in.readLong();
2660        mBatteryRealtime = in.readLong();
2661        mBatteryLastRealtime = in.readLong();
2662        mUptime = in.readLong();
2663        mLastUptime = in.readLong();
2664        mRealtime = in.readLong();
2665        mLastRealtime = in.readLong();
2666        mDischargeStartLevel = in.readInt();
2667        mDischargeCurrentLevel = in.readInt();
2668
2669        mStartCount++;
2670
2671        mScreenOn = false;
2672        mScreenOnTimer.readSummaryFromParcelLocked(in);
2673        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
2674            mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
2675        }
2676        mInputEventCounter.readSummaryFromParcelLocked(in);
2677        mPhoneOn = false;
2678        mPhoneOnTimer.readSummaryFromParcelLocked(in);
2679        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
2680            mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
2681        }
2682        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
2683            mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
2684        }
2685        mWifiOn = false;
2686        mWifiOnTimer.readSummaryFromParcelLocked(in);
2687        mWifiRunning = false;
2688        mWifiRunningTimer.readSummaryFromParcelLocked(in);
2689        mBluetoothOn = false;
2690        mBluetoothOnTimer.readSummaryFromParcelLocked(in);
2691
2692        int NKW = in.readInt();
2693        for (int ikw = 0; ikw < NKW; ikw++) {
2694            if (in.readInt() != 0) {
2695                String kwltName = in.readString();
2696                getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
2697            }
2698        }
2699
2700        final int NU = in.readInt();
2701        for (int iu = 0; iu < NU; iu++) {
2702            int uid = in.readInt();
2703            Uid u = new Uid(uid);
2704            mUidStats.put(uid, u);
2705
2706            u.mWifiTurnedOn = false;
2707            u.mWifiTurnedOnTimer.readSummaryFromParcelLocked(in);
2708            u.mFullWifiLockOut = false;
2709            u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
2710            u.mScanWifiLockOut = false;
2711            u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
2712
2713            if (in.readInt() != 0) {
2714                if (u.mUserActivityCounters == null) {
2715                    u.initUserActivityLocked();
2716                }
2717                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
2718                    u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
2719                }
2720            }
2721
2722            int NW = in.readInt();
2723            for (int iw = 0; iw < NW; iw++) {
2724                String wlName = in.readString();
2725                if (in.readInt() != 0) {
2726                    u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
2727                }
2728                if (in.readInt() != 0) {
2729                    u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
2730                }
2731                if (in.readInt() != 0) {
2732                    u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
2733                }
2734            }
2735
2736            int NP = in.readInt();
2737            for (int is = 0; is < NP; is++) {
2738                int seNumber = in.readInt();
2739                if (in.readInt() != 0) {
2740                    u.getSensorTimerLocked(seNumber, true)
2741                            .readSummaryFromParcelLocked(in);
2742                }
2743            }
2744
2745            NP = in.readInt();
2746            for (int ip = 0; ip < NP; ip++) {
2747                String procName = in.readString();
2748                Uid.Proc p = u.getProcessStatsLocked(procName);
2749                p.mUserTime = p.mLoadedUserTime = in.readLong();
2750                p.mLastUserTime = in.readLong();
2751                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
2752                p.mLastSystemTime = in.readLong();
2753                p.mStarts = p.mLoadedStarts = in.readInt();
2754                p.mLastStarts = in.readInt();
2755            }
2756
2757            NP = in.readInt();
2758            for (int ip = 0; ip < NP; ip++) {
2759                String pkgName = in.readString();
2760                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
2761                p.mWakeups = p.mLoadedWakeups = in.readInt();
2762                p.mLastWakeups = in.readInt();
2763                final int NS = in.readInt();
2764                for (int is = 0; is < NS; is++) {
2765                    String servName = in.readString();
2766                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
2767                    s.mStartTime = s.mLoadedStartTime = in.readLong();
2768                    s.mLastStartTime = in.readLong();
2769                    s.mStarts = s.mLoadedStarts = in.readInt();
2770                    s.mLastStarts = in.readInt();
2771                    s.mLaunches = s.mLoadedLaunches = in.readInt();
2772                    s.mLastLaunches = in.readInt();
2773                }
2774            }
2775
2776            u.mLoadedTcpBytesReceived = in.readLong();
2777            u.mLoadedTcpBytesSent = in.readLong();
2778        }
2779    }
2780
2781    /**
2782     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
2783     * disk.  This format does not allow a lossless round-trip.
2784     *
2785     * @param out the Parcel to be written to.
2786     */
2787    public void writeSummaryToParcel(Parcel out) {
2788        final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
2789        final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
2790        final long NOW = getBatteryUptimeLocked(NOW_SYS);
2791        final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
2792
2793        out.writeInt(VERSION);
2794
2795        out.writeInt(mStartCount);
2796        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_TOTAL));
2797        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_CURRENT));
2798        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_TOTAL));
2799        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_CURRENT));
2800        out.writeLong(computeUptime(NOW_SYS, STATS_TOTAL));
2801        out.writeLong(computeUptime(NOW_SYS, STATS_CURRENT));
2802        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_TOTAL));
2803        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_CURRENT));
2804        out.writeInt(mDischargeStartLevel);
2805        out.writeInt(mDischargeCurrentLevel);
2806
2807
2808        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
2809        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
2810            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
2811        }
2812        mInputEventCounter.writeSummaryFromParcelLocked(out);
2813        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
2814        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
2815            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
2816        }
2817        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
2818            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
2819        }
2820        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
2821        mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
2822        mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
2823
2824        out.writeInt(mKernelWakelockStats.size());
2825        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
2826            Timer kwlt = ent.getValue();
2827            if (kwlt != null) {
2828                out.writeInt(1);
2829                out.writeString(ent.getKey());
2830                ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
2831            } else {
2832                out.writeInt(0);
2833            }
2834        }
2835
2836        final int NU = mUidStats.size();
2837        out.writeInt(NU);
2838        for (int iu = 0; iu < NU; iu++) {
2839            out.writeInt(mUidStats.keyAt(iu));
2840            Uid u = mUidStats.valueAt(iu);
2841
2842            u.mWifiTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
2843            u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
2844            u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
2845
2846            if (u.mUserActivityCounters == null) {
2847                out.writeInt(0);
2848            } else {
2849                out.writeInt(1);
2850                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
2851                    u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
2852                }
2853            }
2854
2855            int NW = u.mWakelockStats.size();
2856            out.writeInt(NW);
2857            if (NW > 0) {
2858                for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
2859                        : u.mWakelockStats.entrySet()) {
2860                    out.writeString(ent.getKey());
2861                    Uid.Wakelock wl = ent.getValue();
2862                    if (wl.mTimerFull != null) {
2863                        out.writeInt(1);
2864                        wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
2865                    } else {
2866                        out.writeInt(0);
2867                    }
2868                    if (wl.mTimerPartial != null) {
2869                        out.writeInt(1);
2870                        wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
2871                    } else {
2872                        out.writeInt(0);
2873                    }
2874                    if (wl.mTimerWindow != null) {
2875                        out.writeInt(1);
2876                        wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
2877                    } else {
2878                        out.writeInt(0);
2879                    }
2880                }
2881            }
2882
2883            int NSE = u.mSensorStats.size();
2884            out.writeInt(NSE);
2885            if (NSE > 0) {
2886                for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
2887                        : u.mSensorStats.entrySet()) {
2888                    out.writeInt(ent.getKey());
2889                    Uid.Sensor se = ent.getValue();
2890                    if (se.mTimer != null) {
2891                        out.writeInt(1);
2892                        se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
2893                    } else {
2894                        out.writeInt(0);
2895                    }
2896                }
2897            }
2898
2899            int NP = u.mProcessStats.size();
2900            out.writeInt(NP);
2901            if (NP > 0) {
2902                for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
2903                    : u.mProcessStats.entrySet()) {
2904                    out.writeString(ent.getKey());
2905                    Uid.Proc ps = ent.getValue();
2906                    out.writeLong(ps.mUserTime);
2907                    out.writeLong(ps.mUserTime - ps.mLoadedUserTime);
2908                    out.writeLong(ps.mSystemTime);
2909                    out.writeLong(ps.mSystemTime - ps.mLoadedSystemTime);
2910                    out.writeInt(ps.mStarts);
2911                    out.writeInt(ps.mStarts - ps.mLoadedStarts);
2912                }
2913            }
2914
2915            NP = u.mPackageStats.size();
2916            out.writeInt(NP);
2917            if (NP > 0) {
2918                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
2919                    : u.mPackageStats.entrySet()) {
2920                    out.writeString(ent.getKey());
2921                    Uid.Pkg ps = ent.getValue();
2922                    out.writeInt(ps.mWakeups);
2923                    out.writeInt(ps.mWakeups - ps.mLoadedWakeups);
2924                    final int NS = ps.mServiceStats.size();
2925                    out.writeInt(NS);
2926                    if (NS > 0) {
2927                        for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
2928                                : ps.mServiceStats.entrySet()) {
2929                            out.writeString(sent.getKey());
2930                            BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
2931                            long time = ss.getStartTimeToNowLocked(NOW);
2932                            out.writeLong(time);
2933                            out.writeLong(time - ss.mLoadedStartTime);
2934                            out.writeInt(ss.mStarts);
2935                            out.writeInt(ss.mStarts - ss.mLoadedStarts);
2936                            out.writeInt(ss.mLaunches);
2937                            out.writeInt(ss.mLaunches - ss.mLoadedLaunches);
2938                        }
2939                    }
2940                }
2941            }
2942
2943            out.writeLong(u.getTcpBytesReceived(STATS_TOTAL));
2944            out.writeLong(u.getTcpBytesSent(STATS_TOTAL));
2945        }
2946    }
2947
2948    public void readFromParcel(Parcel in) {
2949        readFromParcelLocked(in);
2950    }
2951
2952    void readFromParcelLocked(Parcel in) {
2953        int magic = in.readInt();
2954        if (magic != MAGIC) {
2955            throw new ParcelFormatException("Bad magic number");
2956        }
2957
2958        mStartCount = in.readInt();
2959        mBatteryUptime = in.readLong();
2960        mBatteryLastUptime = in.readLong();
2961        mBatteryRealtime = in.readLong();
2962        mBatteryLastRealtime = in.readLong();
2963        mScreenOn = false;
2964        mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables, in);
2965        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
2966            mScreenBrightnessTimer[i] = new StopwatchTimer(-100-i, null, mUnpluggables, in);
2967        }
2968        mInputEventCounter = new Counter(mUnpluggables, in);
2969        mPhoneOn = false;
2970        mPhoneOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
2971        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
2972            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(-200-i, null, mUnpluggables, in);
2973        }
2974        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
2975            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(-300-i, null, mUnpluggables, in);
2976        }
2977        mWifiOn = false;
2978        mWifiOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
2979        mWifiRunning = false;
2980        mWifiRunningTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
2981        mBluetoothOn = false;
2982        mBluetoothOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
2983        mUptime = in.readLong();
2984        mUptimeStart = in.readLong();
2985        mLastUptime = in.readLong();
2986        mRealtime = in.readLong();
2987        mRealtimeStart = in.readLong();
2988        mLastRealtime = in.readLong();
2989        mOnBattery = in.readInt() != 0;
2990        mOnBatteryInternal = false; // we are no longer really running.
2991        mTrackBatteryPastUptime = in.readLong();
2992        mTrackBatteryUptimeStart = in.readLong();
2993        mTrackBatteryPastRealtime = in.readLong();
2994        mTrackBatteryRealtimeStart = in.readLong();
2995        mUnpluggedBatteryUptime = in.readLong();
2996        mUnpluggedBatteryRealtime = in.readLong();
2997        mDischargeStartLevel = in.readInt();
2998        mDischargeCurrentLevel = in.readInt();
2999        mLastWriteTime = in.readLong();
3000
3001        mKernelWakelockStats.clear();
3002        int NKW = in.readInt();
3003        for (int ikw = 0; ikw < NKW; ikw++) {
3004            if (in.readInt() != 0) {
3005                String wakelockName = in.readString();
3006                SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
3007                mKernelWakelockStats.put(wakelockName, kwlt);
3008            }
3009        }
3010
3011        mPartialTimers.clear();
3012        mFullTimers.clear();
3013        mWindowTimers.clear();
3014
3015        int numUids = in.readInt();
3016        mUidStats.clear();
3017        for (int i = 0; i < numUids; i++) {
3018            int uid = in.readInt();
3019            Uid u = new Uid(uid);
3020            u.readFromParcelLocked(mUnpluggables, in);
3021            mUidStats.append(uid, u);
3022        }
3023    }
3024
3025    public void writeToParcel(Parcel out, int flags) {
3026        writeToParcelLocked(out, flags);
3027    }
3028
3029    @SuppressWarnings("unused")
3030    void writeToParcelLocked(Parcel out, int flags) {
3031        final long uSecUptime = SystemClock.uptimeMillis() * 1000;
3032        final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
3033        final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
3034        final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
3035
3036        out.writeInt(MAGIC);
3037        out.writeInt(mStartCount);
3038        out.writeLong(mBatteryUptime);
3039        out.writeLong(mBatteryLastUptime);
3040        out.writeLong(mBatteryRealtime);
3041        out.writeLong(mBatteryLastRealtime);
3042        mScreenOnTimer.writeToParcel(out, batteryRealtime);
3043        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3044            mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
3045        }
3046        mInputEventCounter.writeToParcel(out);
3047        mPhoneOnTimer.writeToParcel(out, batteryRealtime);
3048        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3049            mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
3050        }
3051        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3052            mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
3053        }
3054        mWifiOnTimer.writeToParcel(out, batteryRealtime);
3055        mWifiRunningTimer.writeToParcel(out, batteryRealtime);
3056        mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
3057        out.writeLong(mUptime);
3058        out.writeLong(mUptimeStart);
3059        out.writeLong(mLastUptime);
3060        out.writeLong(mRealtime);
3061        out.writeLong(mRealtimeStart);
3062        out.writeLong(mLastRealtime);
3063        out.writeInt(mOnBattery ? 1 : 0);
3064        out.writeLong(batteryUptime);
3065        out.writeLong(mTrackBatteryUptimeStart);
3066        out.writeLong(batteryRealtime);
3067        out.writeLong(mTrackBatteryRealtimeStart);
3068        out.writeLong(mUnpluggedBatteryUptime);
3069        out.writeLong(mUnpluggedBatteryRealtime);
3070        out.writeInt(mDischargeStartLevel);
3071        out.writeInt(mDischargeCurrentLevel);
3072        out.writeLong(mLastWriteTime);
3073
3074        out.writeInt(mKernelWakelockStats.size());
3075        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
3076            SamplingTimer kwlt = ent.getValue();
3077            if (kwlt != null) {
3078                out.writeInt(1);
3079                out.writeString(ent.getKey());
3080                Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
3081            } else {
3082                out.writeInt(0);
3083            }
3084        }
3085
3086        int size = mUidStats.size();
3087        out.writeInt(size);
3088        for (int i = 0; i < size; i++) {
3089            out.writeInt(mUidStats.keyAt(i));
3090            Uid uid = mUidStats.valueAt(i);
3091
3092            uid.writeToParcelLocked(out, batteryRealtime);
3093        }
3094    }
3095
3096    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
3097        new Parcelable.Creator<BatteryStatsImpl>() {
3098        public BatteryStatsImpl createFromParcel(Parcel in) {
3099            return new BatteryStatsImpl(in);
3100        }
3101
3102        public BatteryStatsImpl[] newArray(int size) {
3103            return new BatteryStatsImpl[size];
3104        }
3105    };
3106
3107    public void dumpLocked(PrintWriter pw) {
3108        if (DEBUG) {
3109            Printer pr = new PrintWriterPrinter(pw);
3110            pr.println("*** Screen timer:");
3111            mScreenOnTimer.logState(pr, "  ");
3112            for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3113                pr.println("*** Screen brightness #" + i + ":");
3114                mScreenBrightnessTimer[i].logState(pr, "  ");
3115            }
3116            pr.println("*** Input event counter:");
3117            mInputEventCounter.logState(pr, "  ");
3118            pr.println("*** Phone timer:");
3119            mPhoneOnTimer.logState(pr, "  ");
3120            for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3121                pr.println("*** Signal strength #" + i + ":");
3122                mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
3123            }
3124            for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3125                pr.println("*** Data connection type #" + i + ":");
3126                mPhoneDataConnectionsTimer[i].logState(pr, "  ");
3127            }
3128            pr.println("*** Wifi timer:");
3129            mWifiOnTimer.logState(pr, "  ");
3130            pr.println("*** WifiRunning timer:");
3131            mWifiRunningTimer.logState(pr, "  ");
3132            pr.println("*** Bluetooth timer:");
3133            mBluetoothOnTimer.logState(pr, "  ");
3134        }
3135        super.dumpLocked(pw);
3136    }
3137}
3138