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