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