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