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