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