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