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