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