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