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