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