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