BatteryStatsImpl.java revision 5284090631e638b916d9a453212e9dc802656a67
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[SignalStrength.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 < SignalStrength.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 > SignalStrength.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 > SignalStrength.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 = SignalStrength.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 = signalStrength.getLevel();
1779        updateAllPhoneStateLocked(mPhoneServiceStateRaw, mPhoneSimStateRaw, bin);
1780    }
1781
1782    public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData) {
1783        int bin = DATA_CONNECTION_NONE;
1784        if (hasData) {
1785            switch (dataType) {
1786                case TelephonyManager.NETWORK_TYPE_EDGE:
1787                    bin = DATA_CONNECTION_EDGE;
1788                    break;
1789                case TelephonyManager.NETWORK_TYPE_GPRS:
1790                    bin = DATA_CONNECTION_GPRS;
1791                    break;
1792                case TelephonyManager.NETWORK_TYPE_UMTS:
1793                    bin = DATA_CONNECTION_UMTS;
1794                    break;
1795                case TelephonyManager.NETWORK_TYPE_CDMA:
1796                    bin = DATA_CONNECTION_CDMA;
1797                    break;
1798                case TelephonyManager.NETWORK_TYPE_EVDO_0:
1799                    bin = DATA_CONNECTION_EVDO_0;
1800                    break;
1801                case TelephonyManager.NETWORK_TYPE_EVDO_A:
1802                    bin = DATA_CONNECTION_EVDO_A;
1803                    break;
1804                case TelephonyManager.NETWORK_TYPE_1xRTT:
1805                    bin = DATA_CONNECTION_1xRTT;
1806                    break;
1807                case TelephonyManager.NETWORK_TYPE_HSDPA:
1808                    bin = DATA_CONNECTION_HSDPA;
1809                    break;
1810                case TelephonyManager.NETWORK_TYPE_HSUPA:
1811                    bin = DATA_CONNECTION_HSUPA;
1812                    break;
1813                case TelephonyManager.NETWORK_TYPE_HSPA:
1814                    bin = DATA_CONNECTION_HSPA;
1815                    break;
1816                case TelephonyManager.NETWORK_TYPE_IDEN:
1817                    bin = DATA_CONNECTION_IDEN;
1818                    break;
1819                case TelephonyManager.NETWORK_TYPE_EVDO_B:
1820                    bin = DATA_CONNECTION_EVDO_B;
1821                    break;
1822                case TelephonyManager.NETWORK_TYPE_LTE:
1823                    bin = DATA_CONNECTION_LTE;
1824                    break;
1825                case TelephonyManager.NETWORK_TYPE_EHRPD:
1826                    bin = DATA_CONNECTION_EHRPD;
1827                    break;
1828                default:
1829                    bin = DATA_CONNECTION_OTHER;
1830                    break;
1831            }
1832        }
1833        if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
1834        if (mPhoneDataConnectionType != bin) {
1835            mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
1836                    | (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
1837            if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
1838                    + Integer.toHexString(mHistoryCur.states));
1839            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1840            if (mPhoneDataConnectionType >= 0) {
1841                mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this);
1842            }
1843            mPhoneDataConnectionType = bin;
1844            mPhoneDataConnectionsTimer[bin].startRunningLocked(this);
1845        }
1846    }
1847
1848    public void noteWifiOnLocked() {
1849        if (!mWifiOn) {
1850            mHistoryCur.states |= HistoryItem.STATE_WIFI_ON_FLAG;
1851            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
1852                    + Integer.toHexString(mHistoryCur.states));
1853            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1854            mWifiOn = true;
1855            mWifiOnTimer.startRunningLocked(this);
1856        }
1857    }
1858
1859    public void noteWifiOffLocked() {
1860        if (mWifiOn) {
1861            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_ON_FLAG;
1862            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
1863                    + Integer.toHexString(mHistoryCur.states));
1864            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1865            mWifiOn = false;
1866            mWifiOnTimer.stopRunningLocked(this);
1867        }
1868        if (mWifiOnUid >= 0) {
1869            getUidStatsLocked(mWifiOnUid).noteWifiStoppedLocked();
1870            mWifiOnUid = -1;
1871        }
1872    }
1873
1874    public void noteAudioOnLocked(int uid) {
1875        if (!mAudioOn) {
1876            mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
1877            if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
1878                    + Integer.toHexString(mHistoryCur.states));
1879            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1880            mAudioOn = true;
1881            mAudioOnTimer.startRunningLocked(this);
1882        }
1883        getUidStatsLocked(uid).noteAudioTurnedOnLocked();
1884    }
1885
1886    public void noteAudioOffLocked(int uid) {
1887        if (mAudioOn) {
1888            mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
1889            if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
1890                    + Integer.toHexString(mHistoryCur.states));
1891            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1892            mAudioOn = false;
1893            mAudioOnTimer.stopRunningLocked(this);
1894        }
1895        getUidStatsLocked(uid).noteAudioTurnedOffLocked();
1896    }
1897
1898    public void noteVideoOnLocked(int uid) {
1899        if (!mVideoOn) {
1900            mHistoryCur.states |= HistoryItem.STATE_VIDEO_ON_FLAG;
1901            if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
1902                    + Integer.toHexString(mHistoryCur.states));
1903            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1904            mVideoOn = true;
1905            mVideoOnTimer.startRunningLocked(this);
1906        }
1907        getUidStatsLocked(uid).noteVideoTurnedOnLocked();
1908    }
1909
1910    public void noteVideoOffLocked(int uid) {
1911        if (mVideoOn) {
1912            mHistoryCur.states &= ~HistoryItem.STATE_VIDEO_ON_FLAG;
1913            if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
1914                    + Integer.toHexString(mHistoryCur.states));
1915            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1916            mVideoOn = false;
1917            mVideoOnTimer.stopRunningLocked(this);
1918        }
1919        getUidStatsLocked(uid).noteVideoTurnedOffLocked();
1920    }
1921
1922    public void noteWifiRunningLocked(WorkSource ws) {
1923        if (!mGlobalWifiRunning) {
1924            mHistoryCur.states |= HistoryItem.STATE_WIFI_RUNNING_FLAG;
1925            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
1926                    + Integer.toHexString(mHistoryCur.states));
1927            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1928            mGlobalWifiRunning = true;
1929            mGlobalWifiRunningTimer.startRunningLocked(this);
1930            int N = ws.size();
1931            for (int i=0; i<N; i++) {
1932                getUidStatsLocked(ws.get(i)).noteWifiRunningLocked();
1933            }
1934        } else {
1935            Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
1936        }
1937    }
1938
1939    public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
1940        if (mGlobalWifiRunning) {
1941            int N = oldWs.size();
1942            for (int i=0; i<N; i++) {
1943                getUidStatsLocked(oldWs.get(i)).noteWifiStoppedLocked();
1944            }
1945            N = newWs.size();
1946            for (int i=0; i<N; i++) {
1947                getUidStatsLocked(newWs.get(i)).noteWifiRunningLocked();
1948            }
1949        } else {
1950            Log.w(TAG, "noteWifiRunningChangedLocked -- called while WIFI not running");
1951        }
1952    }
1953
1954    public void noteWifiStoppedLocked(WorkSource ws) {
1955        if (mGlobalWifiRunning) {
1956            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RUNNING_FLAG;
1957            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
1958                    + Integer.toHexString(mHistoryCur.states));
1959            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1960            mGlobalWifiRunning = false;
1961            mGlobalWifiRunningTimer.stopRunningLocked(this);
1962            int N = ws.size();
1963            for (int i=0; i<N; i++) {
1964                getUidStatsLocked(ws.get(i)).noteWifiStoppedLocked();
1965            }
1966        } else {
1967            Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
1968        }
1969    }
1970
1971    public void noteBluetoothOnLocked() {
1972        if (!mBluetoothOn) {
1973            mHistoryCur.states |= HistoryItem.STATE_BLUETOOTH_ON_FLAG;
1974            if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth on to: "
1975                    + Integer.toHexString(mHistoryCur.states));
1976            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1977            mBluetoothOn = true;
1978            mBluetoothOnTimer.startRunningLocked(this);
1979        }
1980    }
1981
1982    public void noteBluetoothOffLocked() {
1983        if (mBluetoothOn) {
1984            mHistoryCur.states &= ~HistoryItem.STATE_BLUETOOTH_ON_FLAG;
1985            if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth off to: "
1986                    + Integer.toHexString(mHistoryCur.states));
1987            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1988            mBluetoothOn = false;
1989            mBluetoothOnTimer.stopRunningLocked(this);
1990        }
1991    }
1992
1993    int mWifiFullLockNesting = 0;
1994
1995    public void noteFullWifiLockAcquiredLocked(int uid) {
1996        if (mWifiFullLockNesting == 0) {
1997            mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
1998            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
1999                    + Integer.toHexString(mHistoryCur.states));
2000            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2001        }
2002        mWifiFullLockNesting++;
2003        getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
2004    }
2005
2006    public void noteFullWifiLockReleasedLocked(int uid) {
2007        mWifiFullLockNesting--;
2008        if (mWifiFullLockNesting == 0) {
2009            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
2010            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
2011                    + Integer.toHexString(mHistoryCur.states));
2012            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2013        }
2014        getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
2015    }
2016
2017    int mWifiScanLockNesting = 0;
2018
2019    public void noteScanWifiLockAcquiredLocked(int uid) {
2020        if (mWifiScanLockNesting == 0) {
2021            mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_LOCK_FLAG;
2022            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock on to: "
2023                    + Integer.toHexString(mHistoryCur.states));
2024            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2025        }
2026        mWifiScanLockNesting++;
2027        getUidStatsLocked(uid).noteScanWifiLockAcquiredLocked();
2028    }
2029
2030    public void noteScanWifiLockReleasedLocked(int uid) {
2031        mWifiScanLockNesting--;
2032        if (mWifiScanLockNesting == 0) {
2033            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_LOCK_FLAG;
2034            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock off to: "
2035                    + Integer.toHexString(mHistoryCur.states));
2036            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2037        }
2038        getUidStatsLocked(uid).noteScanWifiLockReleasedLocked();
2039    }
2040
2041    int mWifiMulticastNesting = 0;
2042
2043    public void noteWifiMulticastEnabledLocked(int uid) {
2044        if (mWifiMulticastNesting == 0) {
2045            mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
2046            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
2047                    + Integer.toHexString(mHistoryCur.states));
2048            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2049        }
2050        mWifiMulticastNesting++;
2051        getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
2052    }
2053
2054    public void noteWifiMulticastDisabledLocked(int uid) {
2055        mWifiMulticastNesting--;
2056        if (mWifiMulticastNesting == 0) {
2057            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
2058            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
2059                    + Integer.toHexString(mHistoryCur.states));
2060            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2061        }
2062        getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
2063    }
2064
2065    public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
2066        int N = ws.size();
2067        for (int i=0; i<N; i++) {
2068            noteFullWifiLockAcquiredLocked(ws.get(i));
2069        }
2070    }
2071
2072    public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
2073        int N = ws.size();
2074        for (int i=0; i<N; i++) {
2075            noteFullWifiLockReleasedLocked(ws.get(i));
2076        }
2077    }
2078
2079    public void noteScanWifiLockAcquiredFromSourceLocked(WorkSource ws) {
2080        int N = ws.size();
2081        for (int i=0; i<N; i++) {
2082            noteScanWifiLockAcquiredLocked(ws.get(i));
2083        }
2084    }
2085
2086    public void noteScanWifiLockReleasedFromSourceLocked(WorkSource ws) {
2087        int N = ws.size();
2088        for (int i=0; i<N; i++) {
2089            noteScanWifiLockReleasedLocked(ws.get(i));
2090        }
2091    }
2092
2093    public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
2094        int N = ws.size();
2095        for (int i=0; i<N; i++) {
2096            noteWifiMulticastEnabledLocked(ws.get(i));
2097        }
2098    }
2099
2100    public void noteWifiMulticastDisabledFromSourceLocked(WorkSource ws) {
2101        int N = ws.size();
2102        for (int i=0; i<N; i++) {
2103            noteWifiMulticastDisabledLocked(ws.get(i));
2104        }
2105    }
2106
2107    @Override public long getScreenOnTime(long batteryRealtime, int which) {
2108        return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
2109    }
2110
2111    @Override public long getScreenBrightnessTime(int brightnessBin,
2112            long batteryRealtime, int which) {
2113        return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
2114                batteryRealtime, which);
2115    }
2116
2117    @Override public int getInputEventCount(int which) {
2118        return mInputEventCounter.getCountLocked(which);
2119    }
2120
2121    @Override public long getPhoneOnTime(long batteryRealtime, int which) {
2122        return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
2123    }
2124
2125    @Override public long getPhoneSignalStrengthTime(int strengthBin,
2126            long batteryRealtime, int which) {
2127        return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
2128                batteryRealtime, which);
2129    }
2130
2131    @Override public long getPhoneSignalScanningTime(
2132            long batteryRealtime, int which) {
2133        return mPhoneSignalScanningTimer.getTotalTimeLocked(
2134                batteryRealtime, which);
2135    }
2136
2137    @Override public int getPhoneSignalStrengthCount(int dataType, int which) {
2138        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
2139    }
2140
2141    @Override public long getPhoneDataConnectionTime(int dataType,
2142            long batteryRealtime, int which) {
2143        return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
2144                batteryRealtime, which);
2145    }
2146
2147    @Override public int getPhoneDataConnectionCount(int dataType, int which) {
2148        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
2149    }
2150
2151    @Override public long getWifiOnTime(long batteryRealtime, int which) {
2152        return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
2153    }
2154
2155    @Override public long getGlobalWifiRunningTime(long batteryRealtime, int which) {
2156        return mGlobalWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
2157    }
2158
2159    @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
2160        return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
2161    }
2162
2163    @Override public boolean getIsOnBattery() {
2164        return mOnBattery;
2165    }
2166
2167    @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
2168        return mUidStats;
2169    }
2170
2171    /**
2172     * The statistics associated with a particular uid.
2173     */
2174    public final class Uid extends BatteryStats.Uid {
2175
2176        final int mUid;
2177        long mLoadedTcpBytesReceived;
2178        long mLoadedTcpBytesSent;
2179        long mCurrentTcpBytesReceived;
2180        long mCurrentTcpBytesSent;
2181        long mTcpBytesReceivedAtLastUnplug;
2182        long mTcpBytesSentAtLastUnplug;
2183
2184        // These are not saved/restored when parcelling, since we want
2185        // to return from the parcel with a snapshot of the state.
2186        long mStartedTcpBytesReceived = -1;
2187        long mStartedTcpBytesSent = -1;
2188
2189        boolean mWifiRunning;
2190        StopwatchTimer mWifiRunningTimer;
2191
2192        boolean mFullWifiLockOut;
2193        StopwatchTimer mFullWifiLockTimer;
2194
2195        boolean mScanWifiLockOut;
2196        StopwatchTimer mScanWifiLockTimer;
2197
2198        boolean mWifiMulticastEnabled;
2199        StopwatchTimer mWifiMulticastTimer;
2200
2201        boolean mAudioTurnedOn;
2202        StopwatchTimer mAudioTurnedOnTimer;
2203
2204        boolean mVideoTurnedOn;
2205        StopwatchTimer mVideoTurnedOnTimer;
2206
2207        Counter[] mUserActivityCounters;
2208
2209        /**
2210         * The statistics we have collected for this uid's wake locks.
2211         */
2212        final HashMap<String, Wakelock> mWakelockStats = new HashMap<String, Wakelock>();
2213
2214        /**
2215         * The statistics we have collected for this uid's sensor activations.
2216         */
2217        final HashMap<Integer, Sensor> mSensorStats = new HashMap<Integer, Sensor>();
2218
2219        /**
2220         * The statistics we have collected for this uid's processes.
2221         */
2222        final HashMap<String, Proc> mProcessStats = new HashMap<String, Proc>();
2223
2224        /**
2225         * The statistics we have collected for this uid's processes.
2226         */
2227        final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
2228
2229        /**
2230         * The transient wake stats we have collected for this uid's pids.
2231         */
2232        final SparseArray<Pid> mPids = new SparseArray<Pid>();
2233
2234        public Uid(int uid) {
2235            mUid = uid;
2236            mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
2237                    mWifiRunningTimers, mUnpluggables);
2238            mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
2239                    mFullWifiLockTimers, mUnpluggables);
2240            mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
2241                    mScanWifiLockTimers, mUnpluggables);
2242            mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
2243                    mWifiMulticastTimers, mUnpluggables);
2244            mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
2245                    null, mUnpluggables);
2246            mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
2247                    null, mUnpluggables);
2248        }
2249
2250        @Override
2251        public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
2252            return mWakelockStats;
2253        }
2254
2255        @Override
2256        public Map<Integer, ? extends BatteryStats.Uid.Sensor> getSensorStats() {
2257            return mSensorStats;
2258        }
2259
2260        @Override
2261        public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
2262            return mProcessStats;
2263        }
2264
2265        @Override
2266        public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
2267            return mPackageStats;
2268        }
2269
2270        @Override
2271        public int getUid() {
2272            return mUid;
2273        }
2274
2275        @Override
2276        public long getTcpBytesReceived(int which) {
2277            if (which == STATS_LAST) {
2278                return mLoadedTcpBytesReceived;
2279            } else {
2280                long current = computeCurrentTcpBytesReceived();
2281                if (which == STATS_SINCE_UNPLUGGED) {
2282                    current -= mTcpBytesReceivedAtLastUnplug;
2283                } else if (which == STATS_SINCE_CHARGED) {
2284                    current += mLoadedTcpBytesReceived;
2285                }
2286                return current;
2287            }
2288        }
2289
2290        public long computeCurrentTcpBytesReceived() {
2291            return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
2292                    ? (TrafficStats.getUidRxBytes(mUid) - mStartedTcpBytesReceived) : 0);
2293        }
2294
2295        @Override
2296        public long getTcpBytesSent(int which) {
2297            if (which == STATS_LAST) {
2298                return mLoadedTcpBytesSent;
2299            } else {
2300                long current = computeCurrentTcpBytesSent();
2301                if (which == STATS_SINCE_UNPLUGGED) {
2302                    current -= mTcpBytesSentAtLastUnplug;
2303                } else if (which == STATS_SINCE_CHARGED) {
2304                    current += mLoadedTcpBytesSent;
2305                }
2306                return current;
2307            }
2308        }
2309
2310        @Override
2311        public void noteWifiRunningLocked() {
2312            if (!mWifiRunning) {
2313                mWifiRunning = true;
2314                if (mWifiRunningTimer == null) {
2315                    mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
2316                            mWifiRunningTimers, mUnpluggables);
2317                }
2318                mWifiRunningTimer.startRunningLocked(BatteryStatsImpl.this);
2319            }
2320        }
2321
2322        @Override
2323        public void noteWifiStoppedLocked() {
2324            if (mWifiRunning) {
2325                mWifiRunning = false;
2326                mWifiRunningTimer.stopRunningLocked(BatteryStatsImpl.this);
2327            }
2328        }
2329
2330        @Override
2331        public void noteFullWifiLockAcquiredLocked() {
2332            if (!mFullWifiLockOut) {
2333                mFullWifiLockOut = true;
2334                if (mFullWifiLockTimer == null) {
2335                    mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
2336                            mFullWifiLockTimers, mUnpluggables);
2337                }
2338                mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
2339            }
2340        }
2341
2342        @Override
2343        public void noteFullWifiLockReleasedLocked() {
2344            if (mFullWifiLockOut) {
2345                mFullWifiLockOut = false;
2346                mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
2347            }
2348        }
2349
2350        @Override
2351        public void noteScanWifiLockAcquiredLocked() {
2352            if (!mScanWifiLockOut) {
2353                mScanWifiLockOut = true;
2354                if (mScanWifiLockTimer == null) {
2355                    mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
2356                            mScanWifiLockTimers, mUnpluggables);
2357                }
2358                mScanWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
2359            }
2360        }
2361
2362        @Override
2363        public void noteScanWifiLockReleasedLocked() {
2364            if (mScanWifiLockOut) {
2365                mScanWifiLockOut = false;
2366                mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
2367            }
2368        }
2369
2370        @Override
2371        public void noteWifiMulticastEnabledLocked() {
2372            if (!mWifiMulticastEnabled) {
2373                mWifiMulticastEnabled = true;
2374                if (mWifiMulticastTimer == null) {
2375                    mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
2376                            mWifiMulticastTimers, mUnpluggables);
2377                }
2378                mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
2379            }
2380        }
2381
2382        @Override
2383        public void noteWifiMulticastDisabledLocked() {
2384            if (mWifiMulticastEnabled) {
2385                mWifiMulticastEnabled = false;
2386                mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
2387            }
2388        }
2389
2390        @Override
2391        public void noteAudioTurnedOnLocked() {
2392            if (!mAudioTurnedOn) {
2393                mAudioTurnedOn = true;
2394                if (mAudioTurnedOnTimer == null) {
2395                    mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
2396                            null, mUnpluggables);
2397                }
2398                mAudioTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
2399            }
2400        }
2401
2402        @Override
2403        public void noteAudioTurnedOffLocked() {
2404            if (mAudioTurnedOn) {
2405                mAudioTurnedOn = false;
2406                mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
2407            }
2408        }
2409
2410        @Override
2411        public void noteVideoTurnedOnLocked() {
2412            if (!mVideoTurnedOn) {
2413                mVideoTurnedOn = true;
2414                if (mVideoTurnedOnTimer == null) {
2415                    mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
2416                            null, mUnpluggables);
2417                }
2418                mVideoTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
2419            }
2420        }
2421
2422        @Override
2423        public void noteVideoTurnedOffLocked() {
2424            if (mVideoTurnedOn) {
2425                mVideoTurnedOn = false;
2426                mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
2427            }
2428        }
2429
2430        @Override
2431        public long getWifiRunningTime(long batteryRealtime, int which) {
2432            if (mWifiRunningTimer == null) {
2433                return 0;
2434            }
2435            return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
2436        }
2437
2438        @Override
2439        public long getFullWifiLockTime(long batteryRealtime, int which) {
2440            if (mFullWifiLockTimer == null) {
2441                return 0;
2442            }
2443            return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
2444        }
2445
2446        @Override
2447        public long getScanWifiLockTime(long batteryRealtime, int which) {
2448            if (mScanWifiLockTimer == null) {
2449                return 0;
2450            }
2451            return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
2452        }
2453
2454        @Override
2455        public long getWifiMulticastTime(long batteryRealtime, int which) {
2456            if (mWifiMulticastTimer == null) {
2457                return 0;
2458            }
2459            return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime,
2460                                                          which);
2461        }
2462
2463        @Override
2464        public long getAudioTurnedOnTime(long batteryRealtime, int which) {
2465            if (mAudioTurnedOnTimer == null) {
2466                return 0;
2467            }
2468            return mAudioTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
2469        }
2470
2471        @Override
2472        public long getVideoTurnedOnTime(long batteryRealtime, int which) {
2473            if (mVideoTurnedOnTimer == null) {
2474                return 0;
2475            }
2476            return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
2477        }
2478
2479        @Override
2480        public void noteUserActivityLocked(int type) {
2481            if (mUserActivityCounters == null) {
2482                initUserActivityLocked();
2483            }
2484            if (type < 0) type = 0;
2485            else if (type >= NUM_USER_ACTIVITY_TYPES) type = NUM_USER_ACTIVITY_TYPES-1;
2486            mUserActivityCounters[type].stepAtomic();
2487        }
2488
2489        @Override
2490        public boolean hasUserActivity() {
2491            return mUserActivityCounters != null;
2492        }
2493
2494        @Override
2495        public int getUserActivityCount(int type, int which) {
2496            if (mUserActivityCounters == null) {
2497                return 0;
2498            }
2499            return mUserActivityCounters[type].getCountLocked(which);
2500        }
2501
2502        void initUserActivityLocked() {
2503            mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
2504            for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2505                mUserActivityCounters[i] = new Counter(mUnpluggables);
2506            }
2507        }
2508
2509        public long computeCurrentTcpBytesSent() {
2510            return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
2511                    ? (TrafficStats.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
2512        }
2513
2514        /**
2515         * Clear all stats for this uid.  Returns true if the uid is completely
2516         * inactive so can be dropped.
2517         */
2518        boolean reset() {
2519            boolean active = false;
2520
2521            if (mWifiRunningTimer != null) {
2522                active |= !mWifiRunningTimer.reset(BatteryStatsImpl.this, false);
2523                active |= mWifiRunning;
2524            }
2525            if (mFullWifiLockTimer != null) {
2526                active |= !mFullWifiLockTimer.reset(BatteryStatsImpl.this, false);
2527                active |= mFullWifiLockOut;
2528            }
2529            if (mScanWifiLockTimer != null) {
2530                active |= !mScanWifiLockTimer.reset(BatteryStatsImpl.this, false);
2531                active |= mScanWifiLockOut;
2532            }
2533            if (mWifiMulticastTimer != null) {
2534                active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
2535                active |= mWifiMulticastEnabled;
2536            }
2537            if (mAudioTurnedOnTimer != null) {
2538                active |= !mAudioTurnedOnTimer.reset(BatteryStatsImpl.this, false);
2539                active |= mAudioTurnedOn;
2540            }
2541            if (mVideoTurnedOnTimer != null) {
2542                active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
2543                active |= mVideoTurnedOn;
2544            }
2545
2546            mLoadedTcpBytesReceived = mLoadedTcpBytesSent = 0;
2547            mCurrentTcpBytesReceived = mCurrentTcpBytesSent = 0;
2548
2549            if (mUserActivityCounters != null) {
2550                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2551                    mUserActivityCounters[i].reset(false);
2552                }
2553            }
2554
2555            if (mWakelockStats.size() > 0) {
2556                Iterator<Map.Entry<String, Wakelock>> it = mWakelockStats.entrySet().iterator();
2557                while (it.hasNext()) {
2558                    Map.Entry<String, Wakelock> wakelockEntry = it.next();
2559                    Wakelock wl = wakelockEntry.getValue();
2560                    if (wl.reset()) {
2561                        it.remove();
2562                    } else {
2563                        active = true;
2564                    }
2565                }
2566            }
2567            if (mSensorStats.size() > 0) {
2568                Iterator<Map.Entry<Integer, Sensor>> it = mSensorStats.entrySet().iterator();
2569                while (it.hasNext()) {
2570                    Map.Entry<Integer, Sensor> sensorEntry = it.next();
2571                    Sensor s = sensorEntry.getValue();
2572                    if (s.reset()) {
2573                        it.remove();
2574                    } else {
2575                        active = true;
2576                    }
2577                }
2578            }
2579            if (mProcessStats.size() > 0) {
2580                Iterator<Map.Entry<String, Proc>> it = mProcessStats.entrySet().iterator();
2581                while (it.hasNext()) {
2582                    Map.Entry<String, Proc> procEntry = it.next();
2583                    procEntry.getValue().detach();
2584                }
2585                mProcessStats.clear();
2586            }
2587            if (mPids.size() > 0) {
2588                for (int i=0; !active && i<mPids.size(); i++) {
2589                    Pid pid = mPids.valueAt(i);
2590                    if (pid.mWakeStart != 0) {
2591                        active = true;
2592                    }
2593                }
2594            }
2595            if (mPackageStats.size() > 0) {
2596                Iterator<Map.Entry<String, Pkg>> it = mPackageStats.entrySet().iterator();
2597                while (it.hasNext()) {
2598                    Map.Entry<String, Pkg> pkgEntry = it.next();
2599                    Pkg p = pkgEntry.getValue();
2600                    p.detach();
2601                    if (p.mServiceStats.size() > 0) {
2602                        Iterator<Map.Entry<String, Pkg.Serv>> it2
2603                                = p.mServiceStats.entrySet().iterator();
2604                        while (it2.hasNext()) {
2605                            Map.Entry<String, Pkg.Serv> servEntry = it2.next();
2606                            servEntry.getValue().detach();
2607                        }
2608                    }
2609                }
2610                mPackageStats.clear();
2611            }
2612
2613            mPids.clear();
2614
2615            if (!active) {
2616                if (mWifiRunningTimer != null) {
2617                    mWifiRunningTimer.detach();
2618                }
2619                if (mFullWifiLockTimer != null) {
2620                    mFullWifiLockTimer.detach();
2621                }
2622                if (mScanWifiLockTimer != null) {
2623                    mScanWifiLockTimer.detach();
2624                }
2625                if (mWifiMulticastTimer != null) {
2626                    mWifiMulticastTimer.detach();
2627                }
2628                if (mAudioTurnedOnTimer != null) {
2629                    mAudioTurnedOnTimer.detach();
2630                }
2631                if (mVideoTurnedOnTimer != null) {
2632                    mVideoTurnedOnTimer.detach();
2633                }
2634                if (mUserActivityCounters != null) {
2635                    for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2636                        mUserActivityCounters[i].detach();
2637                    }
2638                }
2639            }
2640
2641            return !active;
2642        }
2643
2644        void writeToParcelLocked(Parcel out, long batteryRealtime) {
2645            out.writeInt(mWakelockStats.size());
2646            for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
2647                out.writeString(wakelockEntry.getKey());
2648                Uid.Wakelock wakelock = wakelockEntry.getValue();
2649                wakelock.writeToParcelLocked(out, batteryRealtime);
2650            }
2651
2652            out.writeInt(mSensorStats.size());
2653            for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
2654                out.writeInt(sensorEntry.getKey());
2655                Uid.Sensor sensor = sensorEntry.getValue();
2656                sensor.writeToParcelLocked(out, batteryRealtime);
2657            }
2658
2659            out.writeInt(mProcessStats.size());
2660            for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
2661                out.writeString(procEntry.getKey());
2662                Uid.Proc proc = procEntry.getValue();
2663                proc.writeToParcelLocked(out);
2664            }
2665
2666            out.writeInt(mPackageStats.size());
2667            for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
2668                out.writeString(pkgEntry.getKey());
2669                Uid.Pkg pkg = pkgEntry.getValue();
2670                pkg.writeToParcelLocked(out);
2671            }
2672
2673            out.writeLong(mLoadedTcpBytesReceived);
2674            out.writeLong(mLoadedTcpBytesSent);
2675            out.writeLong(computeCurrentTcpBytesReceived());
2676            out.writeLong(computeCurrentTcpBytesSent());
2677            out.writeLong(mTcpBytesReceivedAtLastUnplug);
2678            out.writeLong(mTcpBytesSentAtLastUnplug);
2679            if (mWifiRunningTimer != null) {
2680                out.writeInt(1);
2681                mWifiRunningTimer.writeToParcel(out, batteryRealtime);
2682            } else {
2683                out.writeInt(0);
2684            }
2685            if (mFullWifiLockTimer != null) {
2686                out.writeInt(1);
2687                mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
2688            } else {
2689                out.writeInt(0);
2690            }
2691            if (mScanWifiLockTimer != null) {
2692                out.writeInt(1);
2693                mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
2694            } else {
2695                out.writeInt(0);
2696            }
2697            if (mWifiMulticastTimer != null) {
2698                out.writeInt(1);
2699                mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
2700            } else {
2701                out.writeInt(0);
2702            }
2703            if (mAudioTurnedOnTimer != null) {
2704                out.writeInt(1);
2705                mAudioTurnedOnTimer.writeToParcel(out, batteryRealtime);
2706            } else {
2707                out.writeInt(0);
2708            }
2709            if (mVideoTurnedOnTimer != null) {
2710                out.writeInt(1);
2711                mVideoTurnedOnTimer.writeToParcel(out, batteryRealtime);
2712            } else {
2713                out.writeInt(0);
2714            }
2715            if (mUserActivityCounters != null) {
2716                out.writeInt(1);
2717                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2718                    mUserActivityCounters[i].writeToParcel(out);
2719                }
2720            } else {
2721                out.writeInt(0);
2722            }
2723        }
2724
2725        void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
2726            int numWakelocks = in.readInt();
2727            mWakelockStats.clear();
2728            for (int j = 0; j < numWakelocks; j++) {
2729                String wakelockName = in.readString();
2730                Uid.Wakelock wakelock = new Wakelock();
2731                wakelock.readFromParcelLocked(unpluggables, in);
2732                if (mWakelockStats.size() < MAX_WAKELOCKS_PER_UID) {
2733                    // We will just drop some random set of wakelocks if
2734                    // the previous run of the system was an older version
2735                    // that didn't impose a limit.
2736                    mWakelockStats.put(wakelockName, wakelock);
2737                }
2738            }
2739
2740            int numSensors = in.readInt();
2741            mSensorStats.clear();
2742            for (int k = 0; k < numSensors; k++) {
2743                int sensorNumber = in.readInt();
2744                Uid.Sensor sensor = new Sensor(sensorNumber);
2745                sensor.readFromParcelLocked(mUnpluggables, in);
2746                mSensorStats.put(sensorNumber, sensor);
2747            }
2748
2749            int numProcs = in.readInt();
2750            mProcessStats.clear();
2751            for (int k = 0; k < numProcs; k++) {
2752                String processName = in.readString();
2753                Uid.Proc proc = new Proc();
2754                proc.readFromParcelLocked(in);
2755                mProcessStats.put(processName, proc);
2756            }
2757
2758            int numPkgs = in.readInt();
2759            mPackageStats.clear();
2760            for (int l = 0; l < numPkgs; l++) {
2761                String packageName = in.readString();
2762                Uid.Pkg pkg = new Pkg();
2763                pkg.readFromParcelLocked(in);
2764                mPackageStats.put(packageName, pkg);
2765            }
2766
2767            mLoadedTcpBytesReceived = in.readLong();
2768            mLoadedTcpBytesSent = in.readLong();
2769            mCurrentTcpBytesReceived = in.readLong();
2770            mCurrentTcpBytesSent = in.readLong();
2771            mTcpBytesReceivedAtLastUnplug = in.readLong();
2772            mTcpBytesSentAtLastUnplug = in.readLong();
2773            mWifiRunning = false;
2774            if (in.readInt() != 0) {
2775                mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
2776                        mWifiRunningTimers, mUnpluggables, in);
2777            } else {
2778                mWifiRunningTimer = null;
2779            }
2780            mFullWifiLockOut = false;
2781            if (in.readInt() != 0) {
2782                mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
2783                        mFullWifiLockTimers, mUnpluggables, in);
2784            } else {
2785                mFullWifiLockTimer = null;
2786            }
2787            mScanWifiLockOut = false;
2788            if (in.readInt() != 0) {
2789                mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
2790                        mScanWifiLockTimers, mUnpluggables, in);
2791            } else {
2792                mScanWifiLockTimer = null;
2793            }
2794            mWifiMulticastEnabled = false;
2795            if (in.readInt() != 0) {
2796                mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
2797                        mWifiMulticastTimers, mUnpluggables, in);
2798            } else {
2799                mWifiMulticastTimer = null;
2800            }
2801            mAudioTurnedOn = false;
2802            if (in.readInt() != 0) {
2803                mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
2804                        null, mUnpluggables, in);
2805            } else {
2806                mAudioTurnedOnTimer = null;
2807            }
2808            mVideoTurnedOn = false;
2809            if (in.readInt() != 0) {
2810                mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
2811                        null, mUnpluggables, in);
2812            } else {
2813                mVideoTurnedOnTimer = null;
2814            }
2815            if (in.readInt() != 0) {
2816                mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
2817                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2818                    mUserActivityCounters[i] = new Counter(mUnpluggables, in);
2819                }
2820            } else {
2821                mUserActivityCounters = null;
2822            }
2823        }
2824
2825        /**
2826         * The statistics associated with a particular wake lock.
2827         */
2828        public final class Wakelock extends BatteryStats.Uid.Wakelock {
2829            /**
2830             * How long (in ms) this uid has been keeping the device partially awake.
2831             */
2832            StopwatchTimer mTimerPartial;
2833
2834            /**
2835             * How long (in ms) this uid has been keeping the device fully awake.
2836             */
2837            StopwatchTimer mTimerFull;
2838
2839            /**
2840             * How long (in ms) this uid has had a window keeping the device awake.
2841             */
2842            StopwatchTimer mTimerWindow;
2843
2844            /**
2845             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
2846             * proper timer pool from the given BatteryStatsImpl object.
2847             *
2848             * @param in the Parcel to be read from.
2849             * return a new Timer, or null.
2850             */
2851            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
2852                    ArrayList<Unpluggable> unpluggables, Parcel in) {
2853                if (in.readInt() == 0) {
2854                    return null;
2855                }
2856
2857                return new StopwatchTimer(Uid.this, type, pool, unpluggables, in);
2858            }
2859
2860            boolean reset() {
2861                boolean wlactive = false;
2862                if (mTimerFull != null) {
2863                    wlactive |= !mTimerFull.reset(BatteryStatsImpl.this, false);
2864                }
2865                if (mTimerPartial != null) {
2866                    wlactive |= !mTimerPartial.reset(BatteryStatsImpl.this, false);
2867                }
2868                if (mTimerWindow != null) {
2869                    wlactive |= !mTimerWindow.reset(BatteryStatsImpl.this, false);
2870                }
2871                if (!wlactive) {
2872                    if (mTimerFull != null) {
2873                        mTimerFull.detach();
2874                        mTimerFull = null;
2875                    }
2876                    if (mTimerPartial != null) {
2877                        mTimerPartial.detach();
2878                        mTimerPartial = null;
2879                    }
2880                    if (mTimerWindow != null) {
2881                        mTimerWindow.detach();
2882                        mTimerWindow = null;
2883                    }
2884                }
2885                return !wlactive;
2886            }
2887
2888            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
2889                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
2890                        mPartialTimers, unpluggables, in);
2891                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
2892                        mFullTimers, unpluggables, in);
2893                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
2894                        mWindowTimers, unpluggables, in);
2895            }
2896
2897            void writeToParcelLocked(Parcel out, long batteryRealtime) {
2898                Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
2899                Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
2900                Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
2901            }
2902
2903            @Override
2904            public Timer getWakeTime(int type) {
2905                switch (type) {
2906                case WAKE_TYPE_FULL: return mTimerFull;
2907                case WAKE_TYPE_PARTIAL: return mTimerPartial;
2908                case WAKE_TYPE_WINDOW: return mTimerWindow;
2909                default: throw new IllegalArgumentException("type = " + type);
2910                }
2911            }
2912        }
2913
2914        public final class Sensor extends BatteryStats.Uid.Sensor {
2915            final int mHandle;
2916            StopwatchTimer mTimer;
2917
2918            public Sensor(int handle) {
2919                mHandle = handle;
2920            }
2921
2922            private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
2923                    Parcel in) {
2924                if (in.readInt() == 0) {
2925                    return null;
2926                }
2927
2928                ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
2929                if (pool == null) {
2930                    pool = new ArrayList<StopwatchTimer>();
2931                    mSensorTimers.put(mHandle, pool);
2932                }
2933                return new StopwatchTimer(Uid.this, 0, pool, unpluggables, in);
2934            }
2935
2936            boolean reset() {
2937                if (mTimer.reset(BatteryStatsImpl.this, true)) {
2938                    mTimer = null;
2939                    return true;
2940                }
2941                return false;
2942            }
2943
2944            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
2945                mTimer = readTimerFromParcel(unpluggables, in);
2946            }
2947
2948            void writeToParcelLocked(Parcel out, long batteryRealtime) {
2949                Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
2950            }
2951
2952            @Override
2953            public Timer getSensorTime() {
2954                return mTimer;
2955            }
2956
2957            @Override
2958            public int getHandle() {
2959                return mHandle;
2960            }
2961        }
2962
2963        /**
2964         * The statistics associated with a particular process.
2965         */
2966        public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
2967            /**
2968             * Total time (in 1/100 sec) spent executing in user code.
2969             */
2970            long mUserTime;
2971
2972            /**
2973             * Total time (in 1/100 sec) spent executing in kernel code.
2974             */
2975            long mSystemTime;
2976
2977            /**
2978             * Number of times the process has been started.
2979             */
2980            int mStarts;
2981
2982            /**
2983             * Amount of time the process was running in the foreground.
2984             */
2985            long mForegroundTime;
2986
2987            /**
2988             * The amount of user time loaded from a previous save.
2989             */
2990            long mLoadedUserTime;
2991
2992            /**
2993             * The amount of system time loaded from a previous save.
2994             */
2995            long mLoadedSystemTime;
2996
2997            /**
2998             * The number of times the process has started from a previous save.
2999             */
3000            int mLoadedStarts;
3001
3002            /**
3003             * The amount of foreground time loaded from a previous save.
3004             */
3005            long mLoadedForegroundTime;
3006
3007            /**
3008             * The amount of user time loaded from the previous run.
3009             */
3010            long mLastUserTime;
3011
3012            /**
3013             * The amount of system time loaded from the previous run.
3014             */
3015            long mLastSystemTime;
3016
3017            /**
3018             * The number of times the process has started from the previous run.
3019             */
3020            int mLastStarts;
3021
3022            /**
3023             * The amount of foreground time loaded from the previous run
3024             */
3025            long mLastForegroundTime;
3026
3027            /**
3028             * The amount of user time when last unplugged.
3029             */
3030            long mUnpluggedUserTime;
3031
3032            /**
3033             * The amount of system time when last unplugged.
3034             */
3035            long mUnpluggedSystemTime;
3036
3037            /**
3038             * The number of times the process has started before unplugged.
3039             */
3040            int mUnpluggedStarts;
3041
3042            /**
3043             * The amount of foreground time since unplugged.
3044             */
3045            long mUnpluggedForegroundTime;
3046
3047            SamplingCounter[] mSpeedBins;
3048
3049            ArrayList<ExcessivePower> mExcessivePower;
3050
3051            Proc() {
3052                mUnpluggables.add(this);
3053                mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
3054            }
3055
3056            public void unplug(long batteryUptime, long batteryRealtime) {
3057                mUnpluggedUserTime = mUserTime;
3058                mUnpluggedSystemTime = mSystemTime;
3059                mUnpluggedStarts = mStarts;
3060                mUnpluggedForegroundTime = mForegroundTime;
3061            }
3062
3063            public void plug(long batteryUptime, long batteryRealtime) {
3064            }
3065
3066            void detach() {
3067                mUnpluggables.remove(this);
3068                for (int i = 0; i < mSpeedBins.length; i++) {
3069                    SamplingCounter c = mSpeedBins[i];
3070                    if (c != null) {
3071                        mUnpluggables.remove(c);
3072                        mSpeedBins[i] = null;
3073                    }
3074                }
3075            }
3076
3077            public int countExcessivePowers() {
3078                return mExcessivePower != null ? mExcessivePower.size() : 0;
3079            }
3080
3081            public ExcessivePower getExcessivePower(int i) {
3082                if (mExcessivePower != null) {
3083                    return mExcessivePower.get(i);
3084                }
3085                return null;
3086            }
3087
3088            public void addExcessiveWake(long overTime, long usedTime) {
3089                if (mExcessivePower == null) {
3090                    mExcessivePower = new ArrayList<ExcessivePower>();
3091                }
3092                ExcessivePower ew = new ExcessivePower();
3093                ew.type = ExcessivePower.TYPE_WAKE;
3094                ew.overTime = overTime;
3095                ew.usedTime = usedTime;
3096                mExcessivePower.add(ew);
3097            }
3098
3099            public void addExcessiveCpu(long overTime, long usedTime) {
3100                if (mExcessivePower == null) {
3101                    mExcessivePower = new ArrayList<ExcessivePower>();
3102                }
3103                ExcessivePower ew = new ExcessivePower();
3104                ew.type = ExcessivePower.TYPE_CPU;
3105                ew.overTime = overTime;
3106                ew.usedTime = usedTime;
3107                mExcessivePower.add(ew);
3108            }
3109
3110            void writeExcessivePowerToParcelLocked(Parcel out) {
3111                if (mExcessivePower == null) {
3112                    out.writeInt(0);
3113                    return;
3114                }
3115
3116                final int N = mExcessivePower.size();
3117                out.writeInt(N);
3118                for (int i=0; i<N; i++) {
3119                    ExcessivePower ew = mExcessivePower.get(i);
3120                    out.writeInt(ew.type);
3121                    out.writeLong(ew.overTime);
3122                    out.writeLong(ew.usedTime);
3123                }
3124            }
3125
3126            boolean readExcessivePowerFromParcelLocked(Parcel in) {
3127                final int N = in.readInt();
3128                if (N == 0) {
3129                    mExcessivePower = null;
3130                    return true;
3131                }
3132
3133                if (N > 10000) {
3134                    Slog.w(TAG, "File corrupt: too many excessive power entries " + N);
3135                    return false;
3136                }
3137
3138                mExcessivePower = new ArrayList<ExcessivePower>();
3139                for (int i=0; i<N; i++) {
3140                    ExcessivePower ew = new ExcessivePower();
3141                    ew.type = in.readInt();
3142                    ew.overTime = in.readLong();
3143                    ew.usedTime = in.readLong();
3144                    mExcessivePower.add(ew);
3145                }
3146                return true;
3147            }
3148
3149            void writeToParcelLocked(Parcel out) {
3150                out.writeLong(mUserTime);
3151                out.writeLong(mSystemTime);
3152                out.writeLong(mForegroundTime);
3153                out.writeInt(mStarts);
3154                out.writeLong(mLoadedUserTime);
3155                out.writeLong(mLoadedSystemTime);
3156                out.writeLong(mLoadedForegroundTime);
3157                out.writeInt(mLoadedStarts);
3158                out.writeLong(mUnpluggedUserTime);
3159                out.writeLong(mUnpluggedSystemTime);
3160                out.writeLong(mUnpluggedForegroundTime);
3161                out.writeInt(mUnpluggedStarts);
3162
3163                out.writeInt(mSpeedBins.length);
3164                for (int i = 0; i < mSpeedBins.length; i++) {
3165                    SamplingCounter c = mSpeedBins[i];
3166                    if (c != null) {
3167                        out.writeInt(1);
3168                        c.writeToParcel(out);
3169                    } else {
3170                        out.writeInt(0);
3171                    }
3172                }
3173
3174                writeExcessivePowerToParcelLocked(out);
3175            }
3176
3177            void readFromParcelLocked(Parcel in) {
3178                mUserTime = in.readLong();
3179                mSystemTime = in.readLong();
3180                mForegroundTime = in.readLong();
3181                mStarts = in.readInt();
3182                mLoadedUserTime = in.readLong();
3183                mLoadedSystemTime = in.readLong();
3184                mLoadedForegroundTime = in.readLong();
3185                mLoadedStarts = in.readInt();
3186                mLastUserTime = 0;
3187                mLastSystemTime = 0;
3188                mLastForegroundTime = 0;
3189                mLastStarts = 0;
3190                mUnpluggedUserTime = in.readLong();
3191                mUnpluggedSystemTime = in.readLong();
3192                mUnpluggedForegroundTime = in.readLong();
3193                mUnpluggedStarts = in.readInt();
3194
3195                int bins = in.readInt();
3196                int steps = getCpuSpeedSteps();
3197                mSpeedBins = new SamplingCounter[bins >= steps ? bins : steps];
3198                for (int i = 0; i < bins; i++) {
3199                    if (in.readInt() != 0) {
3200                        mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
3201                    }
3202                }
3203
3204                readExcessivePowerFromParcelLocked(in);
3205            }
3206
3207            public BatteryStatsImpl getBatteryStats() {
3208                return BatteryStatsImpl.this;
3209            }
3210
3211            public void addCpuTimeLocked(int utime, int stime) {
3212                mUserTime += utime;
3213                mSystemTime += stime;
3214            }
3215
3216            public void addForegroundTimeLocked(long ttime) {
3217                mForegroundTime += ttime;
3218            }
3219
3220            public void incStartsLocked() {
3221                mStarts++;
3222            }
3223
3224            @Override
3225            public long getUserTime(int which) {
3226                long val;
3227                if (which == STATS_LAST) {
3228                    val = mLastUserTime;
3229                } else {
3230                    val = mUserTime;
3231                    if (which == STATS_CURRENT) {
3232                        val -= mLoadedUserTime;
3233                    } else if (which == STATS_SINCE_UNPLUGGED) {
3234                        val -= mUnpluggedUserTime;
3235                    }
3236                }
3237                return val;
3238            }
3239
3240            @Override
3241            public long getSystemTime(int which) {
3242                long val;
3243                if (which == STATS_LAST) {
3244                    val = mLastSystemTime;
3245                } else {
3246                    val = mSystemTime;
3247                    if (which == STATS_CURRENT) {
3248                        val -= mLoadedSystemTime;
3249                    } else if (which == STATS_SINCE_UNPLUGGED) {
3250                        val -= mUnpluggedSystemTime;
3251                    }
3252                }
3253                return val;
3254            }
3255
3256            @Override
3257            public long getForegroundTime(int which) {
3258                long val;
3259                if (which == STATS_LAST) {
3260                    val = mLastForegroundTime;
3261                } else {
3262                    val = mForegroundTime;
3263                    if (which == STATS_CURRENT) {
3264                        val -= mLoadedForegroundTime;
3265                    } else if (which == STATS_SINCE_UNPLUGGED) {
3266                        val -= mUnpluggedForegroundTime;
3267                    }
3268                }
3269                return val;
3270            }
3271
3272            @Override
3273            public int getStarts(int which) {
3274                int val;
3275                if (which == STATS_LAST) {
3276                    val = mLastStarts;
3277                } else {
3278                    val = mStarts;
3279                    if (which == STATS_CURRENT) {
3280                        val -= mLoadedStarts;
3281                    } else if (which == STATS_SINCE_UNPLUGGED) {
3282                        val -= mUnpluggedStarts;
3283                    }
3284                }
3285                return val;
3286            }
3287
3288            /* Called by ActivityManagerService when CPU times are updated. */
3289            public void addSpeedStepTimes(long[] values) {
3290                for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
3291                    long amt = values[i];
3292                    if (amt != 0) {
3293                        SamplingCounter c = mSpeedBins[i];
3294                        if (c == null) {
3295                            mSpeedBins[i] = c = new SamplingCounter(mUnpluggables);
3296                        }
3297                        c.addCountAtomic(values[i]);
3298                    }
3299                }
3300            }
3301
3302            @Override
3303            public long getTimeAtCpuSpeedStep(int speedStep, int which) {
3304                if (speedStep < mSpeedBins.length) {
3305                    SamplingCounter c = mSpeedBins[speedStep];
3306                    return c != null ? c.getCountLocked(which) : 0;
3307                } else {
3308                    return 0;
3309                }
3310            }
3311        }
3312
3313        /**
3314         * The statistics associated with a particular package.
3315         */
3316        public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
3317            /**
3318             * Number of times this package has done something that could wake up the
3319             * device from sleep.
3320             */
3321            int mWakeups;
3322
3323            /**
3324             * Number of things that could wake up the device loaded from a
3325             * previous save.
3326             */
3327            int mLoadedWakeups;
3328
3329            /**
3330             * Number of things that could wake up the device as of the
3331             * last run.
3332             */
3333            int mLastWakeups;
3334
3335            /**
3336             * Number of things that could wake up the device as of the
3337             * last run.
3338             */
3339            int mUnpluggedWakeups;
3340
3341            /**
3342             * The statics we have collected for this package's services.
3343             */
3344            final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
3345
3346            Pkg() {
3347                mUnpluggables.add(this);
3348            }
3349
3350            public void unplug(long batteryUptime, long batteryRealtime) {
3351                mUnpluggedWakeups = mWakeups;
3352            }
3353
3354            public void plug(long batteryUptime, long batteryRealtime) {
3355            }
3356
3357            void detach() {
3358                mUnpluggables.remove(this);
3359            }
3360
3361            void readFromParcelLocked(Parcel in) {
3362                mWakeups = in.readInt();
3363                mLoadedWakeups = in.readInt();
3364                mLastWakeups = 0;
3365                mUnpluggedWakeups = in.readInt();
3366
3367                int numServs = in.readInt();
3368                mServiceStats.clear();
3369                for (int m = 0; m < numServs; m++) {
3370                    String serviceName = in.readString();
3371                    Uid.Pkg.Serv serv = new Serv();
3372                    mServiceStats.put(serviceName, serv);
3373
3374                    serv.readFromParcelLocked(in);
3375                }
3376            }
3377
3378            void writeToParcelLocked(Parcel out) {
3379                out.writeInt(mWakeups);
3380                out.writeInt(mLoadedWakeups);
3381                out.writeInt(mUnpluggedWakeups);
3382
3383                out.writeInt(mServiceStats.size());
3384                for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
3385                    out.writeString(servEntry.getKey());
3386                    Uid.Pkg.Serv serv = servEntry.getValue();
3387
3388                    serv.writeToParcelLocked(out);
3389                }
3390            }
3391
3392            @Override
3393            public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
3394                return mServiceStats;
3395            }
3396
3397            @Override
3398            public int getWakeups(int which) {
3399                int val;
3400                if (which == STATS_LAST) {
3401                    val = mLastWakeups;
3402                } else {
3403                    val = mWakeups;
3404                    if (which == STATS_CURRENT) {
3405                        val -= mLoadedWakeups;
3406                    } else if (which == STATS_SINCE_UNPLUGGED) {
3407                        val -= mUnpluggedWakeups;
3408                    }
3409                }
3410
3411                return val;
3412            }
3413
3414            /**
3415             * The statistics associated with a particular service.
3416             */
3417            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
3418                /**
3419                 * Total time (ms in battery uptime) the service has been left started.
3420                 */
3421                long mStartTime;
3422
3423                /**
3424                 * If service has been started and not yet stopped, this is
3425                 * when it was started.
3426                 */
3427                long mRunningSince;
3428
3429                /**
3430                 * True if we are currently running.
3431                 */
3432                boolean mRunning;
3433
3434                /**
3435                 * Total number of times startService() has been called.
3436                 */
3437                int mStarts;
3438
3439                /**
3440                 * Total time (ms in battery uptime) the service has been left launched.
3441                 */
3442                long mLaunchedTime;
3443
3444                /**
3445                 * If service has been launched and not yet exited, this is
3446                 * when it was launched (ms in battery uptime).
3447                 */
3448                long mLaunchedSince;
3449
3450                /**
3451                 * True if we are currently launched.
3452                 */
3453                boolean mLaunched;
3454
3455                /**
3456                 * Total number times the service has been launched.
3457                 */
3458                int mLaunches;
3459
3460                /**
3461                 * The amount of time spent started loaded from a previous save
3462                 * (ms in battery uptime).
3463                 */
3464                long mLoadedStartTime;
3465
3466                /**
3467                 * The number of starts loaded from a previous save.
3468                 */
3469                int mLoadedStarts;
3470
3471                /**
3472                 * The number of launches loaded from a previous save.
3473                 */
3474                int mLoadedLaunches;
3475
3476                /**
3477                 * The amount of time spent started as of the last run (ms
3478                 * in battery uptime).
3479                 */
3480                long mLastStartTime;
3481
3482                /**
3483                 * The number of starts as of the last run.
3484                 */
3485                int mLastStarts;
3486
3487                /**
3488                 * The number of launches as of the last run.
3489                 */
3490                int mLastLaunches;
3491
3492                /**
3493                 * The amount of time spent started when last unplugged (ms
3494                 * in battery uptime).
3495                 */
3496                long mUnpluggedStartTime;
3497
3498                /**
3499                 * The number of starts when last unplugged.
3500                 */
3501                int mUnpluggedStarts;
3502
3503                /**
3504                 * The number of launches when last unplugged.
3505                 */
3506                int mUnpluggedLaunches;
3507
3508                Serv() {
3509                    mUnpluggables.add(this);
3510                }
3511
3512                public void unplug(long batteryUptime, long batteryRealtime) {
3513                    mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
3514                    mUnpluggedStarts = mStarts;
3515                    mUnpluggedLaunches = mLaunches;
3516                }
3517
3518                public void plug(long batteryUptime, long batteryRealtime) {
3519                }
3520
3521                void detach() {
3522                    mUnpluggables.remove(this);
3523                }
3524
3525                void readFromParcelLocked(Parcel in) {
3526                    mStartTime = in.readLong();
3527                    mRunningSince = in.readLong();
3528                    mRunning = in.readInt() != 0;
3529                    mStarts = in.readInt();
3530                    mLaunchedTime = in.readLong();
3531                    mLaunchedSince = in.readLong();
3532                    mLaunched = in.readInt() != 0;
3533                    mLaunches = in.readInt();
3534                    mLoadedStartTime = in.readLong();
3535                    mLoadedStarts = in.readInt();
3536                    mLoadedLaunches = in.readInt();
3537                    mLastStartTime = 0;
3538                    mLastStarts = 0;
3539                    mLastLaunches = 0;
3540                    mUnpluggedStartTime = in.readLong();
3541                    mUnpluggedStarts = in.readInt();
3542                    mUnpluggedLaunches = in.readInt();
3543                }
3544
3545                void writeToParcelLocked(Parcel out) {
3546                    out.writeLong(mStartTime);
3547                    out.writeLong(mRunningSince);
3548                    out.writeInt(mRunning ? 1 : 0);
3549                    out.writeInt(mStarts);
3550                    out.writeLong(mLaunchedTime);
3551                    out.writeLong(mLaunchedSince);
3552                    out.writeInt(mLaunched ? 1 : 0);
3553                    out.writeInt(mLaunches);
3554                    out.writeLong(mLoadedStartTime);
3555                    out.writeInt(mLoadedStarts);
3556                    out.writeInt(mLoadedLaunches);
3557                    out.writeLong(mUnpluggedStartTime);
3558                    out.writeInt(mUnpluggedStarts);
3559                    out.writeInt(mUnpluggedLaunches);
3560                }
3561
3562                long getLaunchTimeToNowLocked(long batteryUptime) {
3563                    if (!mLaunched) return mLaunchedTime;
3564                    return mLaunchedTime + batteryUptime - mLaunchedSince;
3565                }
3566
3567                long getStartTimeToNowLocked(long batteryUptime) {
3568                    if (!mRunning) return mStartTime;
3569                    return mStartTime + batteryUptime - mRunningSince;
3570                }
3571
3572                public void startLaunchedLocked() {
3573                    if (!mLaunched) {
3574                        mLaunches++;
3575                        mLaunchedSince = getBatteryUptimeLocked();
3576                        mLaunched = true;
3577                    }
3578                }
3579
3580                public void stopLaunchedLocked() {
3581                    if (mLaunched) {
3582                        long time = getBatteryUptimeLocked() - mLaunchedSince;
3583                        if (time > 0) {
3584                            mLaunchedTime += time;
3585                        } else {
3586                            mLaunches--;
3587                        }
3588                        mLaunched = false;
3589                    }
3590                }
3591
3592                public void startRunningLocked() {
3593                    if (!mRunning) {
3594                        mStarts++;
3595                        mRunningSince = getBatteryUptimeLocked();
3596                        mRunning = true;
3597                    }
3598                }
3599
3600                public void stopRunningLocked() {
3601                    if (mRunning) {
3602                        long time = getBatteryUptimeLocked() - mRunningSince;
3603                        if (time > 0) {
3604                            mStartTime += time;
3605                        } else {
3606                            mStarts--;
3607                        }
3608                        mRunning = false;
3609                    }
3610                }
3611
3612                public BatteryStatsImpl getBatteryStats() {
3613                    return BatteryStatsImpl.this;
3614                }
3615
3616                @Override
3617                public int getLaunches(int which) {
3618                    int val;
3619
3620                    if (which == STATS_LAST) {
3621                        val = mLastLaunches;
3622                    } else {
3623                        val = mLaunches;
3624                        if (which == STATS_CURRENT) {
3625                            val -= mLoadedLaunches;
3626                        } else if (which == STATS_SINCE_UNPLUGGED) {
3627                            val -= mUnpluggedLaunches;
3628                        }
3629                    }
3630
3631                    return val;
3632                }
3633
3634                @Override
3635                public long getStartTime(long now, int which) {
3636                    long val;
3637                    if (which == STATS_LAST) {
3638                        val = mLastStartTime;
3639                    } else {
3640                        val = getStartTimeToNowLocked(now);
3641                        if (which == STATS_CURRENT) {
3642                            val -= mLoadedStartTime;
3643                        } else if (which == STATS_SINCE_UNPLUGGED) {
3644                            val -= mUnpluggedStartTime;
3645                        }
3646                    }
3647
3648                    return val;
3649                }
3650
3651                @Override
3652                public int getStarts(int which) {
3653                    int val;
3654                    if (which == STATS_LAST) {
3655                        val = mLastStarts;
3656                    } else {
3657                        val = mStarts;
3658                        if (which == STATS_CURRENT) {
3659                            val -= mLoadedStarts;
3660                        } else if (which == STATS_SINCE_UNPLUGGED) {
3661                            val -= mUnpluggedStarts;
3662                        }
3663                    }
3664
3665                    return val;
3666                }
3667            }
3668
3669            public BatteryStatsImpl getBatteryStats() {
3670                return BatteryStatsImpl.this;
3671            }
3672
3673            public void incWakeupsLocked() {
3674                mWakeups++;
3675            }
3676
3677            final Serv newServiceStatsLocked() {
3678                return new Serv();
3679            }
3680        }
3681
3682        /**
3683         * Retrieve the statistics object for a particular process, creating
3684         * if needed.
3685         */
3686        public Proc getProcessStatsLocked(String name) {
3687            Proc ps = mProcessStats.get(name);
3688            if (ps == null) {
3689                ps = new Proc();
3690                mProcessStats.put(name, ps);
3691            }
3692
3693            return ps;
3694        }
3695
3696        public SparseArray<? extends Pid> getPidStats() {
3697            return mPids;
3698        }
3699
3700        public Pid getPidStatsLocked(int pid) {
3701            Pid p = mPids.get(pid);
3702            if (p == null) {
3703                p = new Pid();
3704                mPids.put(pid, p);
3705            }
3706            return p;
3707        }
3708
3709        /**
3710         * Retrieve the statistics object for a particular service, creating
3711         * if needed.
3712         */
3713        public Pkg getPackageStatsLocked(String name) {
3714            Pkg ps = mPackageStats.get(name);
3715            if (ps == null) {
3716                ps = new Pkg();
3717                mPackageStats.put(name, ps);
3718            }
3719
3720            return ps;
3721        }
3722
3723        /**
3724         * Retrieve the statistics object for a particular service, creating
3725         * if needed.
3726         */
3727        public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
3728            Pkg ps = getPackageStatsLocked(pkg);
3729            Pkg.Serv ss = ps.mServiceStats.get(serv);
3730            if (ss == null) {
3731                ss = ps.newServiceStatsLocked();
3732                ps.mServiceStats.put(serv, ss);
3733            }
3734
3735            return ss;
3736        }
3737
3738        public StopwatchTimer getWakeTimerLocked(String name, int type) {
3739            Wakelock wl = mWakelockStats.get(name);
3740            if (wl == null) {
3741                if (mWakelockStats.size() > MAX_WAKELOCKS_PER_UID) {
3742                    name = BATCHED_WAKELOCK_NAME;
3743                    wl = mWakelockStats.get(name);
3744                }
3745                if (wl == null) {
3746                    wl = new Wakelock();
3747                    mWakelockStats.put(name, wl);
3748                }
3749            }
3750            StopwatchTimer t = null;
3751            switch (type) {
3752                case WAKE_TYPE_PARTIAL:
3753                    t = wl.mTimerPartial;
3754                    if (t == null) {
3755                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
3756                                mPartialTimers, mUnpluggables);
3757                        wl.mTimerPartial = t;
3758                    }
3759                    return t;
3760                case WAKE_TYPE_FULL:
3761                    t = wl.mTimerFull;
3762                    if (t == null) {
3763                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
3764                                mFullTimers, mUnpluggables);
3765                        wl.mTimerFull = t;
3766                    }
3767                    return t;
3768                case WAKE_TYPE_WINDOW:
3769                    t = wl.mTimerWindow;
3770                    if (t == null) {
3771                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
3772                                mWindowTimers, mUnpluggables);
3773                        wl.mTimerWindow = t;
3774                    }
3775                    return t;
3776                default:
3777                    throw new IllegalArgumentException("type=" + type);
3778            }
3779        }
3780
3781        public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
3782            Sensor se = mSensorStats.get(sensor);
3783            if (se == null) {
3784                if (!create) {
3785                    return null;
3786                }
3787                se = new Sensor(sensor);
3788                mSensorStats.put(sensor, se);
3789            }
3790            StopwatchTimer t = se.mTimer;
3791            if (t != null) {
3792                return t;
3793            }
3794            ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
3795            if (timers == null) {
3796                timers = new ArrayList<StopwatchTimer>();
3797                mSensorTimers.put(sensor, timers);
3798            }
3799            t = new StopwatchTimer(Uid.this, BatteryStats.SENSOR, timers, mUnpluggables);
3800            se.mTimer = t;
3801            return t;
3802        }
3803
3804        public void noteStartWakeLocked(int pid, String name, int type) {
3805            StopwatchTimer t = getWakeTimerLocked(name, type);
3806            if (t != null) {
3807                t.startRunningLocked(BatteryStatsImpl.this);
3808            }
3809            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
3810                Pid p = getPidStatsLocked(pid);
3811                if (p.mWakeStart == 0) {
3812                    p.mWakeStart = SystemClock.elapsedRealtime();
3813                }
3814            }
3815        }
3816
3817        public void noteStopWakeLocked(int pid, String name, int type) {
3818            StopwatchTimer t = getWakeTimerLocked(name, type);
3819            if (t != null) {
3820                t.stopRunningLocked(BatteryStatsImpl.this);
3821            }
3822            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
3823                Pid p = mPids.get(pid);
3824                if (p != null && p.mWakeStart != 0) {
3825                    p.mWakeSum += SystemClock.elapsedRealtime() - p.mWakeStart;
3826                    p.mWakeStart = 0;
3827                }
3828            }
3829        }
3830
3831        public void reportExcessiveWakeLocked(String proc, long overTime, long usedTime) {
3832            Proc p = getProcessStatsLocked(proc);
3833            if (p != null) {
3834                p.addExcessiveWake(overTime, usedTime);
3835            }
3836        }
3837
3838        public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) {
3839            Proc p = getProcessStatsLocked(proc);
3840            if (p != null) {
3841                p.addExcessiveCpu(overTime, usedTime);
3842            }
3843        }
3844
3845        public void noteStartSensor(int sensor) {
3846            StopwatchTimer t = getSensorTimerLocked(sensor, true);
3847            if (t != null) {
3848                t.startRunningLocked(BatteryStatsImpl.this);
3849            }
3850        }
3851
3852        public void noteStopSensor(int sensor) {
3853            // Don't create a timer if one doesn't already exist
3854            StopwatchTimer t = getSensorTimerLocked(sensor, false);
3855            if (t != null) {
3856                t.stopRunningLocked(BatteryStatsImpl.this);
3857            }
3858        }
3859
3860        public void noteStartGps() {
3861            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
3862            if (t != null) {
3863                t.startRunningLocked(BatteryStatsImpl.this);
3864            }
3865        }
3866
3867        public void noteStopGps() {
3868            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
3869            if (t != null) {
3870                t.stopRunningLocked(BatteryStatsImpl.this);
3871            }
3872        }
3873
3874        public BatteryStatsImpl getBatteryStats() {
3875            return BatteryStatsImpl.this;
3876        }
3877    }
3878
3879    public BatteryStatsImpl(String filename) {
3880        mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
3881        mHandler = new MyHandler();
3882        mStartCount++;
3883        mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables);
3884        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3885            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mUnpluggables);
3886        }
3887        mInputEventCounter = new Counter(mUnpluggables);
3888        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables);
3889        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
3890            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null, mUnpluggables);
3891        }
3892        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables);
3893        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3894            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null, mUnpluggables);
3895        }
3896        mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables);
3897        mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
3898        mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables);
3899        mAudioOnTimer = new StopwatchTimer(null, -6, null, mUnpluggables);
3900        mVideoOnTimer = new StopwatchTimer(null, -7, null, mUnpluggables);
3901        mOnBattery = mOnBatteryInternal = false;
3902        initTimes();
3903        mTrackBatteryPastUptime = 0;
3904        mTrackBatteryPastRealtime = 0;
3905        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
3906        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
3907        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
3908        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
3909        mDischargeStartLevel = 0;
3910        mDischargeUnplugLevel = 0;
3911        mDischargeCurrentLevel = 0;
3912        initDischarge();
3913    }
3914
3915    public BatteryStatsImpl(Parcel p) {
3916        mFile = null;
3917        mHandler = null;
3918        readFromParcel(p);
3919    }
3920
3921    public void setCallback(BatteryCallback cb) {
3922        mCallback = cb;
3923    }
3924
3925    public void setNumSpeedSteps(int steps) {
3926        if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
3927    }
3928
3929    public void setRadioScanningTimeout(long timeout) {
3930        if (mPhoneSignalScanningTimer != null) {
3931            mPhoneSignalScanningTimer.setTimeout(timeout);
3932        }
3933    }
3934
3935    private HistoryItem mHistoryIterator;
3936
3937    public boolean startIteratingHistoryLocked() {
3938        return (mHistoryIterator = mHistory) != null;
3939    }
3940
3941    public boolean getNextHistoryLocked(HistoryItem out) {
3942        HistoryItem cur = mHistoryIterator;
3943        if (cur == null) {
3944            return false;
3945        }
3946        out.setTo(cur);
3947        mHistoryIterator = cur.next;
3948        return true;
3949    }
3950
3951    @Override
3952    public HistoryItem getHistory() {
3953        return mHistory;
3954    }
3955
3956    @Override
3957    public long getHistoryBaseTime() {
3958        return mHistoryBaseTime;
3959    }
3960
3961    @Override
3962    public int getStartCount() {
3963        return mStartCount;
3964    }
3965
3966    public boolean isOnBattery() {
3967        return mOnBattery;
3968    }
3969
3970    public boolean isScreenOn() {
3971        return mScreenOn;
3972    }
3973
3974    void initTimes() {
3975        mBatteryRealtime = mTrackBatteryPastUptime = 0;
3976        mBatteryUptime = mTrackBatteryPastRealtime = 0;
3977        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
3978        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
3979        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
3980        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
3981    }
3982
3983    void initDischarge() {
3984        mLowDischargeAmountSinceCharge = 0;
3985        mHighDischargeAmountSinceCharge = 0;
3986        mDischargeAmountScreenOn = 0;
3987        mDischargeAmountScreenOnSinceCharge = 0;
3988        mDischargeAmountScreenOff = 0;
3989        mDischargeAmountScreenOffSinceCharge = 0;
3990    }
3991
3992    public void resetAllStatsLocked() {
3993        mStartCount = 0;
3994        initTimes();
3995        mScreenOnTimer.reset(this, false);
3996        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3997            mScreenBrightnessTimer[i].reset(this, false);
3998        }
3999        mInputEventCounter.reset(false);
4000        mPhoneOnTimer.reset(this, false);
4001        mAudioOnTimer.reset(this, false);
4002        mVideoOnTimer.reset(this, false);
4003        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
4004            mPhoneSignalStrengthsTimer[i].reset(this, false);
4005        }
4006        mPhoneSignalScanningTimer.reset(this, false);
4007        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4008            mPhoneDataConnectionsTimer[i].reset(this, false);
4009        }
4010        mWifiOnTimer.reset(this, false);
4011        mGlobalWifiRunningTimer.reset(this, false);
4012        mBluetoothOnTimer.reset(this, false);
4013
4014        for (int i=0; i<mUidStats.size(); i++) {
4015            if (mUidStats.valueAt(i).reset()) {
4016                mUidStats.remove(mUidStats.keyAt(i));
4017                i--;
4018            }
4019        }
4020
4021        if (mKernelWakelockStats.size() > 0) {
4022            for (SamplingTimer timer : mKernelWakelockStats.values()) {
4023                mUnpluggables.remove(timer);
4024            }
4025            mKernelWakelockStats.clear();
4026        }
4027
4028        initDischarge();
4029
4030        clearHistoryLocked();
4031    }
4032
4033    void updateDischargeScreenLevels(boolean oldScreenOn, boolean newScreenOn) {
4034        if (oldScreenOn) {
4035            int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
4036            if (diff > 0) {
4037                mDischargeAmountScreenOn += diff;
4038                mDischargeAmountScreenOnSinceCharge += diff;
4039            }
4040        } else {
4041            int diff = mDischargeScreenOffUnplugLevel - mDischargeCurrentLevel;
4042            if (diff > 0) {
4043                mDischargeAmountScreenOff += diff;
4044                mDischargeAmountScreenOffSinceCharge += diff;
4045            }
4046        }
4047        if (newScreenOn) {
4048            mDischargeScreenOnUnplugLevel = mDischargeCurrentLevel;
4049            mDischargeScreenOffUnplugLevel = 0;
4050        } else {
4051            mDischargeScreenOnUnplugLevel = 0;
4052            mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
4053        }
4054    }
4055
4056    void setOnBattery(boolean onBattery, int oldStatus, int level) {
4057        synchronized(this) {
4058            boolean doWrite = false;
4059            Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
4060            m.arg1 = onBattery ? 1 : 0;
4061            mHandler.sendMessage(m);
4062            mOnBattery = mOnBatteryInternal = onBattery;
4063
4064            long uptime = SystemClock.uptimeMillis() * 1000;
4065            long mSecRealtime = SystemClock.elapsedRealtime();
4066            long realtime = mSecRealtime * 1000;
4067            if (onBattery) {
4068                // We will reset our status if we are unplugging after the
4069                // battery was last full, or the level is at 100, or
4070                // we have gone through a significant charge (from a very low
4071                // level to a now very high level).
4072                if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
4073                        || level >= 90
4074                        || (mDischargeCurrentLevel < 20 && level >= 80)) {
4075                    doWrite = true;
4076                    resetAllStatsLocked();
4077                    mDischargeStartLevel = level;
4078                }
4079                updateKernelWakelocksLocked();
4080                mHistoryCur.batteryLevel = (byte)level;
4081                mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4082                if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
4083                        + Integer.toHexString(mHistoryCur.states));
4084                addHistoryRecordLocked(mSecRealtime);
4085                mTrackBatteryUptimeStart = uptime;
4086                mTrackBatteryRealtimeStart = realtime;
4087                mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
4088                mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
4089                mDischargeCurrentLevel = mDischargeUnplugLevel = level;
4090                if (mScreenOn) {
4091                    mDischargeScreenOnUnplugLevel = level;
4092                    mDischargeScreenOffUnplugLevel = 0;
4093                } else {
4094                    mDischargeScreenOnUnplugLevel = 0;
4095                    mDischargeScreenOffUnplugLevel = level;
4096                }
4097                mDischargeAmountScreenOn = 0;
4098                mDischargeAmountScreenOff = 0;
4099                doUnplugLocked(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
4100            } else {
4101                updateKernelWakelocksLocked();
4102                mHistoryCur.batteryLevel = (byte)level;
4103                mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4104                if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
4105                        + Integer.toHexString(mHistoryCur.states));
4106                addHistoryRecordLocked(mSecRealtime);
4107                mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
4108                mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
4109                mDischargeCurrentLevel = level;
4110                if (level < mDischargeUnplugLevel) {
4111                    mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
4112                    mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
4113                }
4114                updateDischargeScreenLevels(mScreenOn, mScreenOn);
4115                doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
4116            }
4117            if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
4118                if (mFile != null) {
4119                    writeAsyncLocked();
4120                }
4121            }
4122        }
4123    }
4124
4125    // This should probably be exposed in the API, though it's not critical
4126    private static final int BATTERY_PLUGGED_NONE = 0;
4127
4128    public void setBatteryState(int status, int health, int plugType, int level,
4129            int temp, int volt) {
4130        boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
4131        int oldStatus = mHistoryCur.batteryStatus;
4132        if (!mHaveBatteryLevel) {
4133            mHaveBatteryLevel = true;
4134            // We start out assuming that the device is plugged in (not
4135            // on battery).  If our first report is now that we are indeed
4136            // plugged in, then twiddle our state to correctly reflect that
4137            // since we won't be going through the full setOnBattery().
4138            if (onBattery == mOnBattery) {
4139                if (onBattery) {
4140                    mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4141                } else {
4142                    mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4143                }
4144            }
4145            oldStatus = status;
4146        }
4147        if (onBattery) {
4148            mDischargeCurrentLevel = level;
4149            mRecordingHistory = true;
4150        }
4151        if (onBattery != mOnBattery) {
4152            mHistoryCur.batteryLevel = (byte)level;
4153            mHistoryCur.batteryStatus = (byte)status;
4154            mHistoryCur.batteryHealth = (byte)health;
4155            mHistoryCur.batteryPlugType = (byte)plugType;
4156            mHistoryCur.batteryTemperature = (char)temp;
4157            mHistoryCur.batteryVoltage = (char)volt;
4158            setOnBattery(onBattery, oldStatus, level);
4159        } else {
4160            boolean changed = false;
4161            if (mHistoryCur.batteryLevel != level) {
4162                mHistoryCur.batteryLevel = (byte)level;
4163                changed = true;
4164            }
4165            if (mHistoryCur.batteryStatus != status) {
4166                mHistoryCur.batteryStatus = (byte)status;
4167                changed = true;
4168            }
4169            if (mHistoryCur.batteryHealth != health) {
4170                mHistoryCur.batteryHealth = (byte)health;
4171                changed = true;
4172            }
4173            if (mHistoryCur.batteryPlugType != plugType) {
4174                mHistoryCur.batteryPlugType = (byte)plugType;
4175                changed = true;
4176            }
4177            if (temp >= (mHistoryCur.batteryTemperature+10)
4178                    || temp <= (mHistoryCur.batteryTemperature-10)) {
4179                mHistoryCur.batteryTemperature = (char)temp;
4180                changed = true;
4181            }
4182            if (volt > (mHistoryCur.batteryVoltage+20)
4183                    || volt < (mHistoryCur.batteryVoltage-20)) {
4184                mHistoryCur.batteryVoltage = (char)volt;
4185                changed = true;
4186            }
4187            if (changed) {
4188                addHistoryRecordLocked(SystemClock.elapsedRealtime());
4189            }
4190        }
4191        if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
4192            // We don't record history while we are plugged in and fully charged.
4193            // The next time we are unplugged, history will be cleared.
4194            mRecordingHistory = false;
4195        }
4196    }
4197
4198    public void updateKernelWakelocksLocked() {
4199        Map<String, KernelWakelockStats> m = readKernelWakelockStats();
4200
4201        if (m == null) {
4202            // Not crashing might make board bringup easier.
4203            Slog.w(TAG, "Couldn't get kernel wake lock stats");
4204            return;
4205        }
4206
4207        for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
4208            String name = ent.getKey();
4209            KernelWakelockStats kws = ent.getValue();
4210
4211            SamplingTimer kwlt = mKernelWakelockStats.get(name);
4212            if (kwlt == null) {
4213                kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
4214                        true /* track reported values */);
4215                mKernelWakelockStats.put(name, kwlt);
4216            }
4217            kwlt.updateCurrentReportedCount(kws.mCount);
4218            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
4219            kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
4220        }
4221
4222        if (m.size() != mKernelWakelockStats.size()) {
4223            // Set timers to stale if they didn't appear in /proc/wakelocks this time.
4224            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
4225                SamplingTimer st = ent.getValue();
4226                if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
4227                    st.setStale();
4228                }
4229            }
4230        }
4231    }
4232
4233    public long getAwakeTimeBattery() {
4234        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
4235    }
4236
4237    public long getAwakeTimePlugged() {
4238        return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
4239    }
4240
4241    @Override
4242    public long computeUptime(long curTime, int which) {
4243        switch (which) {
4244            case STATS_SINCE_CHARGED: return mUptime + (curTime-mUptimeStart);
4245            case STATS_LAST: return mLastUptime;
4246            case STATS_CURRENT: return (curTime-mUptimeStart);
4247            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
4248        }
4249        return 0;
4250    }
4251
4252    @Override
4253    public long computeRealtime(long curTime, int which) {
4254        switch (which) {
4255            case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
4256            case STATS_LAST: return mLastRealtime;
4257            case STATS_CURRENT: return (curTime-mRealtimeStart);
4258            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
4259        }
4260        return 0;
4261    }
4262
4263    @Override
4264    public long computeBatteryUptime(long curTime, int which) {
4265        switch (which) {
4266            case STATS_SINCE_CHARGED:
4267                return mBatteryUptime + getBatteryUptime(curTime);
4268            case STATS_LAST:
4269                return mBatteryLastUptime;
4270            case STATS_CURRENT:
4271                return getBatteryUptime(curTime);
4272            case STATS_SINCE_UNPLUGGED:
4273                return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
4274        }
4275        return 0;
4276    }
4277
4278    @Override
4279    public long computeBatteryRealtime(long curTime, int which) {
4280        switch (which) {
4281            case STATS_SINCE_CHARGED:
4282                return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
4283            case STATS_LAST:
4284                return mBatteryLastRealtime;
4285            case STATS_CURRENT:
4286                return getBatteryRealtimeLocked(curTime);
4287            case STATS_SINCE_UNPLUGGED:
4288                return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
4289        }
4290        return 0;
4291    }
4292
4293    long getBatteryUptimeLocked(long curTime) {
4294        long time = mTrackBatteryPastUptime;
4295        if (mOnBatteryInternal) {
4296            time += curTime - mTrackBatteryUptimeStart;
4297        }
4298        return time;
4299    }
4300
4301    long getBatteryUptimeLocked() {
4302        return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
4303    }
4304
4305    @Override
4306    public long getBatteryUptime(long curTime) {
4307        return getBatteryUptimeLocked(curTime);
4308    }
4309
4310    long getBatteryRealtimeLocked(long curTime) {
4311        long time = mTrackBatteryPastRealtime;
4312        if (mOnBatteryInternal) {
4313            time += curTime - mTrackBatteryRealtimeStart;
4314        }
4315        return time;
4316    }
4317
4318    @Override
4319    public long getBatteryRealtime(long curTime) {
4320        return getBatteryRealtimeLocked(curTime);
4321    }
4322
4323    private long getTcpBytes(long current, long[] dataBytes, int which) {
4324        if (which == STATS_LAST) {
4325            return dataBytes[STATS_LAST];
4326        } else {
4327            if (which == STATS_SINCE_UNPLUGGED) {
4328                if (dataBytes[STATS_SINCE_UNPLUGGED] < 0) {
4329                    return dataBytes[STATS_LAST];
4330                } else {
4331                    return current - dataBytes[STATS_SINCE_UNPLUGGED];
4332                }
4333            } else if (which == STATS_SINCE_CHARGED) {
4334                return (current - dataBytes[STATS_CURRENT]) + dataBytes[STATS_SINCE_CHARGED];
4335            }
4336            return current - dataBytes[STATS_CURRENT];
4337        }
4338    }
4339
4340    /** Only STATS_UNPLUGGED works properly */
4341    public long getMobileTcpBytesSent(int which) {
4342        return getTcpBytes(TrafficStats.getMobileTxBytes(), mMobileDataTx, which);
4343    }
4344
4345    /** Only STATS_UNPLUGGED works properly */
4346    public long getMobileTcpBytesReceived(int which) {
4347        return getTcpBytes(TrafficStats.getMobileRxBytes(), mMobileDataRx, which);
4348    }
4349
4350    /** Only STATS_UNPLUGGED works properly */
4351    public long getTotalTcpBytesSent(int which) {
4352        return getTcpBytes(TrafficStats.getTotalTxBytes(), mTotalDataTx, which);
4353    }
4354
4355    /** Only STATS_UNPLUGGED works properly */
4356    public long getTotalTcpBytesReceived(int which) {
4357        return getTcpBytes(TrafficStats.getTotalRxBytes(), mTotalDataRx, which);
4358    }
4359
4360    @Override
4361    public int getDischargeStartLevel() {
4362        synchronized(this) {
4363            return getDischargeStartLevelLocked();
4364        }
4365    }
4366
4367    public int getDischargeStartLevelLocked() {
4368            return mDischargeUnplugLevel;
4369    }
4370
4371    @Override
4372    public int getDischargeCurrentLevel() {
4373        synchronized(this) {
4374            return getDischargeCurrentLevelLocked();
4375        }
4376    }
4377
4378    public int getDischargeCurrentLevelLocked() {
4379        return mDischargeCurrentLevel;
4380    }
4381
4382    @Override
4383    public int getLowDischargeAmountSinceCharge() {
4384        synchronized(this) {
4385            int val = mLowDischargeAmountSinceCharge;
4386            if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
4387                val += mDischargeUnplugLevel-mDischargeCurrentLevel-1;
4388            }
4389            return val;
4390        }
4391    }
4392
4393    @Override
4394    public int getHighDischargeAmountSinceCharge() {
4395        synchronized(this) {
4396            int val = mHighDischargeAmountSinceCharge;
4397            if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
4398                val += mDischargeUnplugLevel-mDischargeCurrentLevel;
4399            }
4400            return val;
4401        }
4402    }
4403
4404    public int getDischargeAmountScreenOn() {
4405        synchronized(this) {
4406            int val = mDischargeAmountScreenOn;
4407            if (mOnBattery && mScreenOn
4408                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
4409                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
4410            }
4411            return val;
4412        }
4413    }
4414
4415    public int getDischargeAmountScreenOnSinceCharge() {
4416        synchronized(this) {
4417            int val = mDischargeAmountScreenOnSinceCharge;
4418            if (mOnBattery && mScreenOn
4419                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
4420                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
4421            }
4422            return val;
4423        }
4424    }
4425
4426    public int getDischargeAmountScreenOff() {
4427        synchronized(this) {
4428            int val = mDischargeAmountScreenOff;
4429            if (mOnBattery && !mScreenOn
4430                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
4431                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
4432            }
4433            return val;
4434        }
4435    }
4436
4437    public int getDischargeAmountScreenOffSinceCharge() {
4438        synchronized(this) {
4439            int val = mDischargeAmountScreenOffSinceCharge;
4440            if (mOnBattery && !mScreenOn
4441                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
4442                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
4443            }
4444            return val;
4445        }
4446    }
4447
4448    @Override
4449    public int getCpuSpeedSteps() {
4450        return sNumSpeedSteps;
4451    }
4452
4453    /**
4454     * Retrieve the statistics object for a particular uid, creating if needed.
4455     */
4456    public Uid getUidStatsLocked(int uid) {
4457        Uid u = mUidStats.get(uid);
4458        if (u == null) {
4459            u = new Uid(uid);
4460            mUidStats.put(uid, u);
4461        }
4462        return u;
4463    }
4464
4465    /**
4466     * Remove the statistics object for a particular uid.
4467     */
4468    public void removeUidStatsLocked(int uid) {
4469        mUidStats.remove(uid);
4470    }
4471
4472    /**
4473     * Retrieve the statistics object for a particular process, creating
4474     * if needed.
4475     */
4476    public Uid.Proc getProcessStatsLocked(int uid, String name) {
4477        Uid u = getUidStatsLocked(uid);
4478        return u.getProcessStatsLocked(name);
4479    }
4480
4481    /**
4482     * Retrieve the statistics object for a particular process, given
4483     * the name of the process.
4484     * @param name process name
4485     * @return the statistics object for the process
4486     */
4487    public Uid.Proc getProcessStatsLocked(String name, int pid) {
4488        int uid;
4489        if (mUidCache.containsKey(name)) {
4490            uid = mUidCache.get(name);
4491        } else {
4492            uid = Process.getUidForPid(pid);
4493            mUidCache.put(name, uid);
4494        }
4495        Uid u = getUidStatsLocked(uid);
4496        return u.getProcessStatsLocked(name);
4497    }
4498
4499    /**
4500     * Retrieve the statistics object for a particular process, creating
4501     * if needed.
4502     */
4503    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
4504        Uid u = getUidStatsLocked(uid);
4505        return u.getPackageStatsLocked(pkg);
4506    }
4507
4508    /**
4509     * Retrieve the statistics object for a particular service, creating
4510     * if needed.
4511     */
4512    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
4513        Uid u = getUidStatsLocked(uid);
4514        return u.getServiceStatsLocked(pkg, name);
4515    }
4516
4517    /**
4518     * Massage data to distribute any reasonable work down to more specific
4519     * owners.  Must only be called on a dead BatteryStats object!
4520     */
4521    public void distributeWorkLocked(int which) {
4522        // Aggregate all CPU time associated with WIFI.
4523        Uid wifiUid = mUidStats.get(Process.WIFI_UID);
4524        if (wifiUid != null) {
4525            long uSecTime = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
4526            for (Uid.Proc proc : wifiUid.mProcessStats.values()) {
4527                long totalRunningTime = getGlobalWifiRunningTime(uSecTime, which);
4528                for (int i=0; i<mUidStats.size(); i++) {
4529                    Uid uid = mUidStats.valueAt(i);
4530                    if (uid.mUid != Process.WIFI_UID) {
4531                        long uidRunningTime = uid.getWifiRunningTime(uSecTime, which);
4532                        if (uidRunningTime > 0) {
4533                            Uid.Proc uidProc = uid.getProcessStatsLocked("*wifi*");
4534                            long time = proc.getUserTime(which);
4535                            time = (time*uidRunningTime)/totalRunningTime;
4536                            uidProc.mUserTime += time;
4537                            proc.mUserTime -= time;
4538                            time = proc.getSystemTime(which);
4539                            time = (time*uidRunningTime)/totalRunningTime;
4540                            uidProc.mSystemTime += time;
4541                            proc.mSystemTime -= time;
4542                            time = proc.getForegroundTime(which);
4543                            time = (time*uidRunningTime)/totalRunningTime;
4544                            uidProc.mForegroundTime += time;
4545                            proc.mForegroundTime -= time;
4546                            for (int sb=0; sb<proc.mSpeedBins.length; sb++) {
4547                                SamplingCounter sc = proc.mSpeedBins[sb];
4548                                if (sc != null) {
4549                                    time = sc.getCountLocked(which);
4550                                    time = (time*uidRunningTime)/totalRunningTime;
4551                                    SamplingCounter uidSc = uidProc.mSpeedBins[sb];
4552                                    if (uidSc == null) {
4553                                        uidSc = new SamplingCounter(mUnpluggables);
4554                                        uidProc.mSpeedBins[sb] = uidSc;
4555                                    }
4556                                    uidSc.mCount.addAndGet((int)time);
4557                                    sc.mCount.addAndGet((int)-time);
4558                                }
4559                            }
4560                            totalRunningTime -= uidRunningTime;
4561                        }
4562                    }
4563                }
4564            }
4565        }
4566    }
4567
4568    public void shutdownLocked() {
4569        writeSyncLocked();
4570        mShuttingDown = true;
4571    }
4572
4573    Parcel mPendingWrite = null;
4574    final ReentrantLock mWriteLock = new ReentrantLock();
4575
4576    public void writeAsyncLocked() {
4577        writeLocked(false);
4578    }
4579
4580    public void writeSyncLocked() {
4581        writeLocked(true);
4582    }
4583
4584    void writeLocked(boolean sync) {
4585        if (mFile == null) {
4586            Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
4587            return;
4588        }
4589
4590        if (mShuttingDown) {
4591            return;
4592        }
4593
4594        Parcel out = Parcel.obtain();
4595        writeSummaryToParcel(out);
4596        mLastWriteTime = SystemClock.elapsedRealtime();
4597
4598        if (mPendingWrite != null) {
4599            mPendingWrite.recycle();
4600        }
4601        mPendingWrite = out;
4602
4603        if (sync) {
4604            commitPendingDataToDisk();
4605        } else {
4606            Thread thr = new Thread("BatteryStats-Write") {
4607                @Override
4608                public void run() {
4609                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
4610                    commitPendingDataToDisk();
4611                }
4612            };
4613            thr.start();
4614        }
4615    }
4616
4617    public void commitPendingDataToDisk() {
4618        final Parcel next;
4619        synchronized (this) {
4620            next = mPendingWrite;
4621            mPendingWrite = null;
4622            if (next == null) {
4623                return;
4624            }
4625
4626            mWriteLock.lock();
4627        }
4628
4629        try {
4630            FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
4631            stream.write(next.marshall());
4632            stream.flush();
4633            FileUtils.sync(stream);
4634            stream.close();
4635            mFile.commit();
4636        } catch (IOException e) {
4637            Slog.w("BatteryStats", "Error writing battery statistics", e);
4638            mFile.rollback();
4639        } finally {
4640            next.recycle();
4641            mWriteLock.unlock();
4642        }
4643    }
4644
4645    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
4646        int pos = 0;
4647        int avail = stream.available();
4648        byte[] data = new byte[avail];
4649        while (true) {
4650            int amt = stream.read(data, pos, data.length-pos);
4651            //Log.i("foo", "Read " + amt + " bytes at " + pos
4652            //        + " of avail " + data.length);
4653            if (amt <= 0) {
4654                //Log.i("foo", "**** FINISHED READING: pos=" + pos
4655                //        + " len=" + data.length);
4656                return data;
4657            }
4658            pos += amt;
4659            avail = stream.available();
4660            if (avail > data.length-pos) {
4661                byte[] newData = new byte[pos+avail];
4662                System.arraycopy(data, 0, newData, 0, pos);
4663                data = newData;
4664            }
4665        }
4666    }
4667
4668    public void readLocked() {
4669        if (mFile == null) {
4670            Slog.w("BatteryStats", "readLocked: no file associated with this instance");
4671            return;
4672        }
4673
4674        mUidStats.clear();
4675
4676        try {
4677            File file = mFile.chooseForRead();
4678            if (!file.exists()) {
4679                return;
4680            }
4681            FileInputStream stream = new FileInputStream(file);
4682
4683            byte[] raw = readFully(stream);
4684            Parcel in = Parcel.obtain();
4685            in.unmarshall(raw, 0, raw.length);
4686            in.setDataPosition(0);
4687            stream.close();
4688
4689            readSummaryFromParcel(in);
4690        } catch(java.io.IOException e) {
4691            Slog.e("BatteryStats", "Error reading battery statistics", e);
4692        }
4693
4694        addHistoryRecordLocked(SystemClock.elapsedRealtime(), HistoryItem.CMD_START);
4695    }
4696
4697    public int describeContents() {
4698        return 0;
4699    }
4700
4701    void readHistory(Parcel in) {
4702        mHistory = mHistoryEnd = mHistoryCache = null;
4703        mHistoryBaseTime = 0;
4704        long time;
4705        while ((time=in.readLong()) >= 0) {
4706            HistoryItem rec = new HistoryItem(time, in);
4707            addHistoryRecordLocked(rec);
4708            if (rec.time > mHistoryBaseTime) {
4709                mHistoryBaseTime = rec.time;
4710            }
4711        }
4712
4713        long oldnow = SystemClock.elapsedRealtime() - (5*60*100);
4714        if (oldnow > 0) {
4715            // If the system process has restarted, but not the entire
4716            // system, then the mHistoryBaseTime already accounts for
4717            // much of the elapsed time.  We thus want to adjust it back,
4718            // to avoid large gaps in the data.  We determine we are
4719            // in this case by arbitrarily saying it is so if at this
4720            // point in boot the elapsed time is already more than 5 seconds.
4721            mHistoryBaseTime -= oldnow;
4722        }
4723    }
4724
4725    void writeHistory(Parcel out) {
4726        HistoryItem rec = mHistory;
4727        while (rec != null) {
4728            if (rec.time >= 0) rec.writeToParcel(out, 0);
4729            rec = rec.next;
4730        }
4731        out.writeLong(-1);
4732    }
4733
4734    private void readSummaryFromParcel(Parcel in) {
4735        final int version = in.readInt();
4736        if (version != VERSION) {
4737            Slog.w("BatteryStats", "readFromParcel: version got " + version
4738                + ", expected " + VERSION + "; erasing old stats");
4739            return;
4740        }
4741
4742        readHistory(in);
4743
4744        mStartCount = in.readInt();
4745        mBatteryUptime = in.readLong();
4746        mBatteryRealtime = in.readLong();
4747        mUptime = in.readLong();
4748        mRealtime = in.readLong();
4749        mDischargeUnplugLevel = in.readInt();
4750        mDischargeCurrentLevel = in.readInt();
4751        mLowDischargeAmountSinceCharge = in.readInt();
4752        mHighDischargeAmountSinceCharge = in.readInt();
4753        mDischargeAmountScreenOnSinceCharge = in.readInt();
4754        mDischargeAmountScreenOffSinceCharge = in.readInt();
4755
4756        mStartCount++;
4757
4758        mScreenOn = false;
4759        mScreenOnTimer.readSummaryFromParcelLocked(in);
4760        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4761            mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
4762        }
4763        mInputEventCounter.readSummaryFromParcelLocked(in);
4764        mPhoneOn = false;
4765        mPhoneOnTimer.readSummaryFromParcelLocked(in);
4766        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
4767            mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
4768        }
4769        mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
4770        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4771            mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
4772        }
4773        mWifiOn = false;
4774        mWifiOnTimer.readSummaryFromParcelLocked(in);
4775        mGlobalWifiRunning = false;
4776        mGlobalWifiRunningTimer.readSummaryFromParcelLocked(in);
4777        mBluetoothOn = false;
4778        mBluetoothOnTimer.readSummaryFromParcelLocked(in);
4779
4780        int NKW = in.readInt();
4781        if (NKW > 10000) {
4782            Slog.w(TAG, "File corrupt: too many kernel wake locks " + NKW);
4783            return;
4784        }
4785        for (int ikw = 0; ikw < NKW; ikw++) {
4786            if (in.readInt() != 0) {
4787                String kwltName = in.readString();
4788                getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
4789            }
4790        }
4791
4792        sNumSpeedSteps = in.readInt();
4793
4794        final int NU = in.readInt();
4795        if (NU > 10000) {
4796            Slog.w(TAG, "File corrupt: too many uids " + NU);
4797            return;
4798        }
4799        for (int iu = 0; iu < NU; iu++) {
4800            int uid = in.readInt();
4801            Uid u = new Uid(uid);
4802            mUidStats.put(uid, u);
4803
4804            u.mWifiRunning = false;
4805            if (in.readInt() != 0) {
4806                u.mWifiRunningTimer.readSummaryFromParcelLocked(in);
4807            }
4808            u.mFullWifiLockOut = false;
4809            if (in.readInt() != 0) {
4810                u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
4811            }
4812            u.mScanWifiLockOut = false;
4813            if (in.readInt() != 0) {
4814                u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
4815            }
4816            u.mWifiMulticastEnabled = false;
4817            if (in.readInt() != 0) {
4818                u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
4819            }
4820            u.mAudioTurnedOn = false;
4821            if (in.readInt() != 0) {
4822                u.mAudioTurnedOnTimer.readSummaryFromParcelLocked(in);
4823            }
4824            u.mVideoTurnedOn = false;
4825            if (in.readInt() != 0) {
4826                u.mVideoTurnedOnTimer.readSummaryFromParcelLocked(in);
4827            }
4828
4829            if (in.readInt() != 0) {
4830                if (u.mUserActivityCounters == null) {
4831                    u.initUserActivityLocked();
4832                }
4833                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
4834                    u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
4835                }
4836            }
4837
4838            int NW = in.readInt();
4839            if (NW > 100) {
4840                Slog.w(TAG, "File corrupt: too many wake locks " + NW);
4841                return;
4842            }
4843            for (int iw = 0; iw < NW; iw++) {
4844                String wlName = in.readString();
4845                if (in.readInt() != 0) {
4846                    u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
4847                }
4848                if (in.readInt() != 0) {
4849                    u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
4850                }
4851                if (in.readInt() != 0) {
4852                    u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
4853                }
4854            }
4855
4856            int NP = in.readInt();
4857            if (NP > 1000) {
4858                Slog.w(TAG, "File corrupt: too many sensors " + NP);
4859                return;
4860            }
4861            for (int is = 0; is < NP; is++) {
4862                int seNumber = in.readInt();
4863                if (in.readInt() != 0) {
4864                    u.getSensorTimerLocked(seNumber, true)
4865                            .readSummaryFromParcelLocked(in);
4866                }
4867            }
4868
4869            NP = in.readInt();
4870            if (NP > 1000) {
4871                Slog.w(TAG, "File corrupt: too many processes " + NP);
4872                return;
4873            }
4874            for (int ip = 0; ip < NP; ip++) {
4875                String procName = in.readString();
4876                Uid.Proc p = u.getProcessStatsLocked(procName);
4877                p.mUserTime = p.mLoadedUserTime = in.readLong();
4878                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
4879                p.mStarts = p.mLoadedStarts = in.readInt();
4880                int NSB = in.readInt();
4881                if (NSB > 100) {
4882                    Slog.w(TAG, "File corrupt: too many speed bins " + NSB);
4883                    return;
4884                }
4885                p.mSpeedBins = new SamplingCounter[NSB];
4886                for (int i=0; i<NSB; i++) {
4887                    if (in.readInt() != 0) {
4888                        p.mSpeedBins[i] = new SamplingCounter(mUnpluggables);
4889                        p.mSpeedBins[i].readSummaryFromParcelLocked(in);
4890                    }
4891                }
4892                if (!p.readExcessivePowerFromParcelLocked(in)) {
4893                    return;
4894                }
4895            }
4896
4897            NP = in.readInt();
4898            if (NP > 10000) {
4899                Slog.w(TAG, "File corrupt: too many packages " + NP);
4900                return;
4901            }
4902            for (int ip = 0; ip < NP; ip++) {
4903                String pkgName = in.readString();
4904                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
4905                p.mWakeups = p.mLoadedWakeups = in.readInt();
4906                final int NS = in.readInt();
4907                if (NS > 1000) {
4908                    Slog.w(TAG, "File corrupt: too many services " + NS);
4909                    return;
4910                }
4911                for (int is = 0; is < NS; is++) {
4912                    String servName = in.readString();
4913                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
4914                    s.mStartTime = s.mLoadedStartTime = in.readLong();
4915                    s.mStarts = s.mLoadedStarts = in.readInt();
4916                    s.mLaunches = s.mLoadedLaunches = in.readInt();
4917                }
4918            }
4919
4920            u.mLoadedTcpBytesReceived = in.readLong();
4921            u.mLoadedTcpBytesSent = in.readLong();
4922        }
4923    }
4924
4925    /**
4926     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
4927     * disk.  This format does not allow a lossless round-trip.
4928     *
4929     * @param out the Parcel to be written to.
4930     */
4931    public void writeSummaryToParcel(Parcel out) {
4932        final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
4933        final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
4934        final long NOW = getBatteryUptimeLocked(NOW_SYS);
4935        final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
4936
4937        out.writeInt(VERSION);
4938
4939        writeHistory(out);
4940
4941        out.writeInt(mStartCount);
4942        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_SINCE_CHARGED));
4943        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
4944        out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
4945        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
4946        out.writeInt(mDischargeUnplugLevel);
4947        out.writeInt(mDischargeCurrentLevel);
4948        out.writeInt(getLowDischargeAmountSinceCharge());
4949        out.writeInt(getHighDischargeAmountSinceCharge());
4950        out.writeInt(getDischargeAmountScreenOnSinceCharge());
4951        out.writeInt(getDischargeAmountScreenOffSinceCharge());
4952
4953        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4954        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4955            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
4956        }
4957        mInputEventCounter.writeSummaryFromParcelLocked(out);
4958        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4959        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
4960            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
4961        }
4962        mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4963        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4964            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
4965        }
4966        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4967        mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4968        mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4969
4970        out.writeInt(mKernelWakelockStats.size());
4971        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
4972            Timer kwlt = ent.getValue();
4973            if (kwlt != null) {
4974                out.writeInt(1);
4975                out.writeString(ent.getKey());
4976                ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
4977            } else {
4978                out.writeInt(0);
4979            }
4980        }
4981
4982        out.writeInt(sNumSpeedSteps);
4983        final int NU = mUidStats.size();
4984        out.writeInt(NU);
4985        for (int iu = 0; iu < NU; iu++) {
4986            out.writeInt(mUidStats.keyAt(iu));
4987            Uid u = mUidStats.valueAt(iu);
4988
4989            if (u.mWifiRunningTimer != null) {
4990                out.writeInt(1);
4991                u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4992            } else {
4993                out.writeInt(0);
4994            }
4995            if (u.mFullWifiLockTimer != null) {
4996                out.writeInt(1);
4997                u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4998            } else {
4999                out.writeInt(0);
5000            }
5001            if (u.mScanWifiLockTimer != null) {
5002                out.writeInt(1);
5003                u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5004            } else {
5005                out.writeInt(0);
5006            }
5007            if (u.mWifiMulticastTimer != null) {
5008                out.writeInt(1);
5009                u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5010            } else {
5011                out.writeInt(0);
5012            }
5013            if (u.mAudioTurnedOnTimer != null) {
5014                out.writeInt(1);
5015                u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5016            } else {
5017                out.writeInt(0);
5018            }
5019            if (u.mVideoTurnedOnTimer != null) {
5020                out.writeInt(1);
5021                u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5022            } else {
5023                out.writeInt(0);
5024            }
5025
5026            if (u.mUserActivityCounters == null) {
5027                out.writeInt(0);
5028            } else {
5029                out.writeInt(1);
5030                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
5031                    u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
5032                }
5033            }
5034
5035            int NW = u.mWakelockStats.size();
5036            out.writeInt(NW);
5037            if (NW > 0) {
5038                for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
5039                        : u.mWakelockStats.entrySet()) {
5040                    out.writeString(ent.getKey());
5041                    Uid.Wakelock wl = ent.getValue();
5042                    if (wl.mTimerFull != null) {
5043                        out.writeInt(1);
5044                        wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
5045                    } else {
5046                        out.writeInt(0);
5047                    }
5048                    if (wl.mTimerPartial != null) {
5049                        out.writeInt(1);
5050                        wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
5051                    } else {
5052                        out.writeInt(0);
5053                    }
5054                    if (wl.mTimerWindow != null) {
5055                        out.writeInt(1);
5056                        wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
5057                    } else {
5058                        out.writeInt(0);
5059                    }
5060                }
5061            }
5062
5063            int NSE = u.mSensorStats.size();
5064            out.writeInt(NSE);
5065            if (NSE > 0) {
5066                for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
5067                        : u.mSensorStats.entrySet()) {
5068                    out.writeInt(ent.getKey());
5069                    Uid.Sensor se = ent.getValue();
5070                    if (se.mTimer != null) {
5071                        out.writeInt(1);
5072                        se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5073                    } else {
5074                        out.writeInt(0);
5075                    }
5076                }
5077            }
5078
5079            int NP = u.mProcessStats.size();
5080            out.writeInt(NP);
5081            if (NP > 0) {
5082                for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
5083                    : u.mProcessStats.entrySet()) {
5084                    out.writeString(ent.getKey());
5085                    Uid.Proc ps = ent.getValue();
5086                    out.writeLong(ps.mUserTime);
5087                    out.writeLong(ps.mSystemTime);
5088                    out.writeInt(ps.mStarts);
5089                    final int N = ps.mSpeedBins.length;
5090                    out.writeInt(N);
5091                    for (int i=0; i<N; i++) {
5092                        if (ps.mSpeedBins[i] != null) {
5093                            out.writeInt(1);
5094                            ps.mSpeedBins[i].writeSummaryFromParcelLocked(out);
5095                        } else {
5096                            out.writeInt(0);
5097                        }
5098                    }
5099                    ps.writeExcessivePowerToParcelLocked(out);
5100                }
5101            }
5102
5103            NP = u.mPackageStats.size();
5104            out.writeInt(NP);
5105            if (NP > 0) {
5106                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
5107                    : u.mPackageStats.entrySet()) {
5108                    out.writeString(ent.getKey());
5109                    Uid.Pkg ps = ent.getValue();
5110                    out.writeInt(ps.mWakeups);
5111                    final int NS = ps.mServiceStats.size();
5112                    out.writeInt(NS);
5113                    if (NS > 0) {
5114                        for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
5115                                : ps.mServiceStats.entrySet()) {
5116                            out.writeString(sent.getKey());
5117                            BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
5118                            long time = ss.getStartTimeToNowLocked(NOW);
5119                            out.writeLong(time);
5120                            out.writeInt(ss.mStarts);
5121                            out.writeInt(ss.mLaunches);
5122                        }
5123                    }
5124                }
5125            }
5126
5127            out.writeLong(u.getTcpBytesReceived(STATS_SINCE_CHARGED));
5128            out.writeLong(u.getTcpBytesSent(STATS_SINCE_CHARGED));
5129        }
5130    }
5131
5132    public void readFromParcel(Parcel in) {
5133        readFromParcelLocked(in);
5134    }
5135
5136    void readFromParcelLocked(Parcel in) {
5137        int magic = in.readInt();
5138        if (magic != MAGIC) {
5139            throw new ParcelFormatException("Bad magic number");
5140        }
5141
5142        readHistory(in);
5143
5144        mStartCount = in.readInt();
5145        mBatteryUptime = in.readLong();
5146        mBatteryLastUptime = 0;
5147        mBatteryRealtime = in.readLong();
5148        mBatteryLastRealtime = 0;
5149        mScreenOn = false;
5150        mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables, in);
5151        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5152            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i,
5153                    null, mUnpluggables, in);
5154        }
5155        mInputEventCounter = new Counter(mUnpluggables, in);
5156        mPhoneOn = false;
5157        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5158        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5159            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
5160                    null, mUnpluggables, in);
5161        }
5162        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables, in);
5163        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5164            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
5165                    null, mUnpluggables, in);
5166        }
5167        mWifiOn = false;
5168        mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5169        mGlobalWifiRunning = false;
5170        mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5171        mBluetoothOn = false;
5172        mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5173        mUptime = in.readLong();
5174        mUptimeStart = in.readLong();
5175        mLastUptime = 0;
5176        mRealtime = in.readLong();
5177        mRealtimeStart = in.readLong();
5178        mLastRealtime = 0;
5179        mOnBattery = in.readInt() != 0;
5180        mOnBatteryInternal = false; // we are no longer really running.
5181        mTrackBatteryPastUptime = in.readLong();
5182        mTrackBatteryUptimeStart = in.readLong();
5183        mTrackBatteryPastRealtime = in.readLong();
5184        mTrackBatteryRealtimeStart = in.readLong();
5185        mUnpluggedBatteryUptime = in.readLong();
5186        mUnpluggedBatteryRealtime = in.readLong();
5187        mDischargeUnplugLevel = in.readInt();
5188        mDischargeCurrentLevel = in.readInt();
5189        mLowDischargeAmountSinceCharge = in.readInt();
5190        mHighDischargeAmountSinceCharge = in.readInt();
5191        mDischargeAmountScreenOn = in.readInt();
5192        mDischargeAmountScreenOnSinceCharge = in.readInt();
5193        mDischargeAmountScreenOff = in.readInt();
5194        mDischargeAmountScreenOffSinceCharge = in.readInt();
5195        mLastWriteTime = in.readLong();
5196
5197        mMobileDataRx[STATS_LAST] = in.readLong();
5198        mMobileDataRx[STATS_SINCE_UNPLUGGED] = -1;
5199        mMobileDataTx[STATS_LAST] = in.readLong();
5200        mMobileDataTx[STATS_SINCE_UNPLUGGED] = -1;
5201        mTotalDataRx[STATS_LAST] = in.readLong();
5202        mTotalDataRx[STATS_SINCE_UNPLUGGED] = -1;
5203        mTotalDataTx[STATS_LAST] = in.readLong();
5204        mTotalDataTx[STATS_SINCE_UNPLUGGED] = -1;
5205
5206        mRadioDataUptime = in.readLong();
5207        mRadioDataStart = -1;
5208
5209        mBluetoothPingCount = in.readInt();
5210        mBluetoothPingStart = -1;
5211
5212        mKernelWakelockStats.clear();
5213        int NKW = in.readInt();
5214        for (int ikw = 0; ikw < NKW; ikw++) {
5215            if (in.readInt() != 0) {
5216                String wakelockName = in.readString();
5217                in.readInt(); // Extra 0/1 written by Timer.writeTimerToParcel
5218                SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
5219                mKernelWakelockStats.put(wakelockName, kwlt);
5220            }
5221        }
5222
5223        mPartialTimers.clear();
5224        mFullTimers.clear();
5225        mWindowTimers.clear();
5226        mWifiRunningTimers.clear();
5227        mFullWifiLockTimers.clear();
5228        mScanWifiLockTimers.clear();
5229        mWifiMulticastTimers.clear();
5230
5231        sNumSpeedSteps = in.readInt();
5232
5233        int numUids = in.readInt();
5234        mUidStats.clear();
5235        for (int i = 0; i < numUids; i++) {
5236            int uid = in.readInt();
5237            Uid u = new Uid(uid);
5238            u.readFromParcelLocked(mUnpluggables, in);
5239            mUidStats.append(uid, u);
5240        }
5241    }
5242
5243    public void writeToParcel(Parcel out, int flags) {
5244        writeToParcelLocked(out, true, flags);
5245    }
5246
5247    public void writeToParcelWithoutUids(Parcel out, int flags) {
5248        writeToParcelLocked(out, false, flags);
5249    }
5250
5251    @SuppressWarnings("unused")
5252    void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
5253        final long uSecUptime = SystemClock.uptimeMillis() * 1000;
5254        final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
5255        final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
5256        final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
5257
5258        out.writeInt(MAGIC);
5259
5260        writeHistory(out);
5261
5262        out.writeInt(mStartCount);
5263        out.writeLong(mBatteryUptime);
5264        out.writeLong(mBatteryRealtime);
5265        mScreenOnTimer.writeToParcel(out, batteryRealtime);
5266        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5267            mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
5268        }
5269        mInputEventCounter.writeToParcel(out);
5270        mPhoneOnTimer.writeToParcel(out, batteryRealtime);
5271        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5272            mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
5273        }
5274        mPhoneSignalScanningTimer.writeToParcel(out, batteryRealtime);
5275        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5276            mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
5277        }
5278        mWifiOnTimer.writeToParcel(out, batteryRealtime);
5279        mGlobalWifiRunningTimer.writeToParcel(out, batteryRealtime);
5280        mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
5281        out.writeLong(mUptime);
5282        out.writeLong(mUptimeStart);
5283        out.writeLong(mRealtime);
5284        out.writeLong(mRealtimeStart);
5285        out.writeInt(mOnBattery ? 1 : 0);
5286        out.writeLong(batteryUptime);
5287        out.writeLong(mTrackBatteryUptimeStart);
5288        out.writeLong(batteryRealtime);
5289        out.writeLong(mTrackBatteryRealtimeStart);
5290        out.writeLong(mUnpluggedBatteryUptime);
5291        out.writeLong(mUnpluggedBatteryRealtime);
5292        out.writeInt(mDischargeUnplugLevel);
5293        out.writeInt(mDischargeCurrentLevel);
5294        out.writeInt(mLowDischargeAmountSinceCharge);
5295        out.writeInt(mHighDischargeAmountSinceCharge);
5296        out.writeInt(mDischargeAmountScreenOn);
5297        out.writeInt(mDischargeAmountScreenOnSinceCharge);
5298        out.writeInt(mDischargeAmountScreenOff);
5299        out.writeInt(mDischargeAmountScreenOffSinceCharge);
5300        out.writeLong(mLastWriteTime);
5301
5302        out.writeLong(getMobileTcpBytesReceived(STATS_SINCE_UNPLUGGED));
5303        out.writeLong(getMobileTcpBytesSent(STATS_SINCE_UNPLUGGED));
5304        out.writeLong(getTotalTcpBytesReceived(STATS_SINCE_UNPLUGGED));
5305        out.writeLong(getTotalTcpBytesSent(STATS_SINCE_UNPLUGGED));
5306
5307        // Write radio uptime for data
5308        out.writeLong(getRadioDataUptime());
5309
5310        out.writeInt(getBluetoothPingCount());
5311
5312        if (inclUids) {
5313            out.writeInt(mKernelWakelockStats.size());
5314            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
5315                SamplingTimer kwlt = ent.getValue();
5316                if (kwlt != null) {
5317                    out.writeInt(1);
5318                    out.writeString(ent.getKey());
5319                    Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
5320                } else {
5321                    out.writeInt(0);
5322                }
5323            }
5324        } else {
5325            out.writeInt(0);
5326        }
5327
5328        out.writeInt(sNumSpeedSteps);
5329
5330        if (inclUids) {
5331            int size = mUidStats.size();
5332            out.writeInt(size);
5333            for (int i = 0; i < size; i++) {
5334                out.writeInt(mUidStats.keyAt(i));
5335                Uid uid = mUidStats.valueAt(i);
5336
5337                uid.writeToParcelLocked(out, batteryRealtime);
5338            }
5339        } else {
5340            out.writeInt(0);
5341        }
5342    }
5343
5344    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
5345        new Parcelable.Creator<BatteryStatsImpl>() {
5346        public BatteryStatsImpl createFromParcel(Parcel in) {
5347            return new BatteryStatsImpl(in);
5348        }
5349
5350        public BatteryStatsImpl[] newArray(int size) {
5351            return new BatteryStatsImpl[size];
5352        }
5353    };
5354
5355    public void dumpLocked(PrintWriter pw) {
5356        if (DEBUG) {
5357            Printer pr = new PrintWriterPrinter(pw);
5358            pr.println("*** Screen timer:");
5359            mScreenOnTimer.logState(pr, "  ");
5360            for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5361                pr.println("*** Screen brightness #" + i + ":");
5362                mScreenBrightnessTimer[i].logState(pr, "  ");
5363            }
5364            pr.println("*** Input event counter:");
5365            mInputEventCounter.logState(pr, "  ");
5366            pr.println("*** Phone timer:");
5367            mPhoneOnTimer.logState(pr, "  ");
5368            for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5369                pr.println("*** Signal strength #" + i + ":");
5370                mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
5371            }
5372            pr.println("*** Signal scanning :");
5373            mPhoneSignalScanningTimer.logState(pr, "  ");
5374            for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5375                pr.println("*** Data connection type #" + i + ":");
5376                mPhoneDataConnectionsTimer[i].logState(pr, "  ");
5377            }
5378            pr.println("*** Wifi timer:");
5379            mWifiOnTimer.logState(pr, "  ");
5380            pr.println("*** WifiRunning timer:");
5381            mGlobalWifiRunningTimer.logState(pr, "  ");
5382            pr.println("*** Bluetooth timer:");
5383            mBluetoothOnTimer.logState(pr, "  ");
5384        }
5385        super.dumpLocked(pw);
5386    }
5387}
5388