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