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