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