BatteryStatsImpl.java revision 2098eadfba7aba5d667579222f0fac76d1235ff0
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.BatteryStats;
24import android.os.Parcel;
25import android.os.ParcelFormatException;
26import android.os.Parcelable;
27import android.os.Process;
28import android.os.SystemClock;
29import android.telephony.ServiceState;
30import android.telephony.SignalStrength;
31import android.telephony.TelephonyManager;
32import android.util.Log;
33import android.util.PrintWriterPrinter;
34import android.util.Printer;
35import android.util.Slog;
36import android.util.SparseArray;
37
38import java.io.BufferedReader;
39import java.io.File;
40import java.io.FileInputStream;
41import java.io.FileOutputStream;
42import java.io.FileReader;
43import java.io.IOException;
44import java.io.PrintWriter;
45import java.util.ArrayList;
46import java.util.HashMap;
47import java.util.Iterator;
48import java.util.Map;
49import java.util.concurrent.atomic.AtomicInteger;
50
51/**
52 * All information we are collecting about things that can happen that impact
53 * battery life.  All times are represented in microseconds except where indicated
54 * otherwise.
55 */
56public final class BatteryStatsImpl extends BatteryStats {
57    private static final String TAG = "BatteryStatsImpl";
58    private static final boolean DEBUG = false;
59
60    // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
61    private static final int MAGIC = 0xBA757475; // 'BATSTATS'
62
63    // Current on-disk Parcel version
64    private static final int VERSION = 43;
65
66    // The maximum number of names wakelocks we will keep track of
67    // per uid; once the limit is reached, we batch the remaining wakelocks
68    // in to one common name.
69    private static final int MAX_WAKELOCKS_PER_UID = 20;
70
71    private static final String BATCHED_WAKELOCK_NAME = "*overflow*";
72
73    private static int sNumSpeedSteps;
74
75    private final JournaledFile mFile;
76
77    /**
78     * The statistics we have collected organized by uids.
79     */
80    final SparseArray<BatteryStatsImpl.Uid> mUidStats =
81        new SparseArray<BatteryStatsImpl.Uid>();
82
83    // A set of pools of currently active timers.  When a timer is queried, we will divide the
84    // elapsed time by the number of active timers to arrive at that timer's share of the time.
85    // In order to do this, we must refresh each timer whenever the number of active timers
86    // changes.
87    final ArrayList<StopwatchTimer> mPartialTimers = new ArrayList<StopwatchTimer>();
88    final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<StopwatchTimer>();
89    final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<StopwatchTimer>();
90    final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers
91            = new SparseArray<ArrayList<StopwatchTimer>>();
92
93    // These are the objects that will want to do something when the device
94    // is unplugged from power.
95    final ArrayList<Unpluggable> mUnpluggables = new ArrayList<Unpluggable>();
96
97    int mStartCount;
98
99    long mBatteryUptime;
100    long mBatteryLastUptime;
101    long mBatteryRealtime;
102    long mBatteryLastRealtime;
103
104    long mUptime;
105    long mUptimeStart;
106    long mLastUptime;
107    long mRealtime;
108    long mRealtimeStart;
109    long mLastRealtime;
110
111    boolean mScreenOn;
112    StopwatchTimer mScreenOnTimer;
113
114    int mScreenBrightnessBin = -1;
115    final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
116
117    Counter mInputEventCounter;
118
119    boolean mPhoneOn;
120    StopwatchTimer mPhoneOnTimer;
121
122    boolean mAudioOn;
123    StopwatchTimer mAudioOnTimer;
124
125    boolean mVideoOn;
126    StopwatchTimer mVideoOnTimer;
127
128    int mPhoneSignalStrengthBin = -1;
129    final StopwatchTimer[] mPhoneSignalStrengthsTimer =
130            new StopwatchTimer[NUM_SIGNAL_STRENGTH_BINS];
131
132    StopwatchTimer mPhoneSignalScanningTimer;
133
134    int mPhoneDataConnectionType = -1;
135    final StopwatchTimer[] mPhoneDataConnectionsTimer =
136            new StopwatchTimer[NUM_DATA_CONNECTION_TYPES];
137
138    boolean mWifiOn;
139    StopwatchTimer mWifiOnTimer;
140    int mWifiOnUid = -1;
141
142    boolean mWifiRunning;
143    StopwatchTimer mWifiRunningTimer;
144
145    boolean mBluetoothOn;
146    StopwatchTimer mBluetoothOnTimer;
147
148    /** Bluetooth headset object */
149    BluetoothHeadset mBtHeadset;
150
151    /**
152     * These provide time bases that discount the time the device is plugged
153     * in to power.
154     */
155    boolean mOnBattery;
156    boolean mOnBatteryInternal;
157    long mTrackBatteryPastUptime;
158    long mTrackBatteryUptimeStart;
159    long mTrackBatteryPastRealtime;
160    long mTrackBatteryRealtimeStart;
161
162    long mUnpluggedBatteryUptime;
163    long mUnpluggedBatteryRealtime;
164
165    /*
166     * These keep track of battery levels (1-100) at the last plug event and the last unplug event.
167     */
168    int mDischargeStartLevel;
169    int mDischargeCurrentLevel;
170
171    long mLastWriteTime = 0; // Milliseconds
172
173    // Mobile data transferred while on battery
174    private long[] mMobileDataTx = new long[4];
175    private long[] mMobileDataRx = new long[4];
176    private long[] mTotalDataTx = new long[4];
177    private long[] mTotalDataRx = new long[4];
178
179    private long mRadioDataUptime;
180    private long mRadioDataStart;
181
182    private int mBluetoothPingCount;
183    private int mBluetoothPingStart = -1;
184
185    private int mPhoneServiceState = -1;
186
187    /*
188     * Holds a SamplingTimer associated with each kernel wakelock name being tracked.
189     */
190    private final HashMap<String, SamplingTimer> mKernelWakelockStats =
191            new HashMap<String, SamplingTimer>();
192
193    public Map<String, ? extends SamplingTimer> getKernelWakelockStats() {
194        return mKernelWakelockStats;
195    }
196
197    private static int sKernelWakelockUpdateVersion = 0;
198
199    private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
200        Process.PROC_TAB_TERM|Process.PROC_OUT_STRING,                // 0: name
201        Process.PROC_TAB_TERM|Process.PROC_OUT_LONG,                  // 1: count
202        Process.PROC_TAB_TERM,
203        Process.PROC_TAB_TERM,
204        Process.PROC_TAB_TERM,
205        Process.PROC_TAB_TERM|Process.PROC_OUT_LONG,                  // 5: totalTime
206    };
207
208    private final String[] mProcWakelocksName = new String[3];
209    private final long[] mProcWakelocksData = new long[3];
210
211    /*
212     * Used as a buffer for reading in data from /proc/wakelocks before it is processed and added
213     * to mKernelWakelockStats.
214     */
215    private final Map<String, KernelWakelockStats> mProcWakelockFileStats =
216            new HashMap<String, KernelWakelockStats>();
217
218    private HashMap<String, Integer> mUidCache = new HashMap<String, Integer>();
219
220    // For debugging
221    public BatteryStatsImpl() {
222        mFile = null;
223    }
224
225    public static interface Unpluggable {
226        void unplug(long batteryUptime, long batteryRealtime);
227        void plug(long batteryUptime, long batteryRealtime);
228    }
229
230    /**
231     * State for keeping track of counting information.
232     */
233    public static class Counter extends BatteryStats.Counter implements Unpluggable {
234        final AtomicInteger mCount = new AtomicInteger();
235        int mLoadedCount;
236        int mLastCount;
237        int mUnpluggedCount;
238        int mPluggedCount;
239
240        Counter(ArrayList<Unpluggable> unpluggables, Parcel in) {
241            mPluggedCount = in.readInt();
242            mCount.set(mPluggedCount);
243            mLoadedCount = in.readInt();
244            mLastCount = in.readInt();
245            mUnpluggedCount = in.readInt();
246            unpluggables.add(this);
247        }
248
249        Counter(ArrayList<Unpluggable> unpluggables) {
250            unpluggables.add(this);
251        }
252
253        public void writeToParcel(Parcel out) {
254            out.writeInt(mCount.get());
255            out.writeInt(mLoadedCount);
256            out.writeInt(mLastCount);
257            out.writeInt(mUnpluggedCount);
258        }
259
260        public void unplug(long batteryUptime, long batteryRealtime) {
261            mUnpluggedCount = mPluggedCount;
262            mCount.set(mPluggedCount);
263        }
264
265        public void plug(long batteryUptime, long batteryRealtime) {
266            mPluggedCount = mCount.get();
267        }
268
269        /**
270         * Writes a possibly null Counter to a Parcel.
271         *
272         * @param out the Parcel to be written to.
273         * @param counter a Counter, or null.
274         */
275        public static void writeCounterToParcel(Parcel out, Counter counter) {
276            if (counter == null) {
277                out.writeInt(0); // indicates null
278                return;
279            }
280            out.writeInt(1); // indicates non-null
281
282            counter.writeToParcel(out);
283        }
284
285        @Override
286        public int getCountLocked(int which) {
287            int val;
288            if (which == STATS_LAST) {
289                val = mLastCount;
290            } else {
291                val = mCount.get();
292                if (which == STATS_UNPLUGGED) {
293                    val -= mUnpluggedCount;
294                } else if (which != STATS_TOTAL) {
295                    val -= mLoadedCount;
296                }
297            }
298
299            return val;
300        }
301
302        public void logState(Printer pw, String prefix) {
303            pw.println(prefix + "mCount=" + mCount.get()
304                    + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
305                    + " mUnpluggedCount=" + mUnpluggedCount
306                    + " mPluggedCount=" + mPluggedCount);
307        }
308
309        void stepAtomic() {
310            mCount.incrementAndGet();
311        }
312
313        void writeSummaryFromParcelLocked(Parcel out) {
314            int count = mCount.get();
315            out.writeInt(count);
316            out.writeInt(count - mLoadedCount);
317        }
318
319        void readSummaryFromParcelLocked(Parcel in) {
320            mLoadedCount = in.readInt();
321            mCount.set(mLoadedCount);
322            mLastCount = in.readInt();
323            mUnpluggedCount = mPluggedCount = mLoadedCount;
324        }
325    }
326
327    public static class SamplingCounter extends Counter {
328
329        SamplingCounter(ArrayList<Unpluggable> unpluggables, Parcel in) {
330            super(unpluggables, in);
331        }
332
333        SamplingCounter(ArrayList<Unpluggable> unpluggables) {
334            super(unpluggables);
335        }
336
337        public void addCountAtomic(long count) {
338            mCount.addAndGet((int)count);
339        }
340    }
341
342    /**
343     * State for keeping track of timing information.
344     */
345    public static abstract class Timer extends BatteryStats.Timer implements Unpluggable {
346        final int mType;
347
348
349        int mCount;
350        int mLoadedCount;
351        int mLastCount;
352        int mUnpluggedCount;
353
354        // Times are in microseconds for better accuracy when dividing by the
355        // lock count, and are in "battery realtime" units.
356
357        /**
358         * The total time we have accumulated since the start of the original
359         * boot, to the last time something interesting happened in the
360         * current run.
361         */
362        long mTotalTime;
363
364        /**
365         * The total time we loaded for the previous runs.  Subtract this from
366         * mTotalTime to find the time for the current run of the system.
367         */
368        long mLoadedTime;
369
370        /**
371         * The run time of the last run of the system, as loaded from the
372         * saved data.
373         */
374        long mLastTime;
375
376        /**
377         * The value of mTotalTime when unplug() was last called.  Subtract
378         * this from mTotalTime to find the time since the last unplug from
379         * power.
380         */
381        long mUnpluggedTime;
382
383        /**
384         * Constructs from a parcel.
385         * @param type
386         * @param unpluggables
387         * @param powerType
388         * @param in
389         */
390        Timer(int type, ArrayList<Unpluggable> unpluggables, Parcel in) {
391            mType = type;
392
393            mCount = in.readInt();
394            mLoadedCount = in.readInt();
395            mLastCount = in.readInt();
396            mUnpluggedCount = in.readInt();
397            mTotalTime = in.readLong();
398            mLoadedTime = in.readLong();
399            mLastTime = in.readLong();
400            mUnpluggedTime = in.readLong();
401            unpluggables.add(this);
402        }
403
404        Timer(int type, ArrayList<Unpluggable> unpluggables) {
405            mType = type;
406            unpluggables.add(this);
407        }
408
409        protected abstract long computeRunTimeLocked(long curBatteryRealtime);
410
411        protected abstract int computeCurrentCountLocked();
412
413
414        public void writeToParcel(Parcel out, long batteryRealtime) {
415            out.writeInt(mCount);
416            out.writeInt(mLoadedCount);
417            out.writeInt(mLastCount);
418            out.writeInt(mUnpluggedCount);
419            out.writeLong(computeRunTimeLocked(batteryRealtime));
420            out.writeLong(mLoadedTime);
421            out.writeLong(mLastTime);
422            out.writeLong(mUnpluggedTime);
423        }
424
425        public void unplug(long batteryUptime, long batteryRealtime) {
426            if (DEBUG && mType < 0) {
427                Log.v(TAG, "unplug #" + mType + ": realtime=" + batteryRealtime
428                        + " old mUnpluggedTime=" + mUnpluggedTime
429                        + " old mUnpluggedCount=" + mUnpluggedCount);
430            }
431            mUnpluggedTime = computeRunTimeLocked(batteryRealtime);
432            mUnpluggedCount = mCount;
433            if (DEBUG && mType < 0) {
434                Log.v(TAG, "unplug #" + mType
435                        + ": new mUnpluggedTime=" + mUnpluggedTime
436                        + " new mUnpluggedCount=" + mUnpluggedCount);
437            }
438        }
439
440        public void plug(long batteryUptime, long batteryRealtime) {
441            if (DEBUG && mType < 0) {
442                Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime
443                        + " old mTotalTime=" + mTotalTime);
444            }
445            mTotalTime = computeRunTimeLocked(batteryRealtime);
446            mCount = computeCurrentCountLocked();
447            if (DEBUG && mType < 0) {
448                Log.v(TAG, "plug #" + mType
449                        + ": new mTotalTime=" + mTotalTime);
450            }
451        }
452
453        /**
454         * Writes a possibly null Timer to a Parcel.
455         *
456         * @param out the Parcel to be written to.
457         * @param timer a Timer, or null.
458         */
459        public static void writeTimerToParcel(Parcel out, Timer timer,
460                long batteryRealtime) {
461            if (timer == null) {
462                out.writeInt(0); // indicates null
463                return;
464            }
465            out.writeInt(1); // indicates non-null
466
467            timer.writeToParcel(out, batteryRealtime);
468        }
469
470        @Override
471        public long getTotalTimeLocked(long batteryRealtime, int which) {
472            long val;
473            if (which == STATS_LAST) {
474                val = mLastTime;
475            } else {
476                val = computeRunTimeLocked(batteryRealtime);
477                if (which == STATS_UNPLUGGED) {
478                    val -= mUnpluggedTime;
479                } else if (which != STATS_TOTAL) {
480                    val -= mLoadedTime;
481                }
482            }
483
484            return val;
485        }
486
487        @Override
488        public int getCountLocked(int which) {
489            int val;
490            if (which == STATS_LAST) {
491                val = mLastCount;
492            } else {
493                val = computeCurrentCountLocked();
494                if (which == STATS_UNPLUGGED) {
495                    val -= mUnpluggedCount;
496                } else if (which != STATS_TOTAL) {
497                    val -= mLoadedCount;
498                }
499            }
500
501            return val;
502        }
503
504        public void logState(Printer pw, String prefix) {
505            pw.println(prefix + " mCount=" + mCount
506                    + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
507                    + " mUnpluggedCount=" + mUnpluggedCount);
508            pw.println(prefix + "mTotalTime=" + mTotalTime
509                    + " mLoadedTime=" + mLoadedTime);
510            pw.println(prefix + "mLastTime=" + mLastTime
511                    + " mUnpluggedTime=" + mUnpluggedTime);
512        }
513
514
515        void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
516            long runTime = computeRunTimeLocked(batteryRealtime);
517            // Divide by 1000 for backwards compatibility
518            out.writeLong((runTime + 500) / 1000);
519            out.writeLong(((runTime - mLoadedTime) + 500) / 1000);
520            out.writeInt(mCount);
521            out.writeInt(mCount - mLoadedCount);
522        }
523
524        void readSummaryFromParcelLocked(Parcel in) {
525            // Multiply by 1000 for backwards compatibility
526            mTotalTime = mLoadedTime = in.readLong() * 1000;
527            mLastTime = in.readLong() * 1000;
528            mUnpluggedTime = mTotalTime;
529            mCount = mLoadedCount = in.readInt();
530            mLastCount = in.readInt();
531            mUnpluggedCount = mCount;
532        }
533    }
534
535    public static final class SamplingTimer extends Timer {
536
537        /**
538         * The most recent reported count from /proc/wakelocks.
539         */
540        int mCurrentReportedCount;
541
542        /**
543         * The reported count from /proc/wakelocks when unplug() was last
544         * called.
545         */
546        int mUnpluggedReportedCount;
547
548        /**
549         * The most recent reported total_time from /proc/wakelocks.
550         */
551        long mCurrentReportedTotalTime;
552
553
554        /**
555         * The reported total_time from /proc/wakelocks when unplug() was last
556         * called.
557         */
558        long mUnpluggedReportedTotalTime;
559
560        /**
561         * Whether we are currently in a discharge cycle.
562         */
563        boolean mInDischarge;
564
565        /**
566         * Whether we are currently recording reported values.
567         */
568        boolean mTrackingReportedValues;
569
570        /*
571         * A sequnce counter, incremented once for each update of the stats.
572         */
573        int mUpdateVersion;
574
575        SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge, Parcel in) {
576            super(0, unpluggables, in);
577            mCurrentReportedCount = in.readInt();
578            mUnpluggedReportedCount = in.readInt();
579            mCurrentReportedTotalTime = in.readLong();
580            mUnpluggedReportedTotalTime = in.readLong();
581            mTrackingReportedValues = in.readInt() == 1;
582            mInDischarge = inDischarge;
583        }
584
585        SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge,
586                boolean trackReportedValues) {
587            super(0, unpluggables);
588            mTrackingReportedValues = trackReportedValues;
589            mInDischarge = inDischarge;
590        }
591
592        public void setStale() {
593            mTrackingReportedValues = false;
594            mUnpluggedReportedTotalTime = 0;
595            mUnpluggedReportedCount = 0;
596        }
597
598        public void setUpdateVersion(int version) {
599            mUpdateVersion = version;
600        }
601
602        public int getUpdateVersion() {
603            return mUpdateVersion;
604        }
605
606        public void updateCurrentReportedCount(int count) {
607            if (mInDischarge && mUnpluggedReportedCount == 0) {
608                // Updating the reported value for the first time.
609                mUnpluggedReportedCount = count;
610                // If we are receiving an update update mTrackingReportedValues;
611                mTrackingReportedValues = true;
612            }
613            mCurrentReportedCount = count;
614        }
615
616        public void updateCurrentReportedTotalTime(long totalTime) {
617            if (mInDischarge && mUnpluggedReportedTotalTime == 0) {
618                // Updating the reported value for the first time.
619                mUnpluggedReportedTotalTime = totalTime;
620                // If we are receiving an update update mTrackingReportedValues;
621                mTrackingReportedValues = true;
622            }
623            mCurrentReportedTotalTime = totalTime;
624        }
625
626        public void unplug(long batteryUptime, long batteryRealtime) {
627            super.unplug(batteryUptime, batteryRealtime);
628            if (mTrackingReportedValues) {
629                mUnpluggedReportedTotalTime = mCurrentReportedTotalTime;
630                mUnpluggedReportedCount = mCurrentReportedCount;
631            }
632            mInDischarge = true;
633        }
634
635        public void plug(long batteryUptime, long batteryRealtime) {
636            super.plug(batteryUptime, batteryRealtime);
637            mInDischarge = false;
638        }
639
640        public void logState(Printer pw, String prefix) {
641            super.logState(pw, prefix);
642            pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount
643                    + " mUnpluggedReportedCount=" + mUnpluggedReportedCount
644                    + " mCurrentReportedTotalTime=" + mCurrentReportedTotalTime
645                    + " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTime);
646        }
647
648        protected long computeRunTimeLocked(long curBatteryRealtime) {
649            return mTotalTime + (mInDischarge && mTrackingReportedValues
650                    ? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0);
651        }
652
653        protected int computeCurrentCountLocked() {
654            return mCount + (mInDischarge && mTrackingReportedValues
655                    ? mCurrentReportedCount - mUnpluggedReportedCount : 0);
656        }
657
658        public void writeToParcel(Parcel out, long batteryRealtime) {
659            super.writeToParcel(out, batteryRealtime);
660            out.writeInt(mCurrentReportedCount);
661            out.writeInt(mUnpluggedReportedCount);
662            out.writeLong(mCurrentReportedTotalTime);
663            out.writeLong(mUnpluggedReportedTotalTime);
664            out.writeInt(mTrackingReportedValues ? 1 : 0);
665        }
666
667        void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
668            super.writeSummaryFromParcelLocked(out, batteryRealtime);
669            out.writeLong(mCurrentReportedTotalTime);
670            out.writeInt(mCurrentReportedCount);
671            out.writeInt(mTrackingReportedValues ? 1 : 0);
672        }
673
674        void readSummaryFromParcelLocked(Parcel in) {
675            super.readSummaryFromParcelLocked(in);
676            mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong();
677            mUnpluggedReportedCount = mCurrentReportedCount = in.readInt();
678            mTrackingReportedValues = in.readInt() == 1;
679        }
680    }
681
682    /**
683     * State for keeping track of timing information.
684     */
685    public static final class StopwatchTimer extends Timer {
686        final ArrayList<StopwatchTimer> mTimerPool;
687        int mNesting;
688
689
690        /**
691         * The last time at which we updated the timer.  If mNesting is > 0,
692         * subtract this from the current battery time to find the amount of
693         * time we have been running since we last computed an update.
694         */
695        long mUpdateTime;
696
697        /**
698         * The total time at which the timer was acquired, to determine if
699         * was actually held for an interesting duration.
700         */
701        long mAcquireTime;
702
703        long mTimeout;
704
705        StopwatchTimer(int type, ArrayList<StopwatchTimer> timerPool,
706                ArrayList<Unpluggable> unpluggables, Parcel in) {
707            super(type, unpluggables, in);
708            mTimerPool = timerPool;
709            mUpdateTime = in.readLong();
710        }
711
712        StopwatchTimer(int type, ArrayList<StopwatchTimer> timerPool,
713                ArrayList<Unpluggable> unpluggables) {
714            super(type, unpluggables);
715            mTimerPool = timerPool;
716        }
717
718        void setTimeout(long timeout) {
719            mTimeout = timeout;
720        }
721
722        public void writeToParcel(Parcel out, long batteryRealtime) {
723            super.writeToParcel(out, batteryRealtime);
724            out.writeLong(mUpdateTime);
725        }
726
727        public void plug(long batteryUptime, long batteryRealtime) {
728            if (mNesting > 0) {
729                if (DEBUG && mType < 0) {
730                    Log.v(TAG, "old mUpdateTime=" + mUpdateTime);
731                }
732                super.plug(batteryUptime, batteryRealtime);
733                mUpdateTime = batteryRealtime;
734                if (DEBUG && mType < 0) {
735                    Log.v(TAG, "new mUpdateTime=" + mUpdateTime);
736                }
737            }
738        }
739
740        public void logState(Printer pw, String prefix) {
741            super.logState(pw, prefix);
742            pw.println(prefix + "mNesting=" + mNesting + "mUpdateTime=" + mUpdateTime
743                    + " mAcquireTime=" + mAcquireTime);
744        }
745
746        void startRunningLocked(BatteryStatsImpl stats) {
747            if (mNesting++ == 0) {
748                mUpdateTime = stats.getBatteryRealtimeLocked(
749                        SystemClock.elapsedRealtime() * 1000);
750                if (mTimerPool != null) {
751                    // Accumulate time to all currently active timers before adding
752                    // this new one to the pool.
753                    refreshTimersLocked(stats, mTimerPool);
754                    // Add this timer to the active pool
755                    mTimerPool.add(this);
756                }
757                // Increment the count
758                mCount++;
759                mAcquireTime = mTotalTime;
760                if (DEBUG && mType < 0) {
761                    Log.v(TAG, "start #" + mType + ": mUpdateTime=" + mUpdateTime
762                            + " mTotalTime=" + mTotalTime + " mCount=" + mCount
763                            + " mAcquireTime=" + mAcquireTime);
764                }
765            }
766        }
767
768        boolean isRunningLocked() {
769            return mNesting > 0;
770        }
771
772        void stopRunningLocked(BatteryStatsImpl stats) {
773            // Ignore attempt to stop a timer that isn't running
774            if (mNesting == 0) {
775                return;
776            }
777            if (--mNesting == 0) {
778                if (mTimerPool != null) {
779                    // Accumulate time to all active counters, scaled by the total
780                    // active in the pool, before taking this one out of the pool.
781                    refreshTimersLocked(stats, mTimerPool);
782                    // Remove this timer from the active pool
783                    mTimerPool.remove(this);
784                } else {
785                    final long realtime = SystemClock.elapsedRealtime() * 1000;
786                    final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
787                    mNesting = 1;
788                    mTotalTime = computeRunTimeLocked(batteryRealtime);
789                    mNesting = 0;
790                }
791
792                if (DEBUG && mType < 0) {
793                    Log.v(TAG, "stop #" + mType + ": mUpdateTime=" + mUpdateTime
794                            + " mTotalTime=" + mTotalTime + " mCount=" + mCount
795                            + " mAcquireTime=" + mAcquireTime);
796                }
797
798                if (mTotalTime == mAcquireTime) {
799                    // If there was no change in the time, then discard this
800                    // count.  A somewhat cheezy strategy, but hey.
801                    mCount--;
802                }
803            }
804        }
805
806        // Update the total time for all other running Timers with the same type as this Timer
807        // due to a change in timer count
808        private static void refreshTimersLocked(final BatteryStatsImpl stats,
809                final ArrayList<StopwatchTimer> pool) {
810            final long realtime = SystemClock.elapsedRealtime() * 1000;
811            final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
812            final int N = pool.size();
813            for (int i=N-1; i>= 0; i--) {
814                final StopwatchTimer t = pool.get(i);
815                long heldTime = batteryRealtime - t.mUpdateTime;
816                if (heldTime > 0) {
817                    t.mTotalTime += heldTime / N;
818                }
819                t.mUpdateTime = batteryRealtime;
820            }
821        }
822
823        @Override
824        protected long computeRunTimeLocked(long curBatteryRealtime) {
825            if (mTimeout > 0 && curBatteryRealtime > mUpdateTime + mTimeout) {
826                curBatteryRealtime = mUpdateTime + mTimeout;
827            }
828            return mTotalTime + (mNesting > 0
829                    ? (curBatteryRealtime - mUpdateTime)
830                            / (mTimerPool != null ? mTimerPool.size() : 1)
831                    : 0);
832        }
833
834        @Override
835        protected int computeCurrentCountLocked() {
836            return mCount;
837        }
838
839        void readSummaryFromParcelLocked(Parcel in) {
840            super.readSummaryFromParcelLocked(in);
841            mNesting = 0;
842        }
843    }
844
845    private final Map<String, KernelWakelockStats> readKernelWakelockStats() {
846
847        byte[] buffer = new byte[4096];
848        int len;
849
850        try {
851            FileInputStream is = new FileInputStream("/proc/wakelocks");
852            len = is.read(buffer);
853            is.close();
854
855            if (len > 0) {
856                int i;
857                for (i=0; i<len; i++) {
858                    if (buffer[i] == '\0') {
859                        len = i;
860                        break;
861                    }
862                }
863            }
864        } catch (java.io.FileNotFoundException e) {
865            return null;
866        } catch (java.io.IOException e) {
867            return null;
868        }
869
870        return parseProcWakelocks(buffer, len);
871    }
872
873    private final Map<String, KernelWakelockStats> parseProcWakelocks(
874            byte[] wlBuffer, int len) {
875        String name;
876        int count;
877        long totalTime;
878        int startIndex, endIndex;
879        int numUpdatedWlNames = 0;
880
881        // Advance past the first line.
882        int i;
883        for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++);
884        startIndex = endIndex = i + 1;
885
886        synchronized(this) {
887            Map<String, KernelWakelockStats> m = mProcWakelockFileStats;
888
889            sKernelWakelockUpdateVersion++;
890            while (endIndex < len) {
891                for (endIndex=startIndex;
892                        endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
893                        endIndex++);
894                endIndex++; // endIndex is an exclusive upper bound.
895
896                String[] nameStringArray = mProcWakelocksName;
897                long[] wlData = mProcWakelocksData;
898                // Stomp out any bad characters since this is from a circular buffer
899                // A corruption is seen sometimes that results in the vm crashing
900                // This should prevent crashes and the line will probably fail to parse
901                for (int j = startIndex; j < endIndex; j++) {
902                    if ((wlBuffer[j] & 0x80) != 0) wlBuffer[j] = (byte) '?';
903                }
904                boolean parsed = Process.parseProcLine(wlBuffer, startIndex, endIndex,
905                        PROC_WAKELOCKS_FORMAT, nameStringArray, wlData, null);
906
907                name = nameStringArray[0];
908                count = (int) wlData[1];
909                // convert nanoseconds to microseconds with rounding.
910                totalTime = (wlData[2] + 500) / 1000;
911
912                if (parsed && name.length() > 0) {
913                    if (!m.containsKey(name)) {
914                        m.put(name, new KernelWakelockStats(count, totalTime,
915                                sKernelWakelockUpdateVersion));
916                        numUpdatedWlNames++;
917                    } else {
918                        KernelWakelockStats kwlStats = m.get(name);
919                        if (kwlStats.mVersion == sKernelWakelockUpdateVersion) {
920                            kwlStats.mCount += count;
921                            kwlStats.mTotalTime += totalTime;
922                        } else {
923                            kwlStats.mCount = count;
924                            kwlStats.mTotalTime = totalTime;
925                            kwlStats.mVersion = sKernelWakelockUpdateVersion;
926                            numUpdatedWlNames++;
927                        }
928                    }
929                }
930                startIndex = endIndex;
931            }
932
933            if (m.size() != numUpdatedWlNames) {
934                // Don't report old data.
935                Iterator<KernelWakelockStats> itr = m.values().iterator();
936                while (itr.hasNext()) {
937                    if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
938                        itr.remove();
939                    }
940                }
941            }
942            return m;
943        }
944    }
945
946    private class KernelWakelockStats {
947        public int mCount;
948        public long mTotalTime;
949        public int mVersion;
950
951        KernelWakelockStats(int count, long totalTime, int version) {
952            mCount = count;
953            mTotalTime = totalTime;
954            mVersion = version;
955        }
956    }
957
958    /*
959     * Get the KernelWakelockTimer associated with name, and create a new one if one
960     * doesn't already exist.
961     */
962    public SamplingTimer getKernelWakelockTimerLocked(String name) {
963        SamplingTimer kwlt = mKernelWakelockStats.get(name);
964        if (kwlt == null) {
965            kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
966                    true /* track reported values */);
967            mKernelWakelockStats.put(name, kwlt);
968        }
969        return kwlt;
970    }
971
972    private void doDataPlug(long[] dataTransfer, long currentBytes) {
973        dataTransfer[STATS_LAST] = dataTransfer[STATS_UNPLUGGED];
974        dataTransfer[STATS_UNPLUGGED] = -1;
975    }
976
977    private void doDataUnplug(long[] dataTransfer, long currentBytes) {
978        dataTransfer[STATS_UNPLUGGED] = currentBytes;
979    }
980
981    /**
982     * Radio uptime in microseconds when transferring data. This value is very approximate.
983     * @return
984     */
985    private long getCurrentRadioDataUptime() {
986        try {
987            File awakeTimeFile = new File("/sys/devices/virtual/net/rmnet0/awake_time_ms");
988            if (!awakeTimeFile.exists()) return 0;
989            BufferedReader br = new BufferedReader(new FileReader(awakeTimeFile));
990            String line = br.readLine();
991            br.close();
992            return Long.parseLong(line) * 1000;
993        } catch (NumberFormatException nfe) {
994            // Nothing
995        } catch (IOException ioe) {
996            // Nothing
997        }
998        return 0;
999    }
1000
1001    /**
1002     * @deprecated use getRadioDataUptime
1003     */
1004    public long getRadioDataUptimeMs() {
1005        return getRadioDataUptime() / 1000;
1006    }
1007
1008    /**
1009     * Returns the duration that the cell radio was up for data transfers.
1010     */
1011    public long getRadioDataUptime() {
1012        if (mRadioDataStart == -1) {
1013            return mRadioDataUptime;
1014        } else {
1015            return getCurrentRadioDataUptime() - mRadioDataStart;
1016        }
1017    }
1018
1019    private int getCurrentBluetoothPingCount() {
1020        if (mBtHeadset != null) {
1021            return mBtHeadset.getBatteryUsageHint();
1022        }
1023        return -1;
1024    }
1025
1026    public int getBluetoothPingCount() {
1027        if (mBluetoothPingStart == -1) {
1028            return mBluetoothPingCount;
1029        } else if (mBtHeadset != null) {
1030            return getCurrentBluetoothPingCount() - mBluetoothPingStart;
1031        }
1032        return 0;
1033    }
1034
1035    public void setBtHeadset(BluetoothHeadset headset) {
1036        if (headset != null && mBtHeadset == null && isOnBattery() && mBluetoothPingStart == -1) {
1037            mBluetoothPingStart = getCurrentBluetoothPingCount();
1038        }
1039        mBtHeadset = headset;
1040    }
1041
1042    public void doUnplug(long batteryUptime, long batteryRealtime) {
1043        for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
1044            Uid u = mUidStats.valueAt(iu);
1045            u.mStartedTcpBytesReceived = TrafficStats.getUidRxBytes(u.mUid);
1046            u.mStartedTcpBytesSent = TrafficStats.getUidTxBytes(u.mUid);
1047            u.mTcpBytesReceivedAtLastUnplug = u.mCurrentTcpBytesReceived;
1048            u.mTcpBytesSentAtLastUnplug = u.mCurrentTcpBytesSent;
1049        }
1050        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
1051            mUnpluggables.get(i).unplug(batteryUptime, batteryRealtime);
1052        }
1053        // Track total mobile data
1054        doDataUnplug(mMobileDataRx, TrafficStats.getMobileRxBytes());
1055        doDataUnplug(mMobileDataTx, TrafficStats.getMobileTxBytes());
1056        doDataUnplug(mTotalDataRx, TrafficStats.getTotalRxBytes());
1057        doDataUnplug(mTotalDataTx, TrafficStats.getTotalTxBytes());
1058        // Track radio awake time
1059        mRadioDataStart = getCurrentRadioDataUptime();
1060        mRadioDataUptime = 0;
1061        // Track bt headset ping count
1062        mBluetoothPingStart = getCurrentBluetoothPingCount();
1063        mBluetoothPingCount = 0;
1064    }
1065
1066    public void doPlug(long batteryUptime, long batteryRealtime) {
1067        for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
1068            Uid u = mUidStats.valueAt(iu);
1069            if (u.mStartedTcpBytesReceived >= 0) {
1070                u.mCurrentTcpBytesReceived = u.computeCurrentTcpBytesReceived();
1071                u.mStartedTcpBytesReceived = -1;
1072            }
1073            if (u.mStartedTcpBytesSent >= 0) {
1074                u.mCurrentTcpBytesSent = u.computeCurrentTcpBytesSent();
1075                u.mStartedTcpBytesSent = -1;
1076            }
1077        }
1078        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
1079            mUnpluggables.get(i).plug(batteryUptime, batteryRealtime);
1080        }
1081        doDataPlug(mMobileDataRx, TrafficStats.getMobileRxBytes());
1082        doDataPlug(mMobileDataTx, TrafficStats.getMobileTxBytes());
1083        doDataPlug(mTotalDataRx, TrafficStats.getTotalRxBytes());
1084        doDataPlug(mTotalDataTx, TrafficStats.getTotalTxBytes());
1085        // Track radio awake time
1086        mRadioDataUptime = getRadioDataUptime();
1087        mRadioDataStart = -1;
1088
1089        // Track bt headset ping count
1090        mBluetoothPingCount = getBluetoothPingCount();
1091        mBluetoothPingStart = -1;
1092    }
1093
1094    public void noteStartGps(int uid) {
1095        getUidStatsLocked(uid).noteStartGps();
1096    }
1097
1098    public void noteStopGps(int uid) {
1099        getUidStatsLocked(uid).noteStopGps();
1100    }
1101
1102    public void noteScreenOnLocked() {
1103        if (!mScreenOn) {
1104            mScreenOn = true;
1105            mScreenOnTimer.startRunningLocked(this);
1106            if (mScreenBrightnessBin >= 0) {
1107                mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
1108            }
1109        }
1110    }
1111
1112    public void noteScreenOffLocked() {
1113        if (mScreenOn) {
1114            mScreenOn = false;
1115            mScreenOnTimer.stopRunningLocked(this);
1116            if (mScreenBrightnessBin >= 0) {
1117                mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
1118            }
1119        }
1120    }
1121
1122    public void noteScreenBrightnessLocked(int brightness) {
1123        // Bin the brightness.
1124        int bin = brightness / (256/NUM_SCREEN_BRIGHTNESS_BINS);
1125        if (bin < 0) bin = 0;
1126        else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
1127        if (mScreenBrightnessBin != bin) {
1128            if (mScreenOn) {
1129                if (mScreenBrightnessBin >= 0) {
1130                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
1131                }
1132                mScreenBrightnessTimer[bin].startRunningLocked(this);
1133            }
1134            mScreenBrightnessBin = bin;
1135        }
1136    }
1137
1138    public void noteInputEventAtomic() {
1139        mInputEventCounter.stepAtomic();
1140    }
1141
1142    public void noteUserActivityLocked(int uid, int event) {
1143        getUidStatsLocked(uid).noteUserActivityLocked(event);
1144    }
1145
1146    public void notePhoneOnLocked() {
1147        if (!mPhoneOn) {
1148            mPhoneOn = true;
1149            mPhoneOnTimer.startRunningLocked(this);
1150        }
1151    }
1152
1153    public void notePhoneOffLocked() {
1154        if (mPhoneOn) {
1155            mPhoneOn = false;
1156            mPhoneOnTimer.stopRunningLocked(this);
1157        }
1158    }
1159
1160    /**
1161     * Telephony stack updates the phone state.
1162     * @param state phone state from ServiceState.getState()
1163     */
1164    public void notePhoneStateLocked(int state) {
1165        int bin = mPhoneSignalStrengthBin;
1166        boolean isAirplaneMode = state == ServiceState.STATE_POWER_OFF;
1167        // Stop all timers
1168        if (isAirplaneMode || state == ServiceState.STATE_OUT_OF_SERVICE) {
1169            for (int i = 0; i < NUM_SIGNAL_STRENGTH_BINS; i++) {
1170                while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
1171                    mPhoneSignalStrengthsTimer[i].stopRunningLocked(this);
1172                }
1173            }
1174        }
1175        // Stop Signal Scanning timer, in case we're going into service
1176        while (mPhoneSignalScanningTimer.isRunningLocked()) {
1177            mPhoneSignalScanningTimer.stopRunningLocked(this);
1178        }
1179
1180        // If we're back in service or continuing in service, restart the old timer.
1181        if (state == ServiceState.STATE_IN_SERVICE) {
1182            if (bin == -1) bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1183            if (!mPhoneSignalStrengthsTimer[bin].isRunningLocked()) {
1184                mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
1185            }
1186        } else if (state == ServiceState.STATE_OUT_OF_SERVICE) {
1187            mPhoneSignalStrengthBin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1188            if (!mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].isRunningLocked()) {
1189                mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].startRunningLocked(this);
1190            }
1191            if (!mPhoneSignalScanningTimer.isRunningLocked()) {
1192                mPhoneSignalScanningTimer.startRunningLocked(this);
1193            }
1194        }
1195        mPhoneServiceState = state;
1196    }
1197
1198    public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
1199        // Bin the strength.
1200        int bin;
1201        if (mPhoneServiceState == ServiceState.STATE_POWER_OFF
1202                || mPhoneServiceState == ServiceState.STATE_OUT_OF_SERVICE) {
1203            // Ignore any signal strength changes when radio was turned off or out of service.
1204            return;
1205        }
1206        if (!signalStrength.isGsm()) {
1207            int dBm = signalStrength.getCdmaDbm();
1208            if (dBm >= -75) bin = SIGNAL_STRENGTH_GREAT;
1209            else if (dBm >= -85) bin = SIGNAL_STRENGTH_GOOD;
1210            else if (dBm >= -95)  bin = SIGNAL_STRENGTH_MODERATE;
1211            else if (dBm >= -100)  bin = SIGNAL_STRENGTH_POOR;
1212            else bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1213        } else {
1214            int asu = signalStrength.getGsmSignalStrength();
1215            if (asu < 0 || asu >= 99) bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1216            else if (asu >= 16) bin = SIGNAL_STRENGTH_GREAT;
1217            else if (asu >= 8)  bin = SIGNAL_STRENGTH_GOOD;
1218            else if (asu >= 4)  bin = SIGNAL_STRENGTH_MODERATE;
1219            else bin = SIGNAL_STRENGTH_POOR;
1220        }
1221        if (mPhoneSignalStrengthBin != bin) {
1222            if (mPhoneSignalStrengthBin >= 0) {
1223                mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this);
1224            }
1225            mPhoneSignalStrengthBin = bin;
1226            mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
1227        }
1228    }
1229
1230    public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData) {
1231        int bin = DATA_CONNECTION_NONE;
1232        if (hasData) {
1233            switch (dataType) {
1234                case TelephonyManager.NETWORK_TYPE_EDGE:
1235                    bin = DATA_CONNECTION_EDGE;
1236                    break;
1237                case TelephonyManager.NETWORK_TYPE_GPRS:
1238                    bin = DATA_CONNECTION_GPRS;
1239                    break;
1240                case TelephonyManager.NETWORK_TYPE_UMTS:
1241                    bin = DATA_CONNECTION_UMTS;
1242                    break;
1243                default:
1244                    bin = DATA_CONNECTION_OTHER;
1245                    break;
1246            }
1247        }
1248        if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
1249        if (mPhoneDataConnectionType != bin) {
1250            if (mPhoneDataConnectionType >= 0) {
1251                mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this);
1252            }
1253            mPhoneDataConnectionType = bin;
1254            mPhoneDataConnectionsTimer[bin].startRunningLocked(this);
1255        }
1256    }
1257
1258    public void noteWifiOnLocked(int uid) {
1259        if (!mWifiOn) {
1260            mWifiOn = true;
1261            mWifiOnTimer.startRunningLocked(this);
1262        }
1263        if (mWifiOnUid != uid) {
1264            if (mWifiOnUid >= 0) {
1265                getUidStatsLocked(mWifiOnUid).noteWifiTurnedOffLocked();
1266            }
1267            mWifiOnUid = uid;
1268            getUidStatsLocked(uid).noteWifiTurnedOnLocked();
1269        }
1270    }
1271
1272    public void noteWifiOffLocked(int uid) {
1273        if (mWifiOn) {
1274            mWifiOn = false;
1275            mWifiOnTimer.stopRunningLocked(this);
1276        }
1277        if (mWifiOnUid >= 0) {
1278            getUidStatsLocked(mWifiOnUid).noteWifiTurnedOffLocked();
1279            mWifiOnUid = -1;
1280        }
1281    }
1282
1283    public void noteAudioOnLocked(int uid) {
1284        if (!mAudioOn) {
1285            mAudioOn = true;
1286            mAudioOnTimer.startRunningLocked(this);
1287        }
1288        getUidStatsLocked(uid).noteAudioTurnedOnLocked();
1289    }
1290
1291    public void noteAudioOffLocked(int uid) {
1292        if (mAudioOn) {
1293            mAudioOn = false;
1294            mAudioOnTimer.stopRunningLocked(this);
1295        }
1296        getUidStatsLocked(uid).noteAudioTurnedOffLocked();
1297    }
1298
1299    public void noteVideoOnLocked(int uid) {
1300        if (!mVideoOn) {
1301            mVideoOn = true;
1302            mVideoOnTimer.startRunningLocked(this);
1303        }
1304        getUidStatsLocked(uid).noteVideoTurnedOnLocked();
1305    }
1306
1307    public void noteVideoOffLocked(int uid) {
1308        if (mVideoOn) {
1309            mVideoOn = false;
1310            mVideoOnTimer.stopRunningLocked(this);
1311        }
1312        getUidStatsLocked(uid).noteVideoTurnedOffLocked();
1313    }
1314
1315    public void noteWifiRunningLocked() {
1316        if (!mWifiRunning) {
1317            mWifiRunning = true;
1318            mWifiRunningTimer.startRunningLocked(this);
1319        }
1320    }
1321
1322    public void noteWifiStoppedLocked() {
1323        if (mWifiRunning) {
1324            mWifiRunning = false;
1325            mWifiRunningTimer.stopRunningLocked(this);
1326        }
1327    }
1328
1329    public void noteBluetoothOnLocked() {
1330        if (!mBluetoothOn) {
1331            mBluetoothOn = true;
1332            mBluetoothOnTimer.startRunningLocked(this);
1333        }
1334    }
1335
1336    public void noteBluetoothOffLocked() {
1337        if (mBluetoothOn) {
1338            mBluetoothOn = false;
1339            mBluetoothOnTimer.stopRunningLocked(this);
1340        }
1341    }
1342
1343    public void noteFullWifiLockAcquiredLocked(int uid) {
1344        getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
1345    }
1346
1347    public void noteFullWifiLockReleasedLocked(int uid) {
1348        getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
1349    }
1350
1351    public void noteScanWifiLockAcquiredLocked(int uid) {
1352        getUidStatsLocked(uid).noteScanWifiLockAcquiredLocked();
1353    }
1354
1355    public void noteScanWifiLockReleasedLocked(int uid) {
1356        getUidStatsLocked(uid).noteScanWifiLockReleasedLocked();
1357    }
1358
1359    public void noteWifiMulticastEnabledLocked(int uid) {
1360        getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
1361    }
1362
1363    public void noteWifiMulticastDisabledLocked(int uid) {
1364        getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
1365    }
1366
1367    @Override public long getScreenOnTime(long batteryRealtime, int which) {
1368        return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
1369    }
1370
1371    @Override public long getScreenBrightnessTime(int brightnessBin,
1372            long batteryRealtime, int which) {
1373        return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
1374                batteryRealtime, which);
1375    }
1376
1377    @Override public int getInputEventCount(int which) {
1378        return mInputEventCounter.getCountLocked(which);
1379    }
1380
1381    @Override public long getPhoneOnTime(long batteryRealtime, int which) {
1382        return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
1383    }
1384
1385    @Override public long getPhoneSignalStrengthTime(int strengthBin,
1386            long batteryRealtime, int which) {
1387        return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
1388                batteryRealtime, which);
1389    }
1390
1391    @Override public long getPhoneSignalScanningTime(
1392            long batteryRealtime, int which) {
1393        return mPhoneSignalScanningTimer.getTotalTimeLocked(
1394                batteryRealtime, which);
1395    }
1396
1397    @Override public int getPhoneSignalStrengthCount(int dataType, int which) {
1398        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
1399    }
1400
1401    @Override public long getPhoneDataConnectionTime(int dataType,
1402            long batteryRealtime, int which) {
1403        return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
1404                batteryRealtime, which);
1405    }
1406
1407    @Override public int getPhoneDataConnectionCount(int dataType, int which) {
1408        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
1409    }
1410
1411    @Override public long getWifiOnTime(long batteryRealtime, int which) {
1412        return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
1413    }
1414
1415    @Override public long getWifiRunningTime(long batteryRealtime, int which) {
1416        return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
1417    }
1418
1419    @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
1420        return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
1421    }
1422
1423    @Override public boolean getIsOnBattery() {
1424        return mOnBattery;
1425    }
1426
1427    @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
1428        return mUidStats;
1429    }
1430
1431    /**
1432     * The statistics associated with a particular uid.
1433     */
1434    public final class Uid extends BatteryStats.Uid {
1435
1436        final int mUid;
1437        long mLoadedTcpBytesReceived;
1438        long mLoadedTcpBytesSent;
1439        long mCurrentTcpBytesReceived;
1440        long mCurrentTcpBytesSent;
1441        long mTcpBytesReceivedAtLastUnplug;
1442        long mTcpBytesSentAtLastUnplug;
1443
1444        // These are not saved/restored when parcelling, since we want
1445        // to return from the parcel with a snapshot of the state.
1446        long mStartedTcpBytesReceived = -1;
1447        long mStartedTcpBytesSent = -1;
1448
1449        boolean mWifiTurnedOn;
1450        StopwatchTimer mWifiTurnedOnTimer;
1451
1452        boolean mFullWifiLockOut;
1453        StopwatchTimer mFullWifiLockTimer;
1454
1455        boolean mScanWifiLockOut;
1456        StopwatchTimer mScanWifiLockTimer;
1457
1458        boolean mWifiMulticastEnabled;
1459        StopwatchTimer mWifiMulticastTimer;
1460
1461        boolean mAudioTurnedOn;
1462        StopwatchTimer mAudioTurnedOnTimer;
1463
1464        boolean mVideoTurnedOn;
1465        StopwatchTimer mVideoTurnedOnTimer;
1466
1467        Counter[] mUserActivityCounters;
1468
1469        /**
1470         * The statistics we have collected for this uid's wake locks.
1471         */
1472        final HashMap<String, Wakelock> mWakelockStats = new HashMap<String, Wakelock>();
1473
1474        /**
1475         * The statistics we have collected for this uid's sensor activations.
1476         */
1477        final HashMap<Integer, Sensor> mSensorStats = new HashMap<Integer, Sensor>();
1478
1479        /**
1480         * The statistics we have collected for this uid's processes.
1481         */
1482        final HashMap<String, Proc> mProcessStats = new HashMap<String, Proc>();
1483
1484        /**
1485         * The statistics we have collected for this uid's processes.
1486         */
1487        final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
1488
1489        public Uid(int uid) {
1490            mUid = uid;
1491            mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables);
1492            mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables);
1493            mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables);
1494            mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
1495                    null, mUnpluggables);
1496            mAudioTurnedOnTimer = new StopwatchTimer(AUDIO_TURNED_ON, null, mUnpluggables);
1497            mVideoTurnedOnTimer = new StopwatchTimer(VIDEO_TURNED_ON, null, mUnpluggables);
1498        }
1499
1500        @Override
1501        public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
1502            return mWakelockStats;
1503        }
1504
1505        @Override
1506        public Map<Integer, ? extends BatteryStats.Uid.Sensor> getSensorStats() {
1507            return mSensorStats;
1508        }
1509
1510        @Override
1511        public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
1512            return mProcessStats;
1513        }
1514
1515        @Override
1516        public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
1517            return mPackageStats;
1518        }
1519
1520        @Override
1521        public int getUid() {
1522            return mUid;
1523        }
1524
1525        @Override
1526        public long getTcpBytesReceived(int which) {
1527            if (which == STATS_LAST) {
1528                return mLoadedTcpBytesReceived;
1529            } else {
1530                long current = computeCurrentTcpBytesReceived();
1531                if (which == STATS_UNPLUGGED) {
1532                    current -= mTcpBytesReceivedAtLastUnplug;
1533                } else if (which == STATS_TOTAL) {
1534                    current += mLoadedTcpBytesReceived;
1535                }
1536                return current;
1537            }
1538        }
1539
1540        public long computeCurrentTcpBytesReceived() {
1541            return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
1542                    ? (TrafficStats.getUidRxBytes(mUid) - mStartedTcpBytesReceived) : 0);
1543        }
1544
1545        @Override
1546        public long getTcpBytesSent(int which) {
1547            if (which == STATS_LAST) {
1548                return mLoadedTcpBytesSent;
1549            } else {
1550                long current = computeCurrentTcpBytesSent();
1551                if (which == STATS_UNPLUGGED) {
1552                    current -= mTcpBytesSentAtLastUnplug;
1553                } else if (which == STATS_TOTAL) {
1554                    current += mLoadedTcpBytesSent;
1555                }
1556                return current;
1557            }
1558        }
1559
1560        @Override
1561        public void noteWifiTurnedOnLocked() {
1562            if (!mWifiTurnedOn) {
1563                mWifiTurnedOn = true;
1564                mWifiTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
1565            }
1566        }
1567
1568        @Override
1569        public void noteWifiTurnedOffLocked() {
1570            if (mWifiTurnedOn) {
1571                mWifiTurnedOn = false;
1572                mWifiTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
1573            }
1574        }
1575
1576        @Override
1577        public void noteFullWifiLockAcquiredLocked() {
1578            if (!mFullWifiLockOut) {
1579                mFullWifiLockOut = true;
1580                mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
1581            }
1582        }
1583
1584        @Override
1585        public void noteVideoTurnedOnLocked() {
1586            if (!mVideoTurnedOn) {
1587                mVideoTurnedOn = true;
1588                mVideoTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
1589            }
1590        }
1591
1592        @Override
1593        public void noteVideoTurnedOffLocked() {
1594            if (mVideoTurnedOn) {
1595                mVideoTurnedOn = false;
1596                mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
1597            }
1598        }
1599
1600        @Override
1601        public void noteAudioTurnedOnLocked() {
1602            if (!mAudioTurnedOn) {
1603                mAudioTurnedOn = true;
1604                mAudioTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
1605            }
1606        }
1607
1608        @Override
1609        public void noteAudioTurnedOffLocked() {
1610            if (mAudioTurnedOn) {
1611                mAudioTurnedOn = false;
1612                mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
1613            }
1614        }
1615
1616        @Override
1617        public void noteFullWifiLockReleasedLocked() {
1618            if (mFullWifiLockOut) {
1619                mFullWifiLockOut = false;
1620                mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
1621            }
1622        }
1623
1624        @Override
1625        public void noteScanWifiLockAcquiredLocked() {
1626            if (!mScanWifiLockOut) {
1627                mScanWifiLockOut = true;
1628                mScanWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
1629            }
1630        }
1631
1632        @Override
1633        public void noteScanWifiLockReleasedLocked() {
1634            if (mScanWifiLockOut) {
1635                mScanWifiLockOut = false;
1636                mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
1637            }
1638        }
1639
1640        @Override
1641        public void noteWifiMulticastEnabledLocked() {
1642            if (!mWifiMulticastEnabled) {
1643                mWifiMulticastEnabled = true;
1644                mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
1645            }
1646        }
1647
1648        @Override
1649        public void noteWifiMulticastDisabledLocked() {
1650            if (mWifiMulticastEnabled) {
1651                mWifiMulticastEnabled = false;
1652                mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
1653            }
1654        }
1655
1656        @Override
1657        public long getWifiTurnedOnTime(long batteryRealtime, int which) {
1658            return mWifiTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
1659        }
1660
1661        @Override
1662        public long getAudioTurnedOnTime(long batteryRealtime, int which) {
1663            return mAudioTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
1664        }
1665
1666        @Override
1667        public long getVideoTurnedOnTime(long batteryRealtime, int which) {
1668            return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
1669        }
1670
1671        @Override
1672        public long getFullWifiLockTime(long batteryRealtime, int which) {
1673            return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
1674        }
1675
1676        @Override
1677        public long getScanWifiLockTime(long batteryRealtime, int which) {
1678            return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
1679        }
1680
1681        @Override
1682        public long getWifiMulticastTime(long batteryRealtime, int which) {
1683            return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime,
1684                                                          which);
1685        }
1686
1687        @Override
1688        public void noteUserActivityLocked(int type) {
1689            if (mUserActivityCounters == null) {
1690                initUserActivityLocked();
1691            }
1692            if (type < 0) type = 0;
1693            else if (type >= NUM_USER_ACTIVITY_TYPES) type = NUM_USER_ACTIVITY_TYPES-1;
1694            mUserActivityCounters[type].stepAtomic();
1695        }
1696
1697        @Override
1698        public boolean hasUserActivity() {
1699            return mUserActivityCounters != null;
1700        }
1701
1702        @Override
1703        public int getUserActivityCount(int type, int which) {
1704            if (mUserActivityCounters == null) {
1705                return 0;
1706            }
1707            return mUserActivityCounters[type].getCountLocked(which);
1708        }
1709
1710        void initUserActivityLocked() {
1711            mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
1712            for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
1713                mUserActivityCounters[i] = new Counter(mUnpluggables);
1714            }
1715        }
1716
1717        public long computeCurrentTcpBytesSent() {
1718            return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
1719                    ? (TrafficStats.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
1720        }
1721
1722        void writeToParcelLocked(Parcel out, long batteryRealtime) {
1723            out.writeInt(mWakelockStats.size());
1724            for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
1725                out.writeString(wakelockEntry.getKey());
1726                Uid.Wakelock wakelock = wakelockEntry.getValue();
1727                wakelock.writeToParcelLocked(out, batteryRealtime);
1728            }
1729
1730            out.writeInt(mSensorStats.size());
1731            for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
1732                out.writeInt(sensorEntry.getKey());
1733                Uid.Sensor sensor = sensorEntry.getValue();
1734                sensor.writeToParcelLocked(out, batteryRealtime);
1735            }
1736
1737            out.writeInt(mProcessStats.size());
1738            for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
1739                out.writeString(procEntry.getKey());
1740                Uid.Proc proc = procEntry.getValue();
1741                proc.writeToParcelLocked(out);
1742            }
1743
1744            out.writeInt(mPackageStats.size());
1745            for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
1746                out.writeString(pkgEntry.getKey());
1747                Uid.Pkg pkg = pkgEntry.getValue();
1748                pkg.writeToParcelLocked(out);
1749            }
1750
1751            out.writeLong(mLoadedTcpBytesReceived);
1752            out.writeLong(mLoadedTcpBytesSent);
1753            out.writeLong(computeCurrentTcpBytesReceived());
1754            out.writeLong(computeCurrentTcpBytesSent());
1755            out.writeLong(mTcpBytesReceivedAtLastUnplug);
1756            out.writeLong(mTcpBytesSentAtLastUnplug);
1757            mWifiTurnedOnTimer.writeToParcel(out, batteryRealtime);
1758            mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
1759            mAudioTurnedOnTimer.writeToParcel(out, batteryRealtime);
1760            mVideoTurnedOnTimer.writeToParcel(out, batteryRealtime);
1761            mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
1762            mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
1763            if (mUserActivityCounters == null) {
1764                out.writeInt(0);
1765            } else {
1766                out.writeInt(1);
1767                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
1768                    mUserActivityCounters[i].writeToParcel(out);
1769                }
1770            }
1771        }
1772
1773        void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
1774            int numWakelocks = in.readInt();
1775            mWakelockStats.clear();
1776            for (int j = 0; j < numWakelocks; j++) {
1777                String wakelockName = in.readString();
1778                Uid.Wakelock wakelock = new Wakelock();
1779                wakelock.readFromParcelLocked(unpluggables, in);
1780                if (mWakelockStats.size() < MAX_WAKELOCKS_PER_UID) {
1781                    // We will just drop some random set of wakelocks if
1782                    // the previous run of the system was an older version
1783                    // that didn't impose a limit.
1784                    mWakelockStats.put(wakelockName, wakelock);
1785                }
1786            }
1787
1788            int numSensors = in.readInt();
1789            mSensorStats.clear();
1790            for (int k = 0; k < numSensors; k++) {
1791                int sensorNumber = in.readInt();
1792                Uid.Sensor sensor = new Sensor(sensorNumber);
1793                sensor.readFromParcelLocked(mUnpluggables, in);
1794                mSensorStats.put(sensorNumber, sensor);
1795            }
1796
1797            int numProcs = in.readInt();
1798            mProcessStats.clear();
1799            for (int k = 0; k < numProcs; k++) {
1800                String processName = in.readString();
1801                Uid.Proc proc = new Proc();
1802                proc.readFromParcelLocked(in);
1803                mProcessStats.put(processName, proc);
1804            }
1805
1806            int numPkgs = in.readInt();
1807            mPackageStats.clear();
1808            for (int l = 0; l < numPkgs; l++) {
1809                String packageName = in.readString();
1810                Uid.Pkg pkg = new Pkg();
1811                pkg.readFromParcelLocked(in);
1812                mPackageStats.put(packageName, pkg);
1813            }
1814
1815            mLoadedTcpBytesReceived = in.readLong();
1816            mLoadedTcpBytesSent = in.readLong();
1817            mCurrentTcpBytesReceived = in.readLong();
1818            mCurrentTcpBytesSent = in.readLong();
1819            mTcpBytesReceivedAtLastUnplug = in.readLong();
1820            mTcpBytesSentAtLastUnplug = in.readLong();
1821            mWifiTurnedOn = false;
1822            mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables, in);
1823            mFullWifiLockOut = false;
1824            mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables, in);
1825            mAudioTurnedOn = false;
1826            mAudioTurnedOnTimer = new StopwatchTimer(AUDIO_TURNED_ON, null, mUnpluggables, in);
1827            mVideoTurnedOn = false;
1828            mVideoTurnedOnTimer = new StopwatchTimer(VIDEO_TURNED_ON, null, mUnpluggables, in);
1829            mScanWifiLockOut = false;
1830            mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables, in);
1831            mWifiMulticastEnabled = false;
1832            mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
1833                    null, mUnpluggables, in);
1834            if (in.readInt() == 0) {
1835                mUserActivityCounters = null;
1836            } else {
1837                mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
1838                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
1839                    mUserActivityCounters[i] = new Counter(mUnpluggables, in);
1840                }
1841            }
1842        }
1843
1844        /**
1845         * The statistics associated with a particular wake lock.
1846         */
1847        public final class Wakelock extends BatteryStats.Uid.Wakelock {
1848            /**
1849             * How long (in ms) this uid has been keeping the device partially awake.
1850             */
1851            StopwatchTimer mTimerPartial;
1852
1853            /**
1854             * How long (in ms) this uid has been keeping the device fully awake.
1855             */
1856            StopwatchTimer mTimerFull;
1857
1858            /**
1859             * How long (in ms) this uid has had a window keeping the device awake.
1860             */
1861            StopwatchTimer mTimerWindow;
1862
1863            /**
1864             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
1865             * proper timer pool from the given BatteryStatsImpl object.
1866             *
1867             * @param in the Parcel to be read from.
1868             * return a new Timer, or null.
1869             */
1870            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
1871                    ArrayList<Unpluggable> unpluggables, Parcel in) {
1872                if (in.readInt() == 0) {
1873                    return null;
1874                }
1875
1876                return new StopwatchTimer(type, pool, unpluggables, in);
1877            }
1878
1879            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
1880                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
1881                        mPartialTimers, unpluggables, in);
1882                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
1883                        mFullTimers, unpluggables, in);
1884                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
1885                        mWindowTimers, unpluggables, in);
1886            }
1887
1888            void writeToParcelLocked(Parcel out, long batteryRealtime) {
1889                Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
1890                Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
1891                Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
1892            }
1893
1894            @Override
1895            public Timer getWakeTime(int type) {
1896                switch (type) {
1897                case WAKE_TYPE_FULL: return mTimerFull;
1898                case WAKE_TYPE_PARTIAL: return mTimerPartial;
1899                case WAKE_TYPE_WINDOW: return mTimerWindow;
1900                default: throw new IllegalArgumentException("type = " + type);
1901                }
1902            }
1903        }
1904
1905        public final class Sensor extends BatteryStats.Uid.Sensor {
1906            final int mHandle;
1907            StopwatchTimer mTimer;
1908
1909            public Sensor(int handle) {
1910                mHandle = handle;
1911            }
1912
1913            private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
1914                    Parcel in) {
1915                if (in.readInt() == 0) {
1916                    return null;
1917                }
1918
1919                ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
1920                if (pool == null) {
1921                    pool = new ArrayList<StopwatchTimer>();
1922                    mSensorTimers.put(mHandle, pool);
1923                }
1924                return new StopwatchTimer(0, pool, unpluggables, in);
1925            }
1926
1927            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
1928                mTimer = readTimerFromParcel(unpluggables, in);
1929            }
1930
1931            void writeToParcelLocked(Parcel out, long batteryRealtime) {
1932                Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
1933            }
1934
1935            @Override
1936            public Timer getSensorTime() {
1937                return mTimer;
1938            }
1939
1940            @Override
1941            public int getHandle() {
1942                return mHandle;
1943            }
1944        }
1945
1946        /**
1947         * The statistics associated with a particular process.
1948         */
1949        public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
1950            /**
1951             * Total time (in 1/100 sec) spent executing in user code.
1952             */
1953            long mUserTime;
1954
1955            /**
1956             * Total time (in 1/100 sec) spent executing in kernel code.
1957             */
1958            long mSystemTime;
1959
1960            /**
1961             * Number of times the process has been started.
1962             */
1963            int mStarts;
1964
1965            /**
1966             * Amount of time the process was running in the foreground.
1967             */
1968            long mForegroundTime;
1969
1970            /**
1971             * The amount of user time loaded from a previous save.
1972             */
1973            long mLoadedUserTime;
1974
1975            /**
1976             * The amount of system time loaded from a previous save.
1977             */
1978            long mLoadedSystemTime;
1979
1980            /**
1981             * The number of times the process has started from a previous save.
1982             */
1983            int mLoadedStarts;
1984
1985            /**
1986             * The amount of foreground time loaded from a previous save.
1987             */
1988            long mLoadedForegroundTime;
1989
1990            /**
1991             * The amount of user time loaded from the previous run.
1992             */
1993            long mLastUserTime;
1994
1995            /**
1996             * The amount of system time loaded from the previous run.
1997             */
1998            long mLastSystemTime;
1999
2000            /**
2001             * The number of times the process has started from the previous run.
2002             */
2003            int mLastStarts;
2004
2005            /**
2006             * The amount of foreground time loaded from the previous run
2007             */
2008            long mLastForegroundTime;
2009
2010            /**
2011             * The amount of user time when last unplugged.
2012             */
2013            long mUnpluggedUserTime;
2014
2015            /**
2016             * The amount of system time when last unplugged.
2017             */
2018            long mUnpluggedSystemTime;
2019
2020            /**
2021             * The number of times the process has started before unplugged.
2022             */
2023            int mUnpluggedStarts;
2024
2025            /**
2026             * The amount of foreground time since unplugged.
2027             */
2028            long mUnpluggedForegroundTime;
2029
2030            SamplingCounter[] mSpeedBins;
2031
2032            Proc() {
2033                mUnpluggables.add(this);
2034                mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
2035                for (int i = 0; i < mSpeedBins.length; i++) {
2036                    mSpeedBins[i] = new SamplingCounter(mUnpluggables);
2037                }
2038            }
2039
2040            public void unplug(long batteryUptime, long batteryRealtime) {
2041                mUnpluggedUserTime = mUserTime;
2042                mUnpluggedSystemTime = mSystemTime;
2043                mUnpluggedStarts = mStarts;
2044                mUnpluggedForegroundTime = mForegroundTime;
2045            }
2046
2047            public void plug(long batteryUptime, long batteryRealtime) {
2048            }
2049
2050            void writeToParcelLocked(Parcel out) {
2051                final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
2052                final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
2053
2054                out.writeLong(mUserTime);
2055                out.writeLong(mSystemTime);
2056                out.writeLong(mForegroundTime);
2057                out.writeInt(mStarts);
2058                out.writeLong(mLoadedUserTime);
2059                out.writeLong(mLoadedSystemTime);
2060                out.writeLong(mLoadedForegroundTime);
2061                out.writeInt(mLoadedStarts);
2062                out.writeLong(mLastUserTime);
2063                out.writeLong(mLastSystemTime);
2064                out.writeLong(mLastForegroundTime);
2065                out.writeInt(mLastStarts);
2066                out.writeLong(mUnpluggedUserTime);
2067                out.writeLong(mUnpluggedSystemTime);
2068                out.writeLong(mUnpluggedForegroundTime);
2069                out.writeInt(mUnpluggedStarts);
2070
2071                out.writeInt(mSpeedBins.length);
2072                for (int i = 0; i < mSpeedBins.length; i++) {
2073                    mSpeedBins[i].writeToParcel(out);
2074                }
2075            }
2076
2077            void readFromParcelLocked(Parcel in) {
2078                mUserTime = in.readLong();
2079                mSystemTime = in.readLong();
2080                mForegroundTime = in.readLong();
2081                mStarts = in.readInt();
2082                mLoadedUserTime = in.readLong();
2083                mLoadedSystemTime = in.readLong();
2084                mLoadedForegroundTime = in.readLong();
2085                mLoadedStarts = in.readInt();
2086                mLastUserTime = in.readLong();
2087                mLastSystemTime = in.readLong();
2088                mLastForegroundTime = in.readLong();
2089                mLastStarts = in.readInt();
2090                mUnpluggedUserTime = in.readLong();
2091                mUnpluggedSystemTime = in.readLong();
2092                mUnpluggedForegroundTime = in.readLong();
2093                mUnpluggedStarts = in.readInt();
2094
2095                int bins = in.readInt();
2096                mSpeedBins = new SamplingCounter[bins];
2097                for (int i = 0; i < bins; i++) {
2098                    mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
2099                }
2100            }
2101
2102            public BatteryStatsImpl getBatteryStats() {
2103                return BatteryStatsImpl.this;
2104            }
2105
2106            public void addCpuTimeLocked(int utime, int stime) {
2107                mUserTime += utime;
2108                mSystemTime += stime;
2109            }
2110
2111            public void addForegroundTimeLocked(long ttime) {
2112                mForegroundTime += ttime;
2113            }
2114
2115            public void incStartsLocked() {
2116                mStarts++;
2117            }
2118
2119            @Override
2120            public long getUserTime(int which) {
2121                long val;
2122                if (which == STATS_LAST) {
2123                    val = mLastUserTime;
2124                } else {
2125                    val = mUserTime;
2126                    if (which == STATS_CURRENT) {
2127                        val -= mLoadedUserTime;
2128                    } else if (which == STATS_UNPLUGGED) {
2129                        val -= mUnpluggedUserTime;
2130                    }
2131                }
2132                return val;
2133            }
2134
2135            @Override
2136            public long getSystemTime(int which) {
2137                long val;
2138                if (which == STATS_LAST) {
2139                    val = mLastSystemTime;
2140                } else {
2141                    val = mSystemTime;
2142                    if (which == STATS_CURRENT) {
2143                        val -= mLoadedSystemTime;
2144                    } else if (which == STATS_UNPLUGGED) {
2145                        val -= mUnpluggedSystemTime;
2146                    }
2147                }
2148                return val;
2149            }
2150
2151            @Override
2152            public long getForegroundTime(int which) {
2153                long val;
2154                if (which == STATS_LAST) {
2155                    val = mLastForegroundTime;
2156                } else {
2157                    val = mForegroundTime;
2158                    if (which == STATS_CURRENT) {
2159                        val -= mLoadedForegroundTime;
2160                    } else if (which == STATS_UNPLUGGED) {
2161                        val -= mUnpluggedForegroundTime;
2162                    }
2163                }
2164                return val;
2165            }
2166
2167            @Override
2168            public int getStarts(int which) {
2169                int val;
2170                if (which == STATS_LAST) {
2171                    val = mLastStarts;
2172                } else {
2173                    val = mStarts;
2174                    if (which == STATS_CURRENT) {
2175                        val -= mLoadedStarts;
2176                    } else if (which == STATS_UNPLUGGED) {
2177                        val -= mUnpluggedStarts;
2178                    }
2179                }
2180                return val;
2181            }
2182
2183            /* Called by ActivityManagerService when CPU times are updated. */
2184            public void addSpeedStepTimes(long[] values) {
2185                for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
2186                    mSpeedBins[i].addCountAtomic(values[i]);
2187                }
2188            }
2189
2190            @Override
2191            public long getTimeAtCpuSpeedStep(int speedStep, int which) {
2192                if (speedStep < mSpeedBins.length) {
2193                    return mSpeedBins[speedStep].getCountLocked(which);
2194                } else {
2195                    return 0;
2196                }
2197            }
2198        }
2199
2200        /**
2201         * The statistics associated with a particular package.
2202         */
2203        public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
2204            /**
2205             * Number of times this package has done something that could wake up the
2206             * device from sleep.
2207             */
2208            int mWakeups;
2209
2210            /**
2211             * Number of things that could wake up the device loaded from a
2212             * previous save.
2213             */
2214            int mLoadedWakeups;
2215
2216            /**
2217             * Number of things that could wake up the device as of the
2218             * last run.
2219             */
2220            int mLastWakeups;
2221
2222            /**
2223             * Number of things that could wake up the device as of the
2224             * last run.
2225             */
2226            int mUnpluggedWakeups;
2227
2228            /**
2229             * The statics we have collected for this package's services.
2230             */
2231            final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
2232
2233            Pkg() {
2234                mUnpluggables.add(this);
2235            }
2236
2237            public void unplug(long batteryUptime, long batteryRealtime) {
2238                mUnpluggedWakeups = mWakeups;
2239            }
2240
2241            public void plug(long batteryUptime, long batteryRealtime) {
2242            }
2243
2244            void readFromParcelLocked(Parcel in) {
2245                mWakeups = in.readInt();
2246                mLoadedWakeups = in.readInt();
2247                mLastWakeups = in.readInt();
2248                mUnpluggedWakeups = in.readInt();
2249
2250                int numServs = in.readInt();
2251                mServiceStats.clear();
2252                for (int m = 0; m < numServs; m++) {
2253                    String serviceName = in.readString();
2254                    Uid.Pkg.Serv serv = new Serv();
2255                    mServiceStats.put(serviceName, serv);
2256
2257                    serv.readFromParcelLocked(in);
2258                }
2259            }
2260
2261            void writeToParcelLocked(Parcel out) {
2262                out.writeInt(mWakeups);
2263                out.writeInt(mLoadedWakeups);
2264                out.writeInt(mLastWakeups);
2265                out.writeInt(mUnpluggedWakeups);
2266
2267                out.writeInt(mServiceStats.size());
2268                for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
2269                    out.writeString(servEntry.getKey());
2270                    Uid.Pkg.Serv serv = servEntry.getValue();
2271
2272                    serv.writeToParcelLocked(out);
2273                }
2274            }
2275
2276            @Override
2277            public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
2278                return mServiceStats;
2279            }
2280
2281            @Override
2282            public int getWakeups(int which) {
2283                int val;
2284                if (which == STATS_LAST) {
2285                    val = mLastWakeups;
2286                } else {
2287                    val = mWakeups;
2288                    if (which == STATS_CURRENT) {
2289                        val -= mLoadedWakeups;
2290                    } else if (which == STATS_UNPLUGGED) {
2291                        val -= mUnpluggedWakeups;
2292                    }
2293                }
2294
2295                return val;
2296            }
2297
2298            /**
2299             * The statistics associated with a particular service.
2300             */
2301            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
2302                /**
2303                 * Total time (ms in battery uptime) the service has been left started.
2304                 */
2305                long mStartTime;
2306
2307                /**
2308                 * If service has been started and not yet stopped, this is
2309                 * when it was started.
2310                 */
2311                long mRunningSince;
2312
2313                /**
2314                 * True if we are currently running.
2315                 */
2316                boolean mRunning;
2317
2318                /**
2319                 * Total number of times startService() has been called.
2320                 */
2321                int mStarts;
2322
2323                /**
2324                 * Total time (ms in battery uptime) the service has been left launched.
2325                 */
2326                long mLaunchedTime;
2327
2328                /**
2329                 * If service has been launched and not yet exited, this is
2330                 * when it was launched (ms in battery uptime).
2331                 */
2332                long mLaunchedSince;
2333
2334                /**
2335                 * True if we are currently launched.
2336                 */
2337                boolean mLaunched;
2338
2339                /**
2340                 * Total number times the service has been launched.
2341                 */
2342                int mLaunches;
2343
2344                /**
2345                 * The amount of time spent started loaded from a previous save
2346                 * (ms in battery uptime).
2347                 */
2348                long mLoadedStartTime;
2349
2350                /**
2351                 * The number of starts loaded from a previous save.
2352                 */
2353                int mLoadedStarts;
2354
2355                /**
2356                 * The number of launches loaded from a previous save.
2357                 */
2358                int mLoadedLaunches;
2359
2360                /**
2361                 * The amount of time spent started as of the last run (ms
2362                 * in battery uptime).
2363                 */
2364                long mLastStartTime;
2365
2366                /**
2367                 * The number of starts as of the last run.
2368                 */
2369                int mLastStarts;
2370
2371                /**
2372                 * The number of launches as of the last run.
2373                 */
2374                int mLastLaunches;
2375
2376                /**
2377                 * The amount of time spent started when last unplugged (ms
2378                 * in battery uptime).
2379                 */
2380                long mUnpluggedStartTime;
2381
2382                /**
2383                 * The number of starts when last unplugged.
2384                 */
2385                int mUnpluggedStarts;
2386
2387                /**
2388                 * The number of launches when last unplugged.
2389                 */
2390                int mUnpluggedLaunches;
2391
2392                Serv() {
2393                    mUnpluggables.add(this);
2394                }
2395
2396                public void unplug(long batteryUptime, long batteryRealtime) {
2397                    mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
2398                    mUnpluggedStarts = mStarts;
2399                    mUnpluggedLaunches = mLaunches;
2400                }
2401
2402                public void plug(long batteryUptime, long batteryRealtime) {
2403                }
2404
2405                void readFromParcelLocked(Parcel in) {
2406                    mStartTime = in.readLong();
2407                    mRunningSince = in.readLong();
2408                    mRunning = in.readInt() != 0;
2409                    mStarts = in.readInt();
2410                    mLaunchedTime = in.readLong();
2411                    mLaunchedSince = in.readLong();
2412                    mLaunched = in.readInt() != 0;
2413                    mLaunches = in.readInt();
2414                    mLoadedStartTime = in.readLong();
2415                    mLoadedStarts = in.readInt();
2416                    mLoadedLaunches = in.readInt();
2417                    mLastStartTime = in.readLong();
2418                    mLastStarts = in.readInt();
2419                    mLastLaunches = in.readInt();
2420                    mUnpluggedStartTime = in.readLong();
2421                    mUnpluggedStarts = in.readInt();
2422                    mUnpluggedLaunches = in.readInt();
2423                }
2424
2425                void writeToParcelLocked(Parcel out) {
2426                    out.writeLong(mStartTime);
2427                    out.writeLong(mRunningSince);
2428                    out.writeInt(mRunning ? 1 : 0);
2429                    out.writeInt(mStarts);
2430                    out.writeLong(mLaunchedTime);
2431                    out.writeLong(mLaunchedSince);
2432                    out.writeInt(mLaunched ? 1 : 0);
2433                    out.writeInt(mLaunches);
2434                    out.writeLong(mLoadedStartTime);
2435                    out.writeInt(mLoadedStarts);
2436                    out.writeInt(mLoadedLaunches);
2437                    out.writeLong(mLastStartTime);
2438                    out.writeInt(mLastStarts);
2439                    out.writeInt(mLastLaunches);
2440                    out.writeLong(mUnpluggedStartTime);
2441                    out.writeInt(mUnpluggedStarts);
2442                    out.writeInt(mUnpluggedLaunches);
2443                }
2444
2445                long getLaunchTimeToNowLocked(long batteryUptime) {
2446                    if (!mLaunched) return mLaunchedTime;
2447                    return mLaunchedTime + batteryUptime - mLaunchedSince;
2448                }
2449
2450                long getStartTimeToNowLocked(long batteryUptime) {
2451                    if (!mRunning) return mStartTime;
2452                    return mStartTime + batteryUptime - mRunningSince;
2453                }
2454
2455                public void startLaunchedLocked() {
2456                    if (!mLaunched) {
2457                        mLaunches++;
2458                        mLaunchedSince = getBatteryUptimeLocked();
2459                        mLaunched = true;
2460                    }
2461                }
2462
2463                public void stopLaunchedLocked() {
2464                    if (mLaunched) {
2465                        long time = getBatteryUptimeLocked() - mLaunchedSince;
2466                        if (time > 0) {
2467                            mLaunchedTime += time;
2468                        } else {
2469                            mLaunches--;
2470                        }
2471                        mLaunched = false;
2472                    }
2473                }
2474
2475                public void startRunningLocked() {
2476                    if (!mRunning) {
2477                        mStarts++;
2478                        mRunningSince = getBatteryUptimeLocked();
2479                        mRunning = true;
2480                    }
2481                }
2482
2483                public void stopRunningLocked() {
2484                    if (mRunning) {
2485                        long time = getBatteryUptimeLocked() - mRunningSince;
2486                        if (time > 0) {
2487                            mStartTime += time;
2488                        } else {
2489                            mStarts--;
2490                        }
2491                        mRunning = false;
2492                    }
2493                }
2494
2495                public BatteryStatsImpl getBatteryStats() {
2496                    return BatteryStatsImpl.this;
2497                }
2498
2499                @Override
2500                public int getLaunches(int which) {
2501                    int val;
2502
2503                    if (which == STATS_LAST) {
2504                        val = mLastLaunches;
2505                    } else {
2506                        val = mLaunches;
2507                        if (which == STATS_CURRENT) {
2508                            val -= mLoadedLaunches;
2509                        } else if (which == STATS_UNPLUGGED) {
2510                            val -= mUnpluggedLaunches;
2511                        }
2512                    }
2513
2514                    return val;
2515                }
2516
2517                @Override
2518                public long getStartTime(long now, int which) {
2519                    long val;
2520                    if (which == STATS_LAST) {
2521                        val = mLastStartTime;
2522                    } else {
2523                        val = getStartTimeToNowLocked(now);
2524                        if (which == STATS_CURRENT) {
2525                            val -= mLoadedStartTime;
2526                        } else if (which == STATS_UNPLUGGED) {
2527                            val -= mUnpluggedStartTime;
2528                        }
2529                    }
2530
2531                    return val;
2532                }
2533
2534                @Override
2535                public int getStarts(int which) {
2536                    int val;
2537                    if (which == STATS_LAST) {
2538                        val = mLastStarts;
2539                    } else {
2540                        val = mStarts;
2541                        if (which == STATS_CURRENT) {
2542                            val -= mLoadedStarts;
2543                        } else if (which == STATS_UNPLUGGED) {
2544                            val -= mUnpluggedStarts;
2545                        }
2546                    }
2547
2548                    return val;
2549                }
2550            }
2551
2552            public BatteryStatsImpl getBatteryStats() {
2553                return BatteryStatsImpl.this;
2554            }
2555
2556            public void incWakeupsLocked() {
2557                mWakeups++;
2558            }
2559
2560            final Serv newServiceStatsLocked() {
2561                return new Serv();
2562            }
2563        }
2564
2565        /**
2566         * Retrieve the statistics object for a particular process, creating
2567         * if needed.
2568         */
2569        public Proc getProcessStatsLocked(String name) {
2570            Proc ps = mProcessStats.get(name);
2571            if (ps == null) {
2572                ps = new Proc();
2573                mProcessStats.put(name, ps);
2574            }
2575
2576            return ps;
2577        }
2578
2579        /**
2580         * Retrieve the statistics object for a particular service, creating
2581         * if needed.
2582         */
2583        public Pkg getPackageStatsLocked(String name) {
2584            Pkg ps = mPackageStats.get(name);
2585            if (ps == null) {
2586                ps = new Pkg();
2587                mPackageStats.put(name, ps);
2588            }
2589
2590            return ps;
2591        }
2592
2593        /**
2594         * Retrieve the statistics object for a particular service, creating
2595         * if needed.
2596         */
2597        public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
2598            Pkg ps = getPackageStatsLocked(pkg);
2599            Pkg.Serv ss = ps.mServiceStats.get(serv);
2600            if (ss == null) {
2601                ss = ps.newServiceStatsLocked();
2602                ps.mServiceStats.put(serv, ss);
2603            }
2604
2605            return ss;
2606        }
2607
2608        public StopwatchTimer getWakeTimerLocked(String name, int type) {
2609            Wakelock wl = mWakelockStats.get(name);
2610            if (wl == null) {
2611                if (mWakelockStats.size() > MAX_WAKELOCKS_PER_UID) {
2612                    name = BATCHED_WAKELOCK_NAME;
2613                    wl = mWakelockStats.get(name);
2614                }
2615                if (wl == null) {
2616                    wl = new Wakelock();
2617                    mWakelockStats.put(name, wl);
2618                }
2619            }
2620            StopwatchTimer t = null;
2621            switch (type) {
2622                case WAKE_TYPE_PARTIAL:
2623                    t = wl.mTimerPartial;
2624                    if (t == null) {
2625                        t = new StopwatchTimer(WAKE_TYPE_PARTIAL, mPartialTimers, mUnpluggables);
2626                        wl.mTimerPartial = t;
2627                    }
2628                    return t;
2629                case WAKE_TYPE_FULL:
2630                    t = wl.mTimerFull;
2631                    if (t == null) {
2632                        t = new StopwatchTimer(WAKE_TYPE_FULL, mFullTimers, mUnpluggables);
2633                        wl.mTimerFull = t;
2634                    }
2635                    return t;
2636                case WAKE_TYPE_WINDOW:
2637                    t = wl.mTimerWindow;
2638                    if (t == null) {
2639                        t = new StopwatchTimer(WAKE_TYPE_WINDOW, mWindowTimers, mUnpluggables);
2640                        wl.mTimerWindow = t;
2641                    }
2642                    return t;
2643                default:
2644                    throw new IllegalArgumentException("type=" + type);
2645            }
2646        }
2647
2648        public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
2649            Sensor se = mSensorStats.get(sensor);
2650            if (se == null) {
2651                if (!create) {
2652                    return null;
2653                }
2654                se = new Sensor(sensor);
2655                mSensorStats.put(sensor, se);
2656            }
2657            StopwatchTimer t = se.mTimer;
2658            if (t != null) {
2659                return t;
2660            }
2661            ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
2662            if (timers == null) {
2663                timers = new ArrayList<StopwatchTimer>();
2664                mSensorTimers.put(sensor, timers);
2665            }
2666            t = new StopwatchTimer(BatteryStats.SENSOR, timers, mUnpluggables);
2667            se.mTimer = t;
2668            return t;
2669        }
2670
2671        public void noteStartWakeLocked(String name, int type) {
2672            StopwatchTimer t = getWakeTimerLocked(name, type);
2673            if (t != null) {
2674                t.startRunningLocked(BatteryStatsImpl.this);
2675            }
2676        }
2677
2678        public void noteStopWakeLocked(String name, int type) {
2679            StopwatchTimer t = getWakeTimerLocked(name, type);
2680            if (t != null) {
2681                t.stopRunningLocked(BatteryStatsImpl.this);
2682            }
2683        }
2684
2685        public void noteStartSensor(int sensor) {
2686            StopwatchTimer t = getSensorTimerLocked(sensor, true);
2687            if (t != null) {
2688                t.startRunningLocked(BatteryStatsImpl.this);
2689            }
2690        }
2691
2692        public void noteStopSensor(int sensor) {
2693            // Don't create a timer if one doesn't already exist
2694            StopwatchTimer t = getSensorTimerLocked(sensor, false);
2695            if (t != null) {
2696                t.stopRunningLocked(BatteryStatsImpl.this);
2697            }
2698        }
2699
2700        public void noteStartGps() {
2701            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
2702            if (t != null) {
2703                t.startRunningLocked(BatteryStatsImpl.this);
2704            }
2705        }
2706
2707        public void noteStopGps() {
2708            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
2709            if (t != null) {
2710                t.stopRunningLocked(BatteryStatsImpl.this);
2711            }
2712        }
2713
2714        public BatteryStatsImpl getBatteryStats() {
2715            return BatteryStatsImpl.this;
2716        }
2717    }
2718
2719    public BatteryStatsImpl(String filename) {
2720        mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
2721        mStartCount++;
2722        mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables);
2723        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
2724            mScreenBrightnessTimer[i] = new StopwatchTimer(-100-i, null, mUnpluggables);
2725        }
2726        mInputEventCounter = new Counter(mUnpluggables);
2727        mPhoneOnTimer = new StopwatchTimer(-2, null, mUnpluggables);
2728        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
2729            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(-200-i, null, mUnpluggables);
2730        }
2731        mPhoneSignalScanningTimer = new StopwatchTimer(-200+1, null, mUnpluggables);
2732        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
2733            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(-300-i, null, mUnpluggables);
2734        }
2735        mWifiOnTimer = new StopwatchTimer(-3, null, mUnpluggables);
2736        mWifiRunningTimer = new StopwatchTimer(-4, null, mUnpluggables);
2737        mBluetoothOnTimer = new StopwatchTimer(-5, null, mUnpluggables);
2738        mAudioOnTimer = new StopwatchTimer(-6, null, mUnpluggables);
2739        mOnBattery = mOnBatteryInternal = false;
2740        mTrackBatteryPastUptime = 0;
2741        mTrackBatteryPastRealtime = 0;
2742        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
2743        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
2744        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
2745        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
2746        mDischargeStartLevel = 0;
2747        mDischargeCurrentLevel = 0;
2748    }
2749
2750    public BatteryStatsImpl(Parcel p) {
2751        mFile = null;
2752        readFromParcel(p);
2753    }
2754
2755    public void setNumSpeedSteps(int steps) {
2756        if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
2757    }
2758
2759    public void setRadioScanningTimeout(long timeout) {
2760        if (mPhoneSignalScanningTimer != null) {
2761            mPhoneSignalScanningTimer.setTimeout(timeout);
2762        }
2763    }
2764
2765    @Override
2766    public int getStartCount() {
2767        return mStartCount;
2768    }
2769
2770    public boolean isOnBattery() {
2771        return mOnBattery;
2772    }
2773
2774    public void setOnBattery(boolean onBattery, int level) {
2775        synchronized(this) {
2776            updateKernelWakelocksLocked();
2777            if (mOnBattery != onBattery) {
2778                mOnBattery = mOnBatteryInternal = onBattery;
2779
2780                long uptime = SystemClock.uptimeMillis() * 1000;
2781                long mSecRealtime = SystemClock.elapsedRealtime();
2782                long realtime = mSecRealtime * 1000;
2783                if (onBattery) {
2784                    mTrackBatteryUptimeStart = uptime;
2785                    mTrackBatteryRealtimeStart = realtime;
2786                    mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
2787                    mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
2788                    mDischargeCurrentLevel = mDischargeStartLevel = level;
2789                    doUnplug(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
2790                } else {
2791                    mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
2792                    mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
2793                    mDischargeCurrentLevel = level;
2794                    doPlug(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
2795                }
2796                if ((mLastWriteTime + (60 * 1000)) < mSecRealtime) {
2797                    if (mFile != null) {
2798                        writeLocked();
2799                    }
2800                }
2801            }
2802        }
2803    }
2804
2805    public void recordCurrentLevel(int level) {
2806        mDischargeCurrentLevel = level;
2807    }
2808
2809    public void updateKernelWakelocksLocked() {
2810        Map<String, KernelWakelockStats> m = readKernelWakelockStats();
2811
2812        if (m == null) {
2813            // Not crashing might make board bringup easier.
2814            Slog.w(TAG, "Couldn't get kernel wake lock stats");
2815            return;
2816        }
2817
2818        for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
2819            String name = ent.getKey();
2820            KernelWakelockStats kws = ent.getValue();
2821
2822            SamplingTimer kwlt = mKernelWakelockStats.get(name);
2823            if (kwlt == null) {
2824                kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
2825                        true /* track reported values */);
2826                mKernelWakelockStats.put(name, kwlt);
2827            }
2828            kwlt.updateCurrentReportedCount(kws.mCount);
2829            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
2830            kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
2831        }
2832
2833        if (m.size() != mKernelWakelockStats.size()) {
2834            // Set timers to stale if they didn't appear in /proc/wakelocks this time.
2835            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
2836                SamplingTimer st = ent.getValue();
2837                if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
2838                    st.setStale();
2839                }
2840            }
2841        }
2842    }
2843
2844    public long getAwakeTimeBattery() {
2845        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
2846    }
2847
2848    public long getAwakeTimePlugged() {
2849        return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
2850    }
2851
2852    @Override
2853    public long computeUptime(long curTime, int which) {
2854        switch (which) {
2855            case STATS_TOTAL: return mUptime + (curTime-mUptimeStart);
2856            case STATS_LAST: return mLastUptime;
2857            case STATS_CURRENT: return (curTime-mUptimeStart);
2858            case STATS_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
2859        }
2860        return 0;
2861    }
2862
2863    @Override
2864    public long computeRealtime(long curTime, int which) {
2865        switch (which) {
2866            case STATS_TOTAL: return mRealtime + (curTime-mRealtimeStart);
2867            case STATS_LAST: return mLastRealtime;
2868            case STATS_CURRENT: return (curTime-mRealtimeStart);
2869            case STATS_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
2870        }
2871        return 0;
2872    }
2873
2874    @Override
2875    public long computeBatteryUptime(long curTime, int which) {
2876        switch (which) {
2877            case STATS_TOTAL:
2878                return mBatteryUptime + getBatteryUptime(curTime);
2879            case STATS_LAST:
2880                return mBatteryLastUptime;
2881            case STATS_CURRENT:
2882                return getBatteryUptime(curTime);
2883            case STATS_UNPLUGGED:
2884                return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
2885        }
2886        return 0;
2887    }
2888
2889    @Override
2890    public long computeBatteryRealtime(long curTime, int which) {
2891        switch (which) {
2892            case STATS_TOTAL:
2893                return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
2894            case STATS_LAST:
2895                return mBatteryLastRealtime;
2896            case STATS_CURRENT:
2897                return getBatteryRealtimeLocked(curTime);
2898            case STATS_UNPLUGGED:
2899                return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
2900        }
2901        return 0;
2902    }
2903
2904    long getBatteryUptimeLocked(long curTime) {
2905        long time = mTrackBatteryPastUptime;
2906        if (mOnBatteryInternal) {
2907            time += curTime - mTrackBatteryUptimeStart;
2908        }
2909        return time;
2910    }
2911
2912    long getBatteryUptimeLocked() {
2913        return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
2914    }
2915
2916    @Override
2917    public long getBatteryUptime(long curTime) {
2918        return getBatteryUptimeLocked(curTime);
2919    }
2920
2921    long getBatteryRealtimeLocked(long curTime) {
2922        long time = mTrackBatteryPastRealtime;
2923        if (mOnBatteryInternal) {
2924            time += curTime - mTrackBatteryRealtimeStart;
2925        }
2926        return time;
2927    }
2928
2929    @Override
2930    public long getBatteryRealtime(long curTime) {
2931        return getBatteryRealtimeLocked(curTime);
2932    }
2933
2934    private long getTcpBytes(long current, long[] dataBytes, int which) {
2935        if (which == STATS_LAST) {
2936            return dataBytes[STATS_LAST];
2937        } else {
2938            if (which == STATS_UNPLUGGED) {
2939                if (dataBytes[STATS_UNPLUGGED] < 0) {
2940                    return dataBytes[STATS_LAST];
2941                } else {
2942                    return current - dataBytes[STATS_UNPLUGGED];
2943                }
2944            } else if (which == STATS_TOTAL) {
2945                return (current - dataBytes[STATS_CURRENT]) + dataBytes[STATS_TOTAL];
2946            }
2947            return current - dataBytes[STATS_CURRENT];
2948        }
2949    }
2950
2951    /** Only STATS_UNPLUGGED works properly */
2952    public long getMobileTcpBytesSent(int which) {
2953        return getTcpBytes(TrafficStats.getMobileTxBytes(), mMobileDataTx, which);
2954    }
2955
2956    /** Only STATS_UNPLUGGED works properly */
2957    public long getMobileTcpBytesReceived(int which) {
2958        return getTcpBytes(TrafficStats.getMobileRxBytes(), mMobileDataRx, which);
2959    }
2960
2961    /** Only STATS_UNPLUGGED works properly */
2962    public long getTotalTcpBytesSent(int which) {
2963        return getTcpBytes(TrafficStats.getTotalTxBytes(), mTotalDataTx, which);
2964    }
2965
2966    /** Only STATS_UNPLUGGED works properly */
2967    public long getTotalTcpBytesReceived(int which) {
2968        return getTcpBytes(TrafficStats.getTotalRxBytes(), mTotalDataRx, which);
2969    }
2970
2971    @Override
2972    public int getDischargeStartLevel() {
2973        synchronized(this) {
2974            return getDischargeStartLevelLocked();
2975        }
2976    }
2977
2978    public int getDischargeStartLevelLocked() {
2979            return mDischargeStartLevel;
2980    }
2981
2982    @Override
2983    public int getDischargeCurrentLevel() {
2984        synchronized(this) {
2985            return getDischargeCurrentLevelLocked();
2986        }
2987    }
2988
2989    public int getDischargeCurrentLevelLocked() {
2990            return mDischargeCurrentLevel;
2991    }
2992
2993    @Override
2994    public int getCpuSpeedSteps() {
2995        return sNumSpeedSteps;
2996    }
2997
2998    /**
2999     * Retrieve the statistics object for a particular uid, creating if needed.
3000     */
3001    public Uid getUidStatsLocked(int uid) {
3002        Uid u = mUidStats.get(uid);
3003        if (u == null) {
3004            u = new Uid(uid);
3005            mUidStats.put(uid, u);
3006        }
3007        return u;
3008    }
3009
3010    /**
3011     * Remove the statistics object for a particular uid.
3012     */
3013    public void removeUidStatsLocked(int uid) {
3014        mUidStats.remove(uid);
3015    }
3016
3017    /**
3018     * Retrieve the statistics object for a particular process, creating
3019     * if needed.
3020     */
3021    public Uid.Proc getProcessStatsLocked(int uid, String name) {
3022        Uid u = getUidStatsLocked(uid);
3023        return u.getProcessStatsLocked(name);
3024    }
3025
3026    /**
3027     * Retrieve the statistics object for a particular process, given
3028     * the name of the process.
3029     * @param name process name
3030     * @return the statistics object for the process
3031     */
3032    public Uid.Proc getProcessStatsLocked(String name, int pid) {
3033        int uid;
3034        if (mUidCache.containsKey(name)) {
3035            uid = mUidCache.get(name);
3036        } else {
3037            uid = Process.getUidForPid(pid);
3038            mUidCache.put(name, uid);
3039        }
3040        Uid u = getUidStatsLocked(uid);
3041        return u.getProcessStatsLocked(name);
3042    }
3043
3044    /**
3045     * Retrieve the statistics object for a particular process, creating
3046     * if needed.
3047     */
3048    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
3049        Uid u = getUidStatsLocked(uid);
3050        return u.getPackageStatsLocked(pkg);
3051    }
3052
3053    /**
3054     * Retrieve the statistics object for a particular service, creating
3055     * if needed.
3056     */
3057    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
3058        Uid u = getUidStatsLocked(uid);
3059        return u.getServiceStatsLocked(pkg, name);
3060    }
3061
3062    private static JournaledFile makeJournaledFile() {
3063        final String base = "/data/system/device_policies.xml";
3064        return new JournaledFile(new File(base), new File(base + ".tmp"));
3065    }
3066
3067    public void writeLocked() {
3068        if (mFile == null) {
3069            Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
3070            return;
3071        }
3072
3073        try {
3074            FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
3075            Parcel out = Parcel.obtain();
3076            writeSummaryToParcel(out);
3077            stream.write(out.marshall());
3078            out.recycle();
3079
3080            stream.flush();
3081            stream.close();
3082            mFile.commit();
3083
3084            mLastWriteTime = SystemClock.elapsedRealtime();
3085            return;
3086        } catch (IOException e) {
3087            Slog.w("BatteryStats", "Error writing battery statistics", e);
3088        }
3089        mFile.rollback();
3090    }
3091
3092    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
3093        int pos = 0;
3094        int avail = stream.available();
3095        byte[] data = new byte[avail];
3096        while (true) {
3097            int amt = stream.read(data, pos, data.length-pos);
3098            //Log.i("foo", "Read " + amt + " bytes at " + pos
3099            //        + " of avail " + data.length);
3100            if (amt <= 0) {
3101                //Log.i("foo", "**** FINISHED READING: pos=" + pos
3102                //        + " len=" + data.length);
3103                return data;
3104            }
3105            pos += amt;
3106            avail = stream.available();
3107            if (avail > data.length-pos) {
3108                byte[] newData = new byte[pos+avail];
3109                System.arraycopy(data, 0, newData, 0, pos);
3110                data = newData;
3111            }
3112        }
3113    }
3114
3115    public void readLocked() {
3116        if (mFile == null) {
3117            Slog.w("BatteryStats", "readLocked: no file associated with this instance");
3118            return;
3119        }
3120
3121        mUidStats.clear();
3122
3123        try {
3124            File file = mFile.chooseForRead();
3125            if (!file.exists()) {
3126                return;
3127            }
3128            FileInputStream stream = new FileInputStream(file);
3129
3130            byte[] raw = readFully(stream);
3131            Parcel in = Parcel.obtain();
3132            in.unmarshall(raw, 0, raw.length);
3133            in.setDataPosition(0);
3134            stream.close();
3135
3136            readSummaryFromParcel(in);
3137        } catch(java.io.IOException e) {
3138            Slog.e("BatteryStats", "Error reading battery statistics", e);
3139        }
3140    }
3141
3142    public int describeContents() {
3143        return 0;
3144    }
3145
3146    private void readSummaryFromParcel(Parcel in) {
3147        final int version = in.readInt();
3148        if (version != VERSION) {
3149            Slog.w("BatteryStats", "readFromParcel: version got " + version
3150                + ", expected " + VERSION + "; erasing old stats");
3151            return;
3152        }
3153
3154        mStartCount = in.readInt();
3155        mBatteryUptime = in.readLong();
3156        mBatteryLastUptime = in.readLong();
3157        mBatteryRealtime = in.readLong();
3158        mBatteryLastRealtime = in.readLong();
3159        mUptime = in.readLong();
3160        mLastUptime = in.readLong();
3161        mRealtime = in.readLong();
3162        mLastRealtime = in.readLong();
3163        mDischargeStartLevel = in.readInt();
3164        mDischargeCurrentLevel = in.readInt();
3165
3166        mStartCount++;
3167
3168        mScreenOn = false;
3169        mScreenOnTimer.readSummaryFromParcelLocked(in);
3170        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3171            mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
3172        }
3173        mInputEventCounter.readSummaryFromParcelLocked(in);
3174        mPhoneOn = false;
3175        mPhoneOnTimer.readSummaryFromParcelLocked(in);
3176        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3177            mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
3178        }
3179        mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
3180        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3181            mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
3182        }
3183        mWifiOn = false;
3184        mWifiOnTimer.readSummaryFromParcelLocked(in);
3185        mWifiRunning = false;
3186        mWifiRunningTimer.readSummaryFromParcelLocked(in);
3187        mBluetoothOn = false;
3188        mBluetoothOnTimer.readSummaryFromParcelLocked(in);
3189
3190        int NKW = in.readInt();
3191        if (NKW > 10000) {
3192            Slog.w(TAG, "File corrupt: too many kernel wake locks " + NKW);
3193            return;
3194        }
3195        for (int ikw = 0; ikw < NKW; ikw++) {
3196            if (in.readInt() != 0) {
3197                String kwltName = in.readString();
3198                getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
3199            }
3200        }
3201
3202        sNumSpeedSteps = in.readInt();
3203
3204        final int NU = in.readInt();
3205        if (NU > 10000) {
3206            Slog.w(TAG, "File corrupt: too many uids " + NU);
3207            return;
3208        }
3209        for (int iu = 0; iu < NU; iu++) {
3210            int uid = in.readInt();
3211            Uid u = new Uid(uid);
3212            mUidStats.put(uid, u);
3213
3214            u.mWifiTurnedOn = false;
3215            u.mWifiTurnedOnTimer.readSummaryFromParcelLocked(in);
3216            u.mFullWifiLockOut = false;
3217            u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
3218            u.mAudioTurnedOn = false;
3219            u.mAudioTurnedOnTimer.readSummaryFromParcelLocked(in);
3220            u.mVideoTurnedOn = false;
3221            u.mVideoTurnedOnTimer.readSummaryFromParcelLocked(in);
3222            u.mScanWifiLockOut = false;
3223            u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
3224            u.mWifiMulticastEnabled = false;
3225            u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
3226
3227            if (in.readInt() != 0) {
3228                if (u.mUserActivityCounters == null) {
3229                    u.initUserActivityLocked();
3230                }
3231                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
3232                    u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
3233                }
3234            }
3235
3236            int NW = in.readInt();
3237            if (NW > 10000) {
3238                Slog.w(TAG, "File corrupt: too many wake locks " + NW);
3239                return;
3240            }
3241            for (int iw = 0; iw < NW; iw++) {
3242                String wlName = in.readString();
3243                if (in.readInt() != 0) {
3244                    u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
3245                }
3246                if (in.readInt() != 0) {
3247                    u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
3248                }
3249                if (in.readInt() != 0) {
3250                    u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
3251                }
3252            }
3253
3254            int NP = in.readInt();
3255            if (NP > 10000) {
3256                Slog.w(TAG, "File corrupt: too many sensors " + NP);
3257                return;
3258            }
3259            for (int is = 0; is < NP; is++) {
3260                int seNumber = in.readInt();
3261                if (in.readInt() != 0) {
3262                    u.getSensorTimerLocked(seNumber, true)
3263                            .readSummaryFromParcelLocked(in);
3264                }
3265            }
3266
3267            NP = in.readInt();
3268            if (NP > 10000) {
3269                Slog.w(TAG, "File corrupt: too many processes " + NP);
3270                return;
3271            }
3272            for (int ip = 0; ip < NP; ip++) {
3273                String procName = in.readString();
3274                Uid.Proc p = u.getProcessStatsLocked(procName);
3275                p.mUserTime = p.mLoadedUserTime = in.readLong();
3276                p.mLastUserTime = in.readLong();
3277                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
3278                p.mLastSystemTime = in.readLong();
3279                p.mStarts = p.mLoadedStarts = in.readInt();
3280                p.mLastStarts = in.readInt();
3281            }
3282
3283            NP = in.readInt();
3284            if (NP > 10000) {
3285                Slog.w(TAG, "File corrupt: too many packages " + NP);
3286                return;
3287            }
3288            for (int ip = 0; ip < NP; ip++) {
3289                String pkgName = in.readString();
3290                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
3291                p.mWakeups = p.mLoadedWakeups = in.readInt();
3292                p.mLastWakeups = in.readInt();
3293                final int NS = in.readInt();
3294                for (int is = 0; is < NS; is++) {
3295                    String servName = in.readString();
3296                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
3297                    s.mStartTime = s.mLoadedStartTime = in.readLong();
3298                    s.mLastStartTime = in.readLong();
3299                    s.mStarts = s.mLoadedStarts = in.readInt();
3300                    s.mLastStarts = in.readInt();
3301                    s.mLaunches = s.mLoadedLaunches = in.readInt();
3302                    s.mLastLaunches = in.readInt();
3303                }
3304            }
3305
3306            u.mLoadedTcpBytesReceived = in.readLong();
3307            u.mLoadedTcpBytesSent = in.readLong();
3308        }
3309    }
3310
3311    /**
3312     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
3313     * disk.  This format does not allow a lossless round-trip.
3314     *
3315     * @param out the Parcel to be written to.
3316     */
3317    public void writeSummaryToParcel(Parcel out) {
3318        final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
3319        final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
3320        final long NOW = getBatteryUptimeLocked(NOW_SYS);
3321        final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
3322
3323        out.writeInt(VERSION);
3324
3325        out.writeInt(mStartCount);
3326        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_TOTAL));
3327        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_CURRENT));
3328        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_TOTAL));
3329        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_CURRENT));
3330        out.writeLong(computeUptime(NOW_SYS, STATS_TOTAL));
3331        out.writeLong(computeUptime(NOW_SYS, STATS_CURRENT));
3332        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_TOTAL));
3333        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_CURRENT));
3334        out.writeInt(mDischargeStartLevel);
3335        out.writeInt(mDischargeCurrentLevel);
3336
3337
3338        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3339        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3340            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
3341        }
3342        mInputEventCounter.writeSummaryFromParcelLocked(out);
3343        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3344        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3345            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
3346        }
3347        mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3348        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3349            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
3350        }
3351        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3352        mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3353        mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3354
3355        out.writeInt(mKernelWakelockStats.size());
3356        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
3357            Timer kwlt = ent.getValue();
3358            if (kwlt != null) {
3359                out.writeInt(1);
3360                out.writeString(ent.getKey());
3361                ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
3362            } else {
3363                out.writeInt(0);
3364            }
3365        }
3366
3367        out.writeInt(sNumSpeedSteps);
3368        final int NU = mUidStats.size();
3369        out.writeInt(NU);
3370        for (int iu = 0; iu < NU; iu++) {
3371            out.writeInt(mUidStats.keyAt(iu));
3372            Uid u = mUidStats.valueAt(iu);
3373
3374            u.mWifiTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3375            u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3376            u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3377            u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3378            u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3379            u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3380
3381            if (u.mUserActivityCounters == null) {
3382                out.writeInt(0);
3383            } else {
3384                out.writeInt(1);
3385                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
3386                    u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
3387                }
3388            }
3389
3390            int NW = u.mWakelockStats.size();
3391            out.writeInt(NW);
3392            if (NW > 0) {
3393                for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
3394                        : u.mWakelockStats.entrySet()) {
3395                    out.writeString(ent.getKey());
3396                    Uid.Wakelock wl = ent.getValue();
3397                    if (wl.mTimerFull != null) {
3398                        out.writeInt(1);
3399                        wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
3400                    } else {
3401                        out.writeInt(0);
3402                    }
3403                    if (wl.mTimerPartial != null) {
3404                        out.writeInt(1);
3405                        wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
3406                    } else {
3407                        out.writeInt(0);
3408                    }
3409                    if (wl.mTimerWindow != null) {
3410                        out.writeInt(1);
3411                        wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
3412                    } else {
3413                        out.writeInt(0);
3414                    }
3415                }
3416            }
3417
3418            int NSE = u.mSensorStats.size();
3419            out.writeInt(NSE);
3420            if (NSE > 0) {
3421                for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
3422                        : u.mSensorStats.entrySet()) {
3423                    out.writeInt(ent.getKey());
3424                    Uid.Sensor se = ent.getValue();
3425                    if (se.mTimer != null) {
3426                        out.writeInt(1);
3427                        se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3428                    } else {
3429                        out.writeInt(0);
3430                    }
3431                }
3432            }
3433
3434            int NP = u.mProcessStats.size();
3435            out.writeInt(NP);
3436            if (NP > 0) {
3437                for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
3438                    : u.mProcessStats.entrySet()) {
3439                    out.writeString(ent.getKey());
3440                    Uid.Proc ps = ent.getValue();
3441                    out.writeLong(ps.mUserTime);
3442                    out.writeLong(ps.mUserTime - ps.mLoadedUserTime);
3443                    out.writeLong(ps.mSystemTime);
3444                    out.writeLong(ps.mSystemTime - ps.mLoadedSystemTime);
3445                    out.writeInt(ps.mStarts);
3446                    out.writeInt(ps.mStarts - ps.mLoadedStarts);
3447                }
3448            }
3449
3450            NP = u.mPackageStats.size();
3451            out.writeInt(NP);
3452            if (NP > 0) {
3453                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
3454                    : u.mPackageStats.entrySet()) {
3455                    out.writeString(ent.getKey());
3456                    Uid.Pkg ps = ent.getValue();
3457                    out.writeInt(ps.mWakeups);
3458                    out.writeInt(ps.mWakeups - ps.mLoadedWakeups);
3459                    final int NS = ps.mServiceStats.size();
3460                    out.writeInt(NS);
3461                    if (NS > 0) {
3462                        for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
3463                                : ps.mServiceStats.entrySet()) {
3464                            out.writeString(sent.getKey());
3465                            BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
3466                            long time = ss.getStartTimeToNowLocked(NOW);
3467                            out.writeLong(time);
3468                            out.writeLong(time - ss.mLoadedStartTime);
3469                            out.writeInt(ss.mStarts);
3470                            out.writeInt(ss.mStarts - ss.mLoadedStarts);
3471                            out.writeInt(ss.mLaunches);
3472                            out.writeInt(ss.mLaunches - ss.mLoadedLaunches);
3473                        }
3474                    }
3475                }
3476            }
3477
3478            out.writeLong(u.getTcpBytesReceived(STATS_TOTAL));
3479            out.writeLong(u.getTcpBytesSent(STATS_TOTAL));
3480        }
3481    }
3482
3483    public void readFromParcel(Parcel in) {
3484        readFromParcelLocked(in);
3485    }
3486
3487    void readFromParcelLocked(Parcel in) {
3488        int magic = in.readInt();
3489        if (magic != MAGIC) {
3490            throw new ParcelFormatException("Bad magic number");
3491        }
3492
3493        mStartCount = in.readInt();
3494        mBatteryUptime = in.readLong();
3495        mBatteryLastUptime = in.readLong();
3496        mBatteryRealtime = in.readLong();
3497        mBatteryLastRealtime = in.readLong();
3498        mScreenOn = false;
3499        mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables, in);
3500        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3501            mScreenBrightnessTimer[i] = new StopwatchTimer(-100-i, null, mUnpluggables, in);
3502        }
3503        mInputEventCounter = new Counter(mUnpluggables, in);
3504        mPhoneOn = false;
3505        mPhoneOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
3506        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3507            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(-200-i, null, mUnpluggables, in);
3508        }
3509        mPhoneSignalScanningTimer = new StopwatchTimer(-200+1, null, mUnpluggables, in);
3510        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3511            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(-300-i, null, mUnpluggables, in);
3512        }
3513        mWifiOn = false;
3514        mWifiOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
3515        mWifiRunning = false;
3516        mWifiRunningTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
3517        mBluetoothOn = false;
3518        mBluetoothOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
3519        mUptime = in.readLong();
3520        mUptimeStart = in.readLong();
3521        mLastUptime = in.readLong();
3522        mRealtime = in.readLong();
3523        mRealtimeStart = in.readLong();
3524        mLastRealtime = in.readLong();
3525        mOnBattery = in.readInt() != 0;
3526        mOnBatteryInternal = false; // we are no longer really running.
3527        mTrackBatteryPastUptime = in.readLong();
3528        mTrackBatteryUptimeStart = in.readLong();
3529        mTrackBatteryPastRealtime = in.readLong();
3530        mTrackBatteryRealtimeStart = in.readLong();
3531        mUnpluggedBatteryUptime = in.readLong();
3532        mUnpluggedBatteryRealtime = in.readLong();
3533        mDischargeStartLevel = in.readInt();
3534        mDischargeCurrentLevel = in.readInt();
3535        mLastWriteTime = in.readLong();
3536
3537        mMobileDataRx[STATS_LAST] = in.readLong();
3538        mMobileDataRx[STATS_UNPLUGGED] = -1;
3539        mMobileDataTx[STATS_LAST] = in.readLong();
3540        mMobileDataTx[STATS_UNPLUGGED] = -1;
3541        mTotalDataRx[STATS_LAST] = in.readLong();
3542        mTotalDataRx[STATS_UNPLUGGED] = -1;
3543        mTotalDataTx[STATS_LAST] = in.readLong();
3544        mTotalDataTx[STATS_UNPLUGGED] = -1;
3545
3546        mRadioDataUptime = in.readLong();
3547        mRadioDataStart = -1;
3548
3549        mBluetoothPingCount = in.readInt();
3550        mBluetoothPingStart = -1;
3551
3552        mKernelWakelockStats.clear();
3553        int NKW = in.readInt();
3554        for (int ikw = 0; ikw < NKW; ikw++) {
3555            if (in.readInt() != 0) {
3556                String wakelockName = in.readString();
3557                in.readInt(); // Extra 0/1 written by Timer.writeTimerToParcel
3558                SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
3559                mKernelWakelockStats.put(wakelockName, kwlt);
3560            }
3561        }
3562
3563        mPartialTimers.clear();
3564        mFullTimers.clear();
3565        mWindowTimers.clear();
3566
3567        sNumSpeedSteps = in.readInt();
3568
3569        int numUids = in.readInt();
3570        mUidStats.clear();
3571        for (int i = 0; i < numUids; i++) {
3572            int uid = in.readInt();
3573            Uid u = new Uid(uid);
3574            u.readFromParcelLocked(mUnpluggables, in);
3575            mUidStats.append(uid, u);
3576        }
3577    }
3578
3579    public void writeToParcel(Parcel out, int flags) {
3580        writeToParcelLocked(out, flags);
3581    }
3582
3583    @SuppressWarnings("unused")
3584    void writeToParcelLocked(Parcel out, int flags) {
3585        final long uSecUptime = SystemClock.uptimeMillis() * 1000;
3586        final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
3587        final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
3588        final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
3589
3590        out.writeInt(MAGIC);
3591        out.writeInt(mStartCount);
3592        out.writeLong(mBatteryUptime);
3593        out.writeLong(mBatteryLastUptime);
3594        out.writeLong(mBatteryRealtime);
3595        out.writeLong(mBatteryLastRealtime);
3596        mScreenOnTimer.writeToParcel(out, batteryRealtime);
3597        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3598            mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
3599        }
3600        mInputEventCounter.writeToParcel(out);
3601        mPhoneOnTimer.writeToParcel(out, batteryRealtime);
3602        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3603            mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
3604        }
3605        mPhoneSignalScanningTimer.writeToParcel(out, batteryRealtime);
3606        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3607            mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
3608        }
3609        mWifiOnTimer.writeToParcel(out, batteryRealtime);
3610        mWifiRunningTimer.writeToParcel(out, batteryRealtime);
3611        mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
3612        out.writeLong(mUptime);
3613        out.writeLong(mUptimeStart);
3614        out.writeLong(mLastUptime);
3615        out.writeLong(mRealtime);
3616        out.writeLong(mRealtimeStart);
3617        out.writeLong(mLastRealtime);
3618        out.writeInt(mOnBattery ? 1 : 0);
3619        out.writeLong(batteryUptime);
3620        out.writeLong(mTrackBatteryUptimeStart);
3621        out.writeLong(batteryRealtime);
3622        out.writeLong(mTrackBatteryRealtimeStart);
3623        out.writeLong(mUnpluggedBatteryUptime);
3624        out.writeLong(mUnpluggedBatteryRealtime);
3625        out.writeInt(mDischargeStartLevel);
3626        out.writeInt(mDischargeCurrentLevel);
3627        out.writeLong(mLastWriteTime);
3628
3629        out.writeLong(getMobileTcpBytesReceived(STATS_UNPLUGGED));
3630        out.writeLong(getMobileTcpBytesSent(STATS_UNPLUGGED));
3631        out.writeLong(getTotalTcpBytesReceived(STATS_UNPLUGGED));
3632        out.writeLong(getTotalTcpBytesSent(STATS_UNPLUGGED));
3633
3634        // Write radio uptime for data
3635        out.writeLong(getRadioDataUptime());
3636
3637        out.writeInt(getBluetoothPingCount());
3638
3639        out.writeInt(mKernelWakelockStats.size());
3640        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
3641            SamplingTimer kwlt = ent.getValue();
3642            if (kwlt != null) {
3643                out.writeInt(1);
3644                out.writeString(ent.getKey());
3645                Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
3646            } else {
3647                out.writeInt(0);
3648            }
3649        }
3650
3651        out.writeInt(sNumSpeedSteps);
3652
3653        int size = mUidStats.size();
3654        out.writeInt(size);
3655        for (int i = 0; i < size; i++) {
3656            out.writeInt(mUidStats.keyAt(i));
3657            Uid uid = mUidStats.valueAt(i);
3658
3659            uid.writeToParcelLocked(out, batteryRealtime);
3660        }
3661    }
3662
3663    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
3664        new Parcelable.Creator<BatteryStatsImpl>() {
3665        public BatteryStatsImpl createFromParcel(Parcel in) {
3666            return new BatteryStatsImpl(in);
3667        }
3668
3669        public BatteryStatsImpl[] newArray(int size) {
3670            return new BatteryStatsImpl[size];
3671        }
3672    };
3673
3674    public void dumpLocked(PrintWriter pw) {
3675        if (DEBUG) {
3676            Printer pr = new PrintWriterPrinter(pw);
3677            pr.println("*** Screen timer:");
3678            mScreenOnTimer.logState(pr, "  ");
3679            for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3680                pr.println("*** Screen brightness #" + i + ":");
3681                mScreenBrightnessTimer[i].logState(pr, "  ");
3682            }
3683            pr.println("*** Input event counter:");
3684            mInputEventCounter.logState(pr, "  ");
3685            pr.println("*** Phone timer:");
3686            mPhoneOnTimer.logState(pr, "  ");
3687            for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3688                pr.println("*** Signal strength #" + i + ":");
3689                mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
3690            }
3691            pr.println("*** Signal scanning :");
3692            mPhoneSignalScanningTimer.logState(pr, "  ");
3693            for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3694                pr.println("*** Data connection type #" + i + ":");
3695                mPhoneDataConnectionsTimer[i].logState(pr, "  ");
3696            }
3697            pr.println("*** Wifi timer:");
3698            mWifiOnTimer.logState(pr, "  ");
3699            pr.println("*** WifiRunning timer:");
3700            mWifiRunningTimer.logState(pr, "  ");
3701            pr.println("*** Bluetooth timer:");
3702            mBluetoothOnTimer.logState(pr, "  ");
3703        }
3704        super.dumpLocked(pw);
3705    }
3706}
3707