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