BatteryStatsImpl.java revision e5795610bdc97aebfaa863b5134294aed5c7c1f2
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                // Don't go over the end of the buffer
895                if (endIndex < len) {
896                    endIndex++; // endIndex is an exclusive upper bound.
897                }
898
899                String[] nameStringArray = mProcWakelocksName;
900                long[] wlData = mProcWakelocksData;
901                // Stomp out any bad characters since this is from a circular buffer
902                // A corruption is seen sometimes that results in the vm crashing
903                // This should prevent crashes and the line will probably fail to parse
904                for (int j = startIndex; j < endIndex; j++) {
905                    if ((wlBuffer[j] & 0x80) != 0) wlBuffer[j] = (byte) '?';
906                }
907                boolean parsed = Process.parseProcLine(wlBuffer, startIndex, endIndex,
908                        PROC_WAKELOCKS_FORMAT, nameStringArray, wlData, null);
909
910                name = nameStringArray[0];
911                count = (int) wlData[1];
912                // convert nanoseconds to microseconds with rounding.
913                totalTime = (wlData[2] + 500) / 1000;
914
915                if (parsed && name.length() > 0) {
916                    if (!m.containsKey(name)) {
917                        m.put(name, new KernelWakelockStats(count, totalTime,
918                                sKernelWakelockUpdateVersion));
919                        numUpdatedWlNames++;
920                    } else {
921                        KernelWakelockStats kwlStats = m.get(name);
922                        if (kwlStats.mVersion == sKernelWakelockUpdateVersion) {
923                            kwlStats.mCount += count;
924                            kwlStats.mTotalTime += totalTime;
925                        } else {
926                            kwlStats.mCount = count;
927                            kwlStats.mTotalTime = totalTime;
928                            kwlStats.mVersion = sKernelWakelockUpdateVersion;
929                            numUpdatedWlNames++;
930                        }
931                    }
932                }
933                startIndex = endIndex;
934            }
935
936            if (m.size() != numUpdatedWlNames) {
937                // Don't report old data.
938                Iterator<KernelWakelockStats> itr = m.values().iterator();
939                while (itr.hasNext()) {
940                    if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
941                        itr.remove();
942                    }
943                }
944            }
945            return m;
946        }
947    }
948
949    private class KernelWakelockStats {
950        public int mCount;
951        public long mTotalTime;
952        public int mVersion;
953
954        KernelWakelockStats(int count, long totalTime, int version) {
955            mCount = count;
956            mTotalTime = totalTime;
957            mVersion = version;
958        }
959    }
960
961    /*
962     * Get the KernelWakelockTimer associated with name, and create a new one if one
963     * doesn't already exist.
964     */
965    public SamplingTimer getKernelWakelockTimerLocked(String name) {
966        SamplingTimer kwlt = mKernelWakelockStats.get(name);
967        if (kwlt == null) {
968            kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
969                    true /* track reported values */);
970            mKernelWakelockStats.put(name, kwlt);
971        }
972        return kwlt;
973    }
974
975    private void doDataPlug(long[] dataTransfer, long currentBytes) {
976        dataTransfer[STATS_LAST] = dataTransfer[STATS_UNPLUGGED];
977        dataTransfer[STATS_UNPLUGGED] = -1;
978    }
979
980    private void doDataUnplug(long[] dataTransfer, long currentBytes) {
981        dataTransfer[STATS_UNPLUGGED] = currentBytes;
982    }
983
984    /**
985     * Radio uptime in microseconds when transferring data. This value is very approximate.
986     * @return
987     */
988    private long getCurrentRadioDataUptime() {
989        try {
990            File awakeTimeFile = new File("/sys/devices/virtual/net/rmnet0/awake_time_ms");
991            if (!awakeTimeFile.exists()) return 0;
992            BufferedReader br = new BufferedReader(new FileReader(awakeTimeFile));
993            String line = br.readLine();
994            br.close();
995            return Long.parseLong(line) * 1000;
996        } catch (NumberFormatException nfe) {
997            // Nothing
998        } catch (IOException ioe) {
999            // Nothing
1000        }
1001        return 0;
1002    }
1003
1004    /**
1005     * @deprecated use getRadioDataUptime
1006     */
1007    public long getRadioDataUptimeMs() {
1008        return getRadioDataUptime() / 1000;
1009    }
1010
1011    /**
1012     * Returns the duration that the cell radio was up for data transfers.
1013     */
1014    public long getRadioDataUptime() {
1015        if (mRadioDataStart == -1) {
1016            return mRadioDataUptime;
1017        } else {
1018            return getCurrentRadioDataUptime() - mRadioDataStart;
1019        }
1020    }
1021
1022    private int getCurrentBluetoothPingCount() {
1023        if (mBtHeadset != null) {
1024            return mBtHeadset.getBatteryUsageHint();
1025        }
1026        return -1;
1027    }
1028
1029    public int getBluetoothPingCount() {
1030        if (mBluetoothPingStart == -1) {
1031            return mBluetoothPingCount;
1032        } else if (mBtHeadset != null) {
1033            return getCurrentBluetoothPingCount() - mBluetoothPingStart;
1034        }
1035        return 0;
1036    }
1037
1038    public void setBtHeadset(BluetoothHeadset headset) {
1039        if (headset != null && mBtHeadset == null && isOnBattery() && mBluetoothPingStart == -1) {
1040            mBluetoothPingStart = getCurrentBluetoothPingCount();
1041        }
1042        mBtHeadset = headset;
1043    }
1044
1045    public void doUnplug(long batteryUptime, long batteryRealtime) {
1046        for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
1047            Uid u = mUidStats.valueAt(iu);
1048            u.mStartedTcpBytesReceived = TrafficStats.getUidRxBytes(u.mUid);
1049            u.mStartedTcpBytesSent = TrafficStats.getUidTxBytes(u.mUid);
1050            u.mTcpBytesReceivedAtLastUnplug = u.mCurrentTcpBytesReceived;
1051            u.mTcpBytesSentAtLastUnplug = u.mCurrentTcpBytesSent;
1052        }
1053        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
1054            mUnpluggables.get(i).unplug(batteryUptime, batteryRealtime);
1055        }
1056        // Track total mobile data
1057        doDataUnplug(mMobileDataRx, TrafficStats.getMobileRxBytes());
1058        doDataUnplug(mMobileDataTx, TrafficStats.getMobileTxBytes());
1059        doDataUnplug(mTotalDataRx, TrafficStats.getTotalRxBytes());
1060        doDataUnplug(mTotalDataTx, TrafficStats.getTotalTxBytes());
1061        // Track radio awake time
1062        mRadioDataStart = getCurrentRadioDataUptime();
1063        mRadioDataUptime = 0;
1064        // Track bt headset ping count
1065        mBluetoothPingStart = getCurrentBluetoothPingCount();
1066        mBluetoothPingCount = 0;
1067    }
1068
1069    public void doPlug(long batteryUptime, long batteryRealtime) {
1070        for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
1071            Uid u = mUidStats.valueAt(iu);
1072            if (u.mStartedTcpBytesReceived >= 0) {
1073                u.mCurrentTcpBytesReceived = u.computeCurrentTcpBytesReceived();
1074                u.mStartedTcpBytesReceived = -1;
1075            }
1076            if (u.mStartedTcpBytesSent >= 0) {
1077                u.mCurrentTcpBytesSent = u.computeCurrentTcpBytesSent();
1078                u.mStartedTcpBytesSent = -1;
1079            }
1080        }
1081        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
1082            mUnpluggables.get(i).plug(batteryUptime, batteryRealtime);
1083        }
1084        doDataPlug(mMobileDataRx, TrafficStats.getMobileRxBytes());
1085        doDataPlug(mMobileDataTx, TrafficStats.getMobileTxBytes());
1086        doDataPlug(mTotalDataRx, TrafficStats.getTotalRxBytes());
1087        doDataPlug(mTotalDataTx, TrafficStats.getTotalTxBytes());
1088        // Track radio awake time
1089        mRadioDataUptime = getRadioDataUptime();
1090        mRadioDataStart = -1;
1091
1092        // Track bt headset ping count
1093        mBluetoothPingCount = getBluetoothPingCount();
1094        mBluetoothPingStart = -1;
1095    }
1096
1097    public void noteStartGps(int uid) {
1098        getUidStatsLocked(uid).noteStartGps();
1099    }
1100
1101    public void noteStopGps(int uid) {
1102        getUidStatsLocked(uid).noteStopGps();
1103    }
1104
1105    public void noteScreenOnLocked() {
1106        if (!mScreenOn) {
1107            mScreenOn = true;
1108            mScreenOnTimer.startRunningLocked(this);
1109            if (mScreenBrightnessBin >= 0) {
1110                mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
1111            }
1112        }
1113    }
1114
1115    public void noteScreenOffLocked() {
1116        if (mScreenOn) {
1117            mScreenOn = false;
1118            mScreenOnTimer.stopRunningLocked(this);
1119            if (mScreenBrightnessBin >= 0) {
1120                mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
1121            }
1122        }
1123    }
1124
1125    public void noteScreenBrightnessLocked(int brightness) {
1126        // Bin the brightness.
1127        int bin = brightness / (256/NUM_SCREEN_BRIGHTNESS_BINS);
1128        if (bin < 0) bin = 0;
1129        else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
1130        if (mScreenBrightnessBin != bin) {
1131            if (mScreenOn) {
1132                if (mScreenBrightnessBin >= 0) {
1133                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
1134                }
1135                mScreenBrightnessTimer[bin].startRunningLocked(this);
1136            }
1137            mScreenBrightnessBin = bin;
1138        }
1139    }
1140
1141    public void noteInputEventAtomic() {
1142        mInputEventCounter.stepAtomic();
1143    }
1144
1145    public void noteUserActivityLocked(int uid, int event) {
1146        getUidStatsLocked(uid).noteUserActivityLocked(event);
1147    }
1148
1149    public void notePhoneOnLocked() {
1150        if (!mPhoneOn) {
1151            mPhoneOn = true;
1152            mPhoneOnTimer.startRunningLocked(this);
1153        }
1154    }
1155
1156    public void notePhoneOffLocked() {
1157        if (mPhoneOn) {
1158            mPhoneOn = false;
1159            mPhoneOnTimer.stopRunningLocked(this);
1160        }
1161    }
1162
1163    /**
1164     * Telephony stack updates the phone state.
1165     * @param state phone state from ServiceState.getState()
1166     */
1167    public void notePhoneStateLocked(int state) {
1168        int bin = mPhoneSignalStrengthBin;
1169        boolean isAirplaneMode = state == ServiceState.STATE_POWER_OFF;
1170        // Stop all timers
1171        if (isAirplaneMode || state == ServiceState.STATE_OUT_OF_SERVICE) {
1172            for (int i = 0; i < NUM_SIGNAL_STRENGTH_BINS; i++) {
1173                while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
1174                    mPhoneSignalStrengthsTimer[i].stopRunningLocked(this);
1175                }
1176            }
1177        }
1178        // Stop Signal Scanning timer, in case we're going into service
1179        while (mPhoneSignalScanningTimer.isRunningLocked()) {
1180            mPhoneSignalScanningTimer.stopRunningLocked(this);
1181        }
1182
1183        // If we're back in service or continuing in service, restart the old timer.
1184        if (state == ServiceState.STATE_IN_SERVICE) {
1185            if (bin == -1) bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1186            if (!mPhoneSignalStrengthsTimer[bin].isRunningLocked()) {
1187                mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
1188            }
1189        } else if (state == ServiceState.STATE_OUT_OF_SERVICE) {
1190            mPhoneSignalStrengthBin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1191            if (!mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].isRunningLocked()) {
1192                mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].startRunningLocked(this);
1193            }
1194            if (!mPhoneSignalScanningTimer.isRunningLocked()) {
1195                mPhoneSignalScanningTimer.startRunningLocked(this);
1196            }
1197        }
1198        mPhoneServiceState = state;
1199    }
1200
1201    public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
1202        // Bin the strength.
1203        int bin;
1204        if (mPhoneServiceState == ServiceState.STATE_POWER_OFF
1205                || mPhoneServiceState == ServiceState.STATE_OUT_OF_SERVICE) {
1206            // Ignore any signal strength changes when radio was turned off or out of service.
1207            return;
1208        }
1209        if (!signalStrength.isGsm()) {
1210            int dBm = signalStrength.getCdmaDbm();
1211            if (dBm >= -75) bin = SIGNAL_STRENGTH_GREAT;
1212            else if (dBm >= -85) bin = SIGNAL_STRENGTH_GOOD;
1213            else if (dBm >= -95)  bin = SIGNAL_STRENGTH_MODERATE;
1214            else if (dBm >= -100)  bin = SIGNAL_STRENGTH_POOR;
1215            else bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1216        } else {
1217            int asu = signalStrength.getGsmSignalStrength();
1218            if (asu < 0 || asu >= 99) bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1219            else if (asu >= 16) bin = SIGNAL_STRENGTH_GREAT;
1220            else if (asu >= 8)  bin = SIGNAL_STRENGTH_GOOD;
1221            else if (asu >= 4)  bin = SIGNAL_STRENGTH_MODERATE;
1222            else bin = SIGNAL_STRENGTH_POOR;
1223        }
1224        if (mPhoneSignalStrengthBin != bin) {
1225            if (mPhoneSignalStrengthBin >= 0) {
1226                mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this);
1227            }
1228            mPhoneSignalStrengthBin = bin;
1229            mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
1230        }
1231    }
1232
1233    public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData) {
1234        int bin = DATA_CONNECTION_NONE;
1235        if (hasData) {
1236            switch (dataType) {
1237                case TelephonyManager.NETWORK_TYPE_EDGE:
1238                    bin = DATA_CONNECTION_EDGE;
1239                    break;
1240                case TelephonyManager.NETWORK_TYPE_GPRS:
1241                    bin = DATA_CONNECTION_GPRS;
1242                    break;
1243                case TelephonyManager.NETWORK_TYPE_UMTS:
1244                    bin = DATA_CONNECTION_UMTS;
1245                    break;
1246                default:
1247                    bin = DATA_CONNECTION_OTHER;
1248                    break;
1249            }
1250        }
1251        if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
1252        if (mPhoneDataConnectionType != bin) {
1253            if (mPhoneDataConnectionType >= 0) {
1254                mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this);
1255            }
1256            mPhoneDataConnectionType = bin;
1257            mPhoneDataConnectionsTimer[bin].startRunningLocked(this);
1258        }
1259    }
1260
1261    public void noteWifiOnLocked(int uid) {
1262        if (!mWifiOn) {
1263            mWifiOn = true;
1264            mWifiOnTimer.startRunningLocked(this);
1265        }
1266        if (mWifiOnUid != uid) {
1267            if (mWifiOnUid >= 0) {
1268                getUidStatsLocked(mWifiOnUid).noteWifiTurnedOffLocked();
1269            }
1270            mWifiOnUid = uid;
1271            getUidStatsLocked(uid).noteWifiTurnedOnLocked();
1272        }
1273    }
1274
1275    public void noteWifiOffLocked(int uid) {
1276        if (mWifiOn) {
1277            mWifiOn = false;
1278            mWifiOnTimer.stopRunningLocked(this);
1279        }
1280        if (mWifiOnUid >= 0) {
1281            getUidStatsLocked(mWifiOnUid).noteWifiTurnedOffLocked();
1282            mWifiOnUid = -1;
1283        }
1284    }
1285
1286    public void noteAudioOnLocked(int uid) {
1287        if (!mAudioOn) {
1288            mAudioOn = true;
1289            mAudioOnTimer.startRunningLocked(this);
1290        }
1291        getUidStatsLocked(uid).noteAudioTurnedOnLocked();
1292    }
1293
1294    public void noteAudioOffLocked(int uid) {
1295        if (mAudioOn) {
1296            mAudioOn = false;
1297            mAudioOnTimer.stopRunningLocked(this);
1298        }
1299        getUidStatsLocked(uid).noteAudioTurnedOffLocked();
1300    }
1301
1302    public void noteVideoOnLocked(int uid) {
1303        if (!mVideoOn) {
1304            mVideoOn = true;
1305            mVideoOnTimer.startRunningLocked(this);
1306        }
1307        getUidStatsLocked(uid).noteVideoTurnedOnLocked();
1308    }
1309
1310    public void noteVideoOffLocked(int uid) {
1311        if (mVideoOn) {
1312            mVideoOn = false;
1313            mVideoOnTimer.stopRunningLocked(this);
1314        }
1315        getUidStatsLocked(uid).noteVideoTurnedOffLocked();
1316    }
1317
1318    public void noteWifiRunningLocked() {
1319        if (!mWifiRunning) {
1320            mWifiRunning = true;
1321            mWifiRunningTimer.startRunningLocked(this);
1322        }
1323    }
1324
1325    public void noteWifiStoppedLocked() {
1326        if (mWifiRunning) {
1327            mWifiRunning = false;
1328            mWifiRunningTimer.stopRunningLocked(this);
1329        }
1330    }
1331
1332    public void noteBluetoothOnLocked() {
1333        if (!mBluetoothOn) {
1334            mBluetoothOn = true;
1335            mBluetoothOnTimer.startRunningLocked(this);
1336        }
1337    }
1338
1339    public void noteBluetoothOffLocked() {
1340        if (mBluetoothOn) {
1341            mBluetoothOn = false;
1342            mBluetoothOnTimer.stopRunningLocked(this);
1343        }
1344    }
1345
1346    public void noteFullWifiLockAcquiredLocked(int uid) {
1347        getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
1348    }
1349
1350    public void noteFullWifiLockReleasedLocked(int uid) {
1351        getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
1352    }
1353
1354    public void noteScanWifiLockAcquiredLocked(int uid) {
1355        getUidStatsLocked(uid).noteScanWifiLockAcquiredLocked();
1356    }
1357
1358    public void noteScanWifiLockReleasedLocked(int uid) {
1359        getUidStatsLocked(uid).noteScanWifiLockReleasedLocked();
1360    }
1361
1362    public void noteWifiMulticastEnabledLocked(int uid) {
1363        getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
1364    }
1365
1366    public void noteWifiMulticastDisabledLocked(int uid) {
1367        getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
1368    }
1369
1370    @Override public long getScreenOnTime(long batteryRealtime, int which) {
1371        return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
1372    }
1373
1374    @Override public long getScreenBrightnessTime(int brightnessBin,
1375            long batteryRealtime, int which) {
1376        return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
1377                batteryRealtime, which);
1378    }
1379
1380    @Override public int getInputEventCount(int which) {
1381        return mInputEventCounter.getCountLocked(which);
1382    }
1383
1384    @Override public long getPhoneOnTime(long batteryRealtime, int which) {
1385        return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
1386    }
1387
1388    @Override public long getPhoneSignalStrengthTime(int strengthBin,
1389            long batteryRealtime, int which) {
1390        return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
1391                batteryRealtime, which);
1392    }
1393
1394    @Override public long getPhoneSignalScanningTime(
1395            long batteryRealtime, int which) {
1396        return mPhoneSignalScanningTimer.getTotalTimeLocked(
1397                batteryRealtime, which);
1398    }
1399
1400    @Override public int getPhoneSignalStrengthCount(int dataType, int which) {
1401        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
1402    }
1403
1404    @Override public long getPhoneDataConnectionTime(int dataType,
1405            long batteryRealtime, int which) {
1406        return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
1407                batteryRealtime, which);
1408    }
1409
1410    @Override public int getPhoneDataConnectionCount(int dataType, int which) {
1411        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
1412    }
1413
1414    @Override public long getWifiOnTime(long batteryRealtime, int which) {
1415        return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
1416    }
1417
1418    @Override public long getWifiRunningTime(long batteryRealtime, int which) {
1419        return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
1420    }
1421
1422    @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
1423        return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
1424    }
1425
1426    @Override public boolean getIsOnBattery() {
1427        return mOnBattery;
1428    }
1429
1430    @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
1431        return mUidStats;
1432    }
1433
1434    /**
1435     * The statistics associated with a particular uid.
1436     */
1437    public final class Uid extends BatteryStats.Uid {
1438
1439        final int mUid;
1440        long mLoadedTcpBytesReceived;
1441        long mLoadedTcpBytesSent;
1442        long mCurrentTcpBytesReceived;
1443        long mCurrentTcpBytesSent;
1444        long mTcpBytesReceivedAtLastUnplug;
1445        long mTcpBytesSentAtLastUnplug;
1446
1447        // These are not saved/restored when parcelling, since we want
1448        // to return from the parcel with a snapshot of the state.
1449        long mStartedTcpBytesReceived = -1;
1450        long mStartedTcpBytesSent = -1;
1451
1452        boolean mWifiTurnedOn;
1453        StopwatchTimer mWifiTurnedOnTimer;
1454
1455        boolean mFullWifiLockOut;
1456        StopwatchTimer mFullWifiLockTimer;
1457
1458        boolean mScanWifiLockOut;
1459        StopwatchTimer mScanWifiLockTimer;
1460
1461        boolean mWifiMulticastEnabled;
1462        StopwatchTimer mWifiMulticastTimer;
1463
1464        boolean mAudioTurnedOn;
1465        StopwatchTimer mAudioTurnedOnTimer;
1466
1467        boolean mVideoTurnedOn;
1468        StopwatchTimer mVideoTurnedOnTimer;
1469
1470        Counter[] mUserActivityCounters;
1471
1472        /**
1473         * The statistics we have collected for this uid's wake locks.
1474         */
1475        final HashMap<String, Wakelock> mWakelockStats = new HashMap<String, Wakelock>();
1476
1477        /**
1478         * The statistics we have collected for this uid's sensor activations.
1479         */
1480        final HashMap<Integer, Sensor> mSensorStats = new HashMap<Integer, Sensor>();
1481
1482        /**
1483         * The statistics we have collected for this uid's processes.
1484         */
1485        final HashMap<String, Proc> mProcessStats = new HashMap<String, Proc>();
1486
1487        /**
1488         * The statistics we have collected for this uid's processes.
1489         */
1490        final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
1491
1492        public Uid(int uid) {
1493            mUid = uid;
1494            mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables);
1495            mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables);
1496            mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables);
1497            mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
1498                    null, mUnpluggables);
1499            mAudioTurnedOnTimer = new StopwatchTimer(AUDIO_TURNED_ON, null, mUnpluggables);
1500            mVideoTurnedOnTimer = new StopwatchTimer(VIDEO_TURNED_ON, null, mUnpluggables);
1501        }
1502
1503        @Override
1504        public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
1505            return mWakelockStats;
1506        }
1507
1508        @Override
1509        public Map<Integer, ? extends BatteryStats.Uid.Sensor> getSensorStats() {
1510            return mSensorStats;
1511        }
1512
1513        @Override
1514        public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
1515            return mProcessStats;
1516        }
1517
1518        @Override
1519        public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
1520            return mPackageStats;
1521        }
1522
1523        @Override
1524        public int getUid() {
1525            return mUid;
1526        }
1527
1528        @Override
1529        public long getTcpBytesReceived(int which) {
1530            if (which == STATS_LAST) {
1531                return mLoadedTcpBytesReceived;
1532            } else {
1533                long current = computeCurrentTcpBytesReceived();
1534                if (which == STATS_UNPLUGGED) {
1535                    current -= mTcpBytesReceivedAtLastUnplug;
1536                } else if (which == STATS_TOTAL) {
1537                    current += mLoadedTcpBytesReceived;
1538                }
1539                return current;
1540            }
1541        }
1542
1543        public long computeCurrentTcpBytesReceived() {
1544            return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
1545                    ? (TrafficStats.getUidRxBytes(mUid) - mStartedTcpBytesReceived) : 0);
1546        }
1547
1548        @Override
1549        public long getTcpBytesSent(int which) {
1550            if (which == STATS_LAST) {
1551                return mLoadedTcpBytesSent;
1552            } else {
1553                long current = computeCurrentTcpBytesSent();
1554                if (which == STATS_UNPLUGGED) {
1555                    current -= mTcpBytesSentAtLastUnplug;
1556                } else if (which == STATS_TOTAL) {
1557                    current += mLoadedTcpBytesSent;
1558                }
1559                return current;
1560            }
1561        }
1562
1563        @Override
1564        public void noteWifiTurnedOnLocked() {
1565            if (!mWifiTurnedOn) {
1566                mWifiTurnedOn = true;
1567                mWifiTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
1568            }
1569        }
1570
1571        @Override
1572        public void noteWifiTurnedOffLocked() {
1573            if (mWifiTurnedOn) {
1574                mWifiTurnedOn = false;
1575                mWifiTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
1576            }
1577        }
1578
1579        @Override
1580        public void noteFullWifiLockAcquiredLocked() {
1581            if (!mFullWifiLockOut) {
1582                mFullWifiLockOut = true;
1583                mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
1584            }
1585        }
1586
1587        @Override
1588        public void noteVideoTurnedOnLocked() {
1589            if (!mVideoTurnedOn) {
1590                mVideoTurnedOn = true;
1591                mVideoTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
1592            }
1593        }
1594
1595        @Override
1596        public void noteVideoTurnedOffLocked() {
1597            if (mVideoTurnedOn) {
1598                mVideoTurnedOn = false;
1599                mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
1600            }
1601        }
1602
1603        @Override
1604        public void noteAudioTurnedOnLocked() {
1605            if (!mAudioTurnedOn) {
1606                mAudioTurnedOn = true;
1607                mAudioTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
1608            }
1609        }
1610
1611        @Override
1612        public void noteAudioTurnedOffLocked() {
1613            if (mAudioTurnedOn) {
1614                mAudioTurnedOn = false;
1615                mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
1616            }
1617        }
1618
1619        @Override
1620        public void noteFullWifiLockReleasedLocked() {
1621            if (mFullWifiLockOut) {
1622                mFullWifiLockOut = false;
1623                mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
1624            }
1625        }
1626
1627        @Override
1628        public void noteScanWifiLockAcquiredLocked() {
1629            if (!mScanWifiLockOut) {
1630                mScanWifiLockOut = true;
1631                mScanWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
1632            }
1633        }
1634
1635        @Override
1636        public void noteScanWifiLockReleasedLocked() {
1637            if (mScanWifiLockOut) {
1638                mScanWifiLockOut = false;
1639                mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
1640            }
1641        }
1642
1643        @Override
1644        public void noteWifiMulticastEnabledLocked() {
1645            if (!mWifiMulticastEnabled) {
1646                mWifiMulticastEnabled = true;
1647                mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
1648            }
1649        }
1650
1651        @Override
1652        public void noteWifiMulticastDisabledLocked() {
1653            if (mWifiMulticastEnabled) {
1654                mWifiMulticastEnabled = false;
1655                mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
1656            }
1657        }
1658
1659        @Override
1660        public long getWifiTurnedOnTime(long batteryRealtime, int which) {
1661            return mWifiTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
1662        }
1663
1664        @Override
1665        public long getAudioTurnedOnTime(long batteryRealtime, int which) {
1666            return mAudioTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
1667        }
1668
1669        @Override
1670        public long getVideoTurnedOnTime(long batteryRealtime, int which) {
1671            return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
1672        }
1673
1674        @Override
1675        public long getFullWifiLockTime(long batteryRealtime, int which) {
1676            return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
1677        }
1678
1679        @Override
1680        public long getScanWifiLockTime(long batteryRealtime, int which) {
1681            return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
1682        }
1683
1684        @Override
1685        public long getWifiMulticastTime(long batteryRealtime, int which) {
1686            return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime,
1687                                                          which);
1688        }
1689
1690        @Override
1691        public void noteUserActivityLocked(int type) {
1692            if (mUserActivityCounters == null) {
1693                initUserActivityLocked();
1694            }
1695            if (type < 0) type = 0;
1696            else if (type >= NUM_USER_ACTIVITY_TYPES) type = NUM_USER_ACTIVITY_TYPES-1;
1697            mUserActivityCounters[type].stepAtomic();
1698        }
1699
1700        @Override
1701        public boolean hasUserActivity() {
1702            return mUserActivityCounters != null;
1703        }
1704
1705        @Override
1706        public int getUserActivityCount(int type, int which) {
1707            if (mUserActivityCounters == null) {
1708                return 0;
1709            }
1710            return mUserActivityCounters[type].getCountLocked(which);
1711        }
1712
1713        void initUserActivityLocked() {
1714            mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
1715            for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
1716                mUserActivityCounters[i] = new Counter(mUnpluggables);
1717            }
1718        }
1719
1720        public long computeCurrentTcpBytesSent() {
1721            return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
1722                    ? (TrafficStats.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
1723        }
1724
1725        void writeToParcelLocked(Parcel out, long batteryRealtime) {
1726            out.writeInt(mWakelockStats.size());
1727            for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
1728                out.writeString(wakelockEntry.getKey());
1729                Uid.Wakelock wakelock = wakelockEntry.getValue();
1730                wakelock.writeToParcelLocked(out, batteryRealtime);
1731            }
1732
1733            out.writeInt(mSensorStats.size());
1734            for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
1735                out.writeInt(sensorEntry.getKey());
1736                Uid.Sensor sensor = sensorEntry.getValue();
1737                sensor.writeToParcelLocked(out, batteryRealtime);
1738            }
1739
1740            out.writeInt(mProcessStats.size());
1741            for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
1742                out.writeString(procEntry.getKey());
1743                Uid.Proc proc = procEntry.getValue();
1744                proc.writeToParcelLocked(out);
1745            }
1746
1747            out.writeInt(mPackageStats.size());
1748            for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
1749                out.writeString(pkgEntry.getKey());
1750                Uid.Pkg pkg = pkgEntry.getValue();
1751                pkg.writeToParcelLocked(out);
1752            }
1753
1754            out.writeLong(mLoadedTcpBytesReceived);
1755            out.writeLong(mLoadedTcpBytesSent);
1756            out.writeLong(computeCurrentTcpBytesReceived());
1757            out.writeLong(computeCurrentTcpBytesSent());
1758            out.writeLong(mTcpBytesReceivedAtLastUnplug);
1759            out.writeLong(mTcpBytesSentAtLastUnplug);
1760            mWifiTurnedOnTimer.writeToParcel(out, batteryRealtime);
1761            mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
1762            mAudioTurnedOnTimer.writeToParcel(out, batteryRealtime);
1763            mVideoTurnedOnTimer.writeToParcel(out, batteryRealtime);
1764            mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
1765            mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
1766            if (mUserActivityCounters == null) {
1767                out.writeInt(0);
1768            } else {
1769                out.writeInt(1);
1770                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
1771                    mUserActivityCounters[i].writeToParcel(out);
1772                }
1773            }
1774        }
1775
1776        void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
1777            int numWakelocks = in.readInt();
1778            mWakelockStats.clear();
1779            for (int j = 0; j < numWakelocks; j++) {
1780                String wakelockName = in.readString();
1781                Uid.Wakelock wakelock = new Wakelock();
1782                wakelock.readFromParcelLocked(unpluggables, in);
1783                if (mWakelockStats.size() < MAX_WAKELOCKS_PER_UID) {
1784                    // We will just drop some random set of wakelocks if
1785                    // the previous run of the system was an older version
1786                    // that didn't impose a limit.
1787                    mWakelockStats.put(wakelockName, wakelock);
1788                }
1789            }
1790
1791            int numSensors = in.readInt();
1792            mSensorStats.clear();
1793            for (int k = 0; k < numSensors; k++) {
1794                int sensorNumber = in.readInt();
1795                Uid.Sensor sensor = new Sensor(sensorNumber);
1796                sensor.readFromParcelLocked(mUnpluggables, in);
1797                mSensorStats.put(sensorNumber, sensor);
1798            }
1799
1800            int numProcs = in.readInt();
1801            mProcessStats.clear();
1802            for (int k = 0; k < numProcs; k++) {
1803                String processName = in.readString();
1804                Uid.Proc proc = new Proc();
1805                proc.readFromParcelLocked(in);
1806                mProcessStats.put(processName, proc);
1807            }
1808
1809            int numPkgs = in.readInt();
1810            mPackageStats.clear();
1811            for (int l = 0; l < numPkgs; l++) {
1812                String packageName = in.readString();
1813                Uid.Pkg pkg = new Pkg();
1814                pkg.readFromParcelLocked(in);
1815                mPackageStats.put(packageName, pkg);
1816            }
1817
1818            mLoadedTcpBytesReceived = in.readLong();
1819            mLoadedTcpBytesSent = in.readLong();
1820            mCurrentTcpBytesReceived = in.readLong();
1821            mCurrentTcpBytesSent = in.readLong();
1822            mTcpBytesReceivedAtLastUnplug = in.readLong();
1823            mTcpBytesSentAtLastUnplug = in.readLong();
1824            mWifiTurnedOn = false;
1825            mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables, in);
1826            mFullWifiLockOut = false;
1827            mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables, in);
1828            mAudioTurnedOn = false;
1829            mAudioTurnedOnTimer = new StopwatchTimer(AUDIO_TURNED_ON, null, mUnpluggables, in);
1830            mVideoTurnedOn = false;
1831            mVideoTurnedOnTimer = new StopwatchTimer(VIDEO_TURNED_ON, null, mUnpluggables, in);
1832            mScanWifiLockOut = false;
1833            mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables, in);
1834            mWifiMulticastEnabled = false;
1835            mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
1836                    null, mUnpluggables, in);
1837            if (in.readInt() == 0) {
1838                mUserActivityCounters = null;
1839            } else {
1840                mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
1841                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
1842                    mUserActivityCounters[i] = new Counter(mUnpluggables, in);
1843                }
1844            }
1845        }
1846
1847        /**
1848         * The statistics associated with a particular wake lock.
1849         */
1850        public final class Wakelock extends BatteryStats.Uid.Wakelock {
1851            /**
1852             * How long (in ms) this uid has been keeping the device partially awake.
1853             */
1854            StopwatchTimer mTimerPartial;
1855
1856            /**
1857             * How long (in ms) this uid has been keeping the device fully awake.
1858             */
1859            StopwatchTimer mTimerFull;
1860
1861            /**
1862             * How long (in ms) this uid has had a window keeping the device awake.
1863             */
1864            StopwatchTimer mTimerWindow;
1865
1866            /**
1867             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
1868             * proper timer pool from the given BatteryStatsImpl object.
1869             *
1870             * @param in the Parcel to be read from.
1871             * return a new Timer, or null.
1872             */
1873            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
1874                    ArrayList<Unpluggable> unpluggables, Parcel in) {
1875                if (in.readInt() == 0) {
1876                    return null;
1877                }
1878
1879                return new StopwatchTimer(type, pool, unpluggables, in);
1880            }
1881
1882            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
1883                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
1884                        mPartialTimers, unpluggables, in);
1885                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
1886                        mFullTimers, unpluggables, in);
1887                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
1888                        mWindowTimers, unpluggables, in);
1889            }
1890
1891            void writeToParcelLocked(Parcel out, long batteryRealtime) {
1892                Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
1893                Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
1894                Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
1895            }
1896
1897            @Override
1898            public Timer getWakeTime(int type) {
1899                switch (type) {
1900                case WAKE_TYPE_FULL: return mTimerFull;
1901                case WAKE_TYPE_PARTIAL: return mTimerPartial;
1902                case WAKE_TYPE_WINDOW: return mTimerWindow;
1903                default: throw new IllegalArgumentException("type = " + type);
1904                }
1905            }
1906        }
1907
1908        public final class Sensor extends BatteryStats.Uid.Sensor {
1909            final int mHandle;
1910            StopwatchTimer mTimer;
1911
1912            public Sensor(int handle) {
1913                mHandle = handle;
1914            }
1915
1916            private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
1917                    Parcel in) {
1918                if (in.readInt() == 0) {
1919                    return null;
1920                }
1921
1922                ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
1923                if (pool == null) {
1924                    pool = new ArrayList<StopwatchTimer>();
1925                    mSensorTimers.put(mHandle, pool);
1926                }
1927                return new StopwatchTimer(0, pool, unpluggables, in);
1928            }
1929
1930            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
1931                mTimer = readTimerFromParcel(unpluggables, in);
1932            }
1933
1934            void writeToParcelLocked(Parcel out, long batteryRealtime) {
1935                Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
1936            }
1937
1938            @Override
1939            public Timer getSensorTime() {
1940                return mTimer;
1941            }
1942
1943            @Override
1944            public int getHandle() {
1945                return mHandle;
1946            }
1947        }
1948
1949        /**
1950         * The statistics associated with a particular process.
1951         */
1952        public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
1953            /**
1954             * Total time (in 1/100 sec) spent executing in user code.
1955             */
1956            long mUserTime;
1957
1958            /**
1959             * Total time (in 1/100 sec) spent executing in kernel code.
1960             */
1961            long mSystemTime;
1962
1963            /**
1964             * Number of times the process has been started.
1965             */
1966            int mStarts;
1967
1968            /**
1969             * Amount of time the process was running in the foreground.
1970             */
1971            long mForegroundTime;
1972
1973            /**
1974             * The amount of user time loaded from a previous save.
1975             */
1976            long mLoadedUserTime;
1977
1978            /**
1979             * The amount of system time loaded from a previous save.
1980             */
1981            long mLoadedSystemTime;
1982
1983            /**
1984             * The number of times the process has started from a previous save.
1985             */
1986            int mLoadedStarts;
1987
1988            /**
1989             * The amount of foreground time loaded from a previous save.
1990             */
1991            long mLoadedForegroundTime;
1992
1993            /**
1994             * The amount of user time loaded from the previous run.
1995             */
1996            long mLastUserTime;
1997
1998            /**
1999             * The amount of system time loaded from the previous run.
2000             */
2001            long mLastSystemTime;
2002
2003            /**
2004             * The number of times the process has started from the previous run.
2005             */
2006            int mLastStarts;
2007
2008            /**
2009             * The amount of foreground time loaded from the previous run
2010             */
2011            long mLastForegroundTime;
2012
2013            /**
2014             * The amount of user time when last unplugged.
2015             */
2016            long mUnpluggedUserTime;
2017
2018            /**
2019             * The amount of system time when last unplugged.
2020             */
2021            long mUnpluggedSystemTime;
2022
2023            /**
2024             * The number of times the process has started before unplugged.
2025             */
2026            int mUnpluggedStarts;
2027
2028            /**
2029             * The amount of foreground time since unplugged.
2030             */
2031            long mUnpluggedForegroundTime;
2032
2033            SamplingCounter[] mSpeedBins;
2034
2035            Proc() {
2036                mUnpluggables.add(this);
2037                mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
2038                for (int i = 0; i < mSpeedBins.length; i++) {
2039                    mSpeedBins[i] = new SamplingCounter(mUnpluggables);
2040                }
2041            }
2042
2043            public void unplug(long batteryUptime, long batteryRealtime) {
2044                mUnpluggedUserTime = mUserTime;
2045                mUnpluggedSystemTime = mSystemTime;
2046                mUnpluggedStarts = mStarts;
2047                mUnpluggedForegroundTime = mForegroundTime;
2048            }
2049
2050            public void plug(long batteryUptime, long batteryRealtime) {
2051            }
2052
2053            void writeToParcelLocked(Parcel out) {
2054                final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
2055                final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
2056
2057                out.writeLong(mUserTime);
2058                out.writeLong(mSystemTime);
2059                out.writeLong(mForegroundTime);
2060                out.writeInt(mStarts);
2061                out.writeLong(mLoadedUserTime);
2062                out.writeLong(mLoadedSystemTime);
2063                out.writeLong(mLoadedForegroundTime);
2064                out.writeInt(mLoadedStarts);
2065                out.writeLong(mLastUserTime);
2066                out.writeLong(mLastSystemTime);
2067                out.writeLong(mLastForegroundTime);
2068                out.writeInt(mLastStarts);
2069                out.writeLong(mUnpluggedUserTime);
2070                out.writeLong(mUnpluggedSystemTime);
2071                out.writeLong(mUnpluggedForegroundTime);
2072                out.writeInt(mUnpluggedStarts);
2073
2074                out.writeInt(mSpeedBins.length);
2075                for (int i = 0; i < mSpeedBins.length; i++) {
2076                    mSpeedBins[i].writeToParcel(out);
2077                }
2078            }
2079
2080            void readFromParcelLocked(Parcel in) {
2081                mUserTime = in.readLong();
2082                mSystemTime = in.readLong();
2083                mForegroundTime = in.readLong();
2084                mStarts = in.readInt();
2085                mLoadedUserTime = in.readLong();
2086                mLoadedSystemTime = in.readLong();
2087                mLoadedForegroundTime = in.readLong();
2088                mLoadedStarts = in.readInt();
2089                mLastUserTime = in.readLong();
2090                mLastSystemTime = in.readLong();
2091                mLastForegroundTime = in.readLong();
2092                mLastStarts = in.readInt();
2093                mUnpluggedUserTime = in.readLong();
2094                mUnpluggedSystemTime = in.readLong();
2095                mUnpluggedForegroundTime = in.readLong();
2096                mUnpluggedStarts = in.readInt();
2097
2098                int bins = in.readInt();
2099                mSpeedBins = new SamplingCounter[bins];
2100                for (int i = 0; i < bins; i++) {
2101                    mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
2102                }
2103            }
2104
2105            public BatteryStatsImpl getBatteryStats() {
2106                return BatteryStatsImpl.this;
2107            }
2108
2109            public void addCpuTimeLocked(int utime, int stime) {
2110                mUserTime += utime;
2111                mSystemTime += stime;
2112            }
2113
2114            public void addForegroundTimeLocked(long ttime) {
2115                mForegroundTime += ttime;
2116            }
2117
2118            public void incStartsLocked() {
2119                mStarts++;
2120            }
2121
2122            @Override
2123            public long getUserTime(int which) {
2124                long val;
2125                if (which == STATS_LAST) {
2126                    val = mLastUserTime;
2127                } else {
2128                    val = mUserTime;
2129                    if (which == STATS_CURRENT) {
2130                        val -= mLoadedUserTime;
2131                    } else if (which == STATS_UNPLUGGED) {
2132                        val -= mUnpluggedUserTime;
2133                    }
2134                }
2135                return val;
2136            }
2137
2138            @Override
2139            public long getSystemTime(int which) {
2140                long val;
2141                if (which == STATS_LAST) {
2142                    val = mLastSystemTime;
2143                } else {
2144                    val = mSystemTime;
2145                    if (which == STATS_CURRENT) {
2146                        val -= mLoadedSystemTime;
2147                    } else if (which == STATS_UNPLUGGED) {
2148                        val -= mUnpluggedSystemTime;
2149                    }
2150                }
2151                return val;
2152            }
2153
2154            @Override
2155            public long getForegroundTime(int which) {
2156                long val;
2157                if (which == STATS_LAST) {
2158                    val = mLastForegroundTime;
2159                } else {
2160                    val = mForegroundTime;
2161                    if (which == STATS_CURRENT) {
2162                        val -= mLoadedForegroundTime;
2163                    } else if (which == STATS_UNPLUGGED) {
2164                        val -= mUnpluggedForegroundTime;
2165                    }
2166                }
2167                return val;
2168            }
2169
2170            @Override
2171            public int getStarts(int which) {
2172                int val;
2173                if (which == STATS_LAST) {
2174                    val = mLastStarts;
2175                } else {
2176                    val = mStarts;
2177                    if (which == STATS_CURRENT) {
2178                        val -= mLoadedStarts;
2179                    } else if (which == STATS_UNPLUGGED) {
2180                        val -= mUnpluggedStarts;
2181                    }
2182                }
2183                return val;
2184            }
2185
2186            /* Called by ActivityManagerService when CPU times are updated. */
2187            public void addSpeedStepTimes(long[] values) {
2188                for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
2189                    mSpeedBins[i].addCountAtomic(values[i]);
2190                }
2191            }
2192
2193            @Override
2194            public long getTimeAtCpuSpeedStep(int speedStep, int which) {
2195                if (speedStep < mSpeedBins.length) {
2196                    return mSpeedBins[speedStep].getCountLocked(which);
2197                } else {
2198                    return 0;
2199                }
2200            }
2201        }
2202
2203        /**
2204         * The statistics associated with a particular package.
2205         */
2206        public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
2207            /**
2208             * Number of times this package has done something that could wake up the
2209             * device from sleep.
2210             */
2211            int mWakeups;
2212
2213            /**
2214             * Number of things that could wake up the device loaded from a
2215             * previous save.
2216             */
2217            int mLoadedWakeups;
2218
2219            /**
2220             * Number of things that could wake up the device as of the
2221             * last run.
2222             */
2223            int mLastWakeups;
2224
2225            /**
2226             * Number of things that could wake up the device as of the
2227             * last run.
2228             */
2229            int mUnpluggedWakeups;
2230
2231            /**
2232             * The statics we have collected for this package's services.
2233             */
2234            final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
2235
2236            Pkg() {
2237                mUnpluggables.add(this);
2238            }
2239
2240            public void unplug(long batteryUptime, long batteryRealtime) {
2241                mUnpluggedWakeups = mWakeups;
2242            }
2243
2244            public void plug(long batteryUptime, long batteryRealtime) {
2245            }
2246
2247            void readFromParcelLocked(Parcel in) {
2248                mWakeups = in.readInt();
2249                mLoadedWakeups = in.readInt();
2250                mLastWakeups = in.readInt();
2251                mUnpluggedWakeups = in.readInt();
2252
2253                int numServs = in.readInt();
2254                mServiceStats.clear();
2255                for (int m = 0; m < numServs; m++) {
2256                    String serviceName = in.readString();
2257                    Uid.Pkg.Serv serv = new Serv();
2258                    mServiceStats.put(serviceName, serv);
2259
2260                    serv.readFromParcelLocked(in);
2261                }
2262            }
2263
2264            void writeToParcelLocked(Parcel out) {
2265                out.writeInt(mWakeups);
2266                out.writeInt(mLoadedWakeups);
2267                out.writeInt(mLastWakeups);
2268                out.writeInt(mUnpluggedWakeups);
2269
2270                out.writeInt(mServiceStats.size());
2271                for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
2272                    out.writeString(servEntry.getKey());
2273                    Uid.Pkg.Serv serv = servEntry.getValue();
2274
2275                    serv.writeToParcelLocked(out);
2276                }
2277            }
2278
2279            @Override
2280            public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
2281                return mServiceStats;
2282            }
2283
2284            @Override
2285            public int getWakeups(int which) {
2286                int val;
2287                if (which == STATS_LAST) {
2288                    val = mLastWakeups;
2289                } else {
2290                    val = mWakeups;
2291                    if (which == STATS_CURRENT) {
2292                        val -= mLoadedWakeups;
2293                    } else if (which == STATS_UNPLUGGED) {
2294                        val -= mUnpluggedWakeups;
2295                    }
2296                }
2297
2298                return val;
2299            }
2300
2301            /**
2302             * The statistics associated with a particular service.
2303             */
2304            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
2305                /**
2306                 * Total time (ms in battery uptime) the service has been left started.
2307                 */
2308                long mStartTime;
2309
2310                /**
2311                 * If service has been started and not yet stopped, this is
2312                 * when it was started.
2313                 */
2314                long mRunningSince;
2315
2316                /**
2317                 * True if we are currently running.
2318                 */
2319                boolean mRunning;
2320
2321                /**
2322                 * Total number of times startService() has been called.
2323                 */
2324                int mStarts;
2325
2326                /**
2327                 * Total time (ms in battery uptime) the service has been left launched.
2328                 */
2329                long mLaunchedTime;
2330
2331                /**
2332                 * If service has been launched and not yet exited, this is
2333                 * when it was launched (ms in battery uptime).
2334                 */
2335                long mLaunchedSince;
2336
2337                /**
2338                 * True if we are currently launched.
2339                 */
2340                boolean mLaunched;
2341
2342                /**
2343                 * Total number times the service has been launched.
2344                 */
2345                int mLaunches;
2346
2347                /**
2348                 * The amount of time spent started loaded from a previous save
2349                 * (ms in battery uptime).
2350                 */
2351                long mLoadedStartTime;
2352
2353                /**
2354                 * The number of starts loaded from a previous save.
2355                 */
2356                int mLoadedStarts;
2357
2358                /**
2359                 * The number of launches loaded from a previous save.
2360                 */
2361                int mLoadedLaunches;
2362
2363                /**
2364                 * The amount of time spent started as of the last run (ms
2365                 * in battery uptime).
2366                 */
2367                long mLastStartTime;
2368
2369                /**
2370                 * The number of starts as of the last run.
2371                 */
2372                int mLastStarts;
2373
2374                /**
2375                 * The number of launches as of the last run.
2376                 */
2377                int mLastLaunches;
2378
2379                /**
2380                 * The amount of time spent started when last unplugged (ms
2381                 * in battery uptime).
2382                 */
2383                long mUnpluggedStartTime;
2384
2385                /**
2386                 * The number of starts when last unplugged.
2387                 */
2388                int mUnpluggedStarts;
2389
2390                /**
2391                 * The number of launches when last unplugged.
2392                 */
2393                int mUnpluggedLaunches;
2394
2395                Serv() {
2396                    mUnpluggables.add(this);
2397                }
2398
2399                public void unplug(long batteryUptime, long batteryRealtime) {
2400                    mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
2401                    mUnpluggedStarts = mStarts;
2402                    mUnpluggedLaunches = mLaunches;
2403                }
2404
2405                public void plug(long batteryUptime, long batteryRealtime) {
2406                }
2407
2408                void readFromParcelLocked(Parcel in) {
2409                    mStartTime = in.readLong();
2410                    mRunningSince = in.readLong();
2411                    mRunning = in.readInt() != 0;
2412                    mStarts = in.readInt();
2413                    mLaunchedTime = in.readLong();
2414                    mLaunchedSince = in.readLong();
2415                    mLaunched = in.readInt() != 0;
2416                    mLaunches = in.readInt();
2417                    mLoadedStartTime = in.readLong();
2418                    mLoadedStarts = in.readInt();
2419                    mLoadedLaunches = in.readInt();
2420                    mLastStartTime = in.readLong();
2421                    mLastStarts = in.readInt();
2422                    mLastLaunches = in.readInt();
2423                    mUnpluggedStartTime = in.readLong();
2424                    mUnpluggedStarts = in.readInt();
2425                    mUnpluggedLaunches = in.readInt();
2426                }
2427
2428                void writeToParcelLocked(Parcel out) {
2429                    out.writeLong(mStartTime);
2430                    out.writeLong(mRunningSince);
2431                    out.writeInt(mRunning ? 1 : 0);
2432                    out.writeInt(mStarts);
2433                    out.writeLong(mLaunchedTime);
2434                    out.writeLong(mLaunchedSince);
2435                    out.writeInt(mLaunched ? 1 : 0);
2436                    out.writeInt(mLaunches);
2437                    out.writeLong(mLoadedStartTime);
2438                    out.writeInt(mLoadedStarts);
2439                    out.writeInt(mLoadedLaunches);
2440                    out.writeLong(mLastStartTime);
2441                    out.writeInt(mLastStarts);
2442                    out.writeInt(mLastLaunches);
2443                    out.writeLong(mUnpluggedStartTime);
2444                    out.writeInt(mUnpluggedStarts);
2445                    out.writeInt(mUnpluggedLaunches);
2446                }
2447
2448                long getLaunchTimeToNowLocked(long batteryUptime) {
2449                    if (!mLaunched) return mLaunchedTime;
2450                    return mLaunchedTime + batteryUptime - mLaunchedSince;
2451                }
2452
2453                long getStartTimeToNowLocked(long batteryUptime) {
2454                    if (!mRunning) return mStartTime;
2455                    return mStartTime + batteryUptime - mRunningSince;
2456                }
2457
2458                public void startLaunchedLocked() {
2459                    if (!mLaunched) {
2460                        mLaunches++;
2461                        mLaunchedSince = getBatteryUptimeLocked();
2462                        mLaunched = true;
2463                    }
2464                }
2465
2466                public void stopLaunchedLocked() {
2467                    if (mLaunched) {
2468                        long time = getBatteryUptimeLocked() - mLaunchedSince;
2469                        if (time > 0) {
2470                            mLaunchedTime += time;
2471                        } else {
2472                            mLaunches--;
2473                        }
2474                        mLaunched = false;
2475                    }
2476                }
2477
2478                public void startRunningLocked() {
2479                    if (!mRunning) {
2480                        mStarts++;
2481                        mRunningSince = getBatteryUptimeLocked();
2482                        mRunning = true;
2483                    }
2484                }
2485
2486                public void stopRunningLocked() {
2487                    if (mRunning) {
2488                        long time = getBatteryUptimeLocked() - mRunningSince;
2489                        if (time > 0) {
2490                            mStartTime += time;
2491                        } else {
2492                            mStarts--;
2493                        }
2494                        mRunning = false;
2495                    }
2496                }
2497
2498                public BatteryStatsImpl getBatteryStats() {
2499                    return BatteryStatsImpl.this;
2500                }
2501
2502                @Override
2503                public int getLaunches(int which) {
2504                    int val;
2505
2506                    if (which == STATS_LAST) {
2507                        val = mLastLaunches;
2508                    } else {
2509                        val = mLaunches;
2510                        if (which == STATS_CURRENT) {
2511                            val -= mLoadedLaunches;
2512                        } else if (which == STATS_UNPLUGGED) {
2513                            val -= mUnpluggedLaunches;
2514                        }
2515                    }
2516
2517                    return val;
2518                }
2519
2520                @Override
2521                public long getStartTime(long now, int which) {
2522                    long val;
2523                    if (which == STATS_LAST) {
2524                        val = mLastStartTime;
2525                    } else {
2526                        val = getStartTimeToNowLocked(now);
2527                        if (which == STATS_CURRENT) {
2528                            val -= mLoadedStartTime;
2529                        } else if (which == STATS_UNPLUGGED) {
2530                            val -= mUnpluggedStartTime;
2531                        }
2532                    }
2533
2534                    return val;
2535                }
2536
2537                @Override
2538                public int getStarts(int which) {
2539                    int val;
2540                    if (which == STATS_LAST) {
2541                        val = mLastStarts;
2542                    } else {
2543                        val = mStarts;
2544                        if (which == STATS_CURRENT) {
2545                            val -= mLoadedStarts;
2546                        } else if (which == STATS_UNPLUGGED) {
2547                            val -= mUnpluggedStarts;
2548                        }
2549                    }
2550
2551                    return val;
2552                }
2553            }
2554
2555            public BatteryStatsImpl getBatteryStats() {
2556                return BatteryStatsImpl.this;
2557            }
2558
2559            public void incWakeupsLocked() {
2560                mWakeups++;
2561            }
2562
2563            final Serv newServiceStatsLocked() {
2564                return new Serv();
2565            }
2566        }
2567
2568        /**
2569         * Retrieve the statistics object for a particular process, creating
2570         * if needed.
2571         */
2572        public Proc getProcessStatsLocked(String name) {
2573            Proc ps = mProcessStats.get(name);
2574            if (ps == null) {
2575                ps = new Proc();
2576                mProcessStats.put(name, ps);
2577            }
2578
2579            return ps;
2580        }
2581
2582        /**
2583         * Retrieve the statistics object for a particular service, creating
2584         * if needed.
2585         */
2586        public Pkg getPackageStatsLocked(String name) {
2587            Pkg ps = mPackageStats.get(name);
2588            if (ps == null) {
2589                ps = new Pkg();
2590                mPackageStats.put(name, ps);
2591            }
2592
2593            return ps;
2594        }
2595
2596        /**
2597         * Retrieve the statistics object for a particular service, creating
2598         * if needed.
2599         */
2600        public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
2601            Pkg ps = getPackageStatsLocked(pkg);
2602            Pkg.Serv ss = ps.mServiceStats.get(serv);
2603            if (ss == null) {
2604                ss = ps.newServiceStatsLocked();
2605                ps.mServiceStats.put(serv, ss);
2606            }
2607
2608            return ss;
2609        }
2610
2611        public StopwatchTimer getWakeTimerLocked(String name, int type) {
2612            Wakelock wl = mWakelockStats.get(name);
2613            if (wl == null) {
2614                if (mWakelockStats.size() > MAX_WAKELOCKS_PER_UID) {
2615                    name = BATCHED_WAKELOCK_NAME;
2616                    wl = mWakelockStats.get(name);
2617                }
2618                if (wl == null) {
2619                    wl = new Wakelock();
2620                    mWakelockStats.put(name, wl);
2621                }
2622            }
2623            StopwatchTimer t = null;
2624            switch (type) {
2625                case WAKE_TYPE_PARTIAL:
2626                    t = wl.mTimerPartial;
2627                    if (t == null) {
2628                        t = new StopwatchTimer(WAKE_TYPE_PARTIAL, mPartialTimers, mUnpluggables);
2629                        wl.mTimerPartial = t;
2630                    }
2631                    return t;
2632                case WAKE_TYPE_FULL:
2633                    t = wl.mTimerFull;
2634                    if (t == null) {
2635                        t = new StopwatchTimer(WAKE_TYPE_FULL, mFullTimers, mUnpluggables);
2636                        wl.mTimerFull = t;
2637                    }
2638                    return t;
2639                case WAKE_TYPE_WINDOW:
2640                    t = wl.mTimerWindow;
2641                    if (t == null) {
2642                        t = new StopwatchTimer(WAKE_TYPE_WINDOW, mWindowTimers, mUnpluggables);
2643                        wl.mTimerWindow = t;
2644                    }
2645                    return t;
2646                default:
2647                    throw new IllegalArgumentException("type=" + type);
2648            }
2649        }
2650
2651        public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
2652            Sensor se = mSensorStats.get(sensor);
2653            if (se == null) {
2654                if (!create) {
2655                    return null;
2656                }
2657                se = new Sensor(sensor);
2658                mSensorStats.put(sensor, se);
2659            }
2660            StopwatchTimer t = se.mTimer;
2661            if (t != null) {
2662                return t;
2663            }
2664            ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
2665            if (timers == null) {
2666                timers = new ArrayList<StopwatchTimer>();
2667                mSensorTimers.put(sensor, timers);
2668            }
2669            t = new StopwatchTimer(BatteryStats.SENSOR, timers, mUnpluggables);
2670            se.mTimer = t;
2671            return t;
2672        }
2673
2674        public void noteStartWakeLocked(String name, int type) {
2675            StopwatchTimer t = getWakeTimerLocked(name, type);
2676            if (t != null) {
2677                t.startRunningLocked(BatteryStatsImpl.this);
2678            }
2679        }
2680
2681        public void noteStopWakeLocked(String name, int type) {
2682            StopwatchTimer t = getWakeTimerLocked(name, type);
2683            if (t != null) {
2684                t.stopRunningLocked(BatteryStatsImpl.this);
2685            }
2686        }
2687
2688        public void noteStartSensor(int sensor) {
2689            StopwatchTimer t = getSensorTimerLocked(sensor, true);
2690            if (t != null) {
2691                t.startRunningLocked(BatteryStatsImpl.this);
2692            }
2693        }
2694
2695        public void noteStopSensor(int sensor) {
2696            // Don't create a timer if one doesn't already exist
2697            StopwatchTimer t = getSensorTimerLocked(sensor, false);
2698            if (t != null) {
2699                t.stopRunningLocked(BatteryStatsImpl.this);
2700            }
2701        }
2702
2703        public void noteStartGps() {
2704            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
2705            if (t != null) {
2706                t.startRunningLocked(BatteryStatsImpl.this);
2707            }
2708        }
2709
2710        public void noteStopGps() {
2711            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
2712            if (t != null) {
2713                t.stopRunningLocked(BatteryStatsImpl.this);
2714            }
2715        }
2716
2717        public BatteryStatsImpl getBatteryStats() {
2718            return BatteryStatsImpl.this;
2719        }
2720    }
2721
2722    public BatteryStatsImpl(String filename) {
2723        mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
2724        mStartCount++;
2725        mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables);
2726        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
2727            mScreenBrightnessTimer[i] = new StopwatchTimer(-100-i, null, mUnpluggables);
2728        }
2729        mInputEventCounter = new Counter(mUnpluggables);
2730        mPhoneOnTimer = new StopwatchTimer(-2, null, mUnpluggables);
2731        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
2732            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(-200-i, null, mUnpluggables);
2733        }
2734        mPhoneSignalScanningTimer = new StopwatchTimer(-200+1, null, mUnpluggables);
2735        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
2736            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(-300-i, null, mUnpluggables);
2737        }
2738        mWifiOnTimer = new StopwatchTimer(-3, null, mUnpluggables);
2739        mWifiRunningTimer = new StopwatchTimer(-4, null, mUnpluggables);
2740        mBluetoothOnTimer = new StopwatchTimer(-5, null, mUnpluggables);
2741        mAudioOnTimer = new StopwatchTimer(-6, null, mUnpluggables);
2742        mOnBattery = mOnBatteryInternal = false;
2743        mTrackBatteryPastUptime = 0;
2744        mTrackBatteryPastRealtime = 0;
2745        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
2746        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
2747        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
2748        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
2749        mDischargeStartLevel = 0;
2750        mDischargeCurrentLevel = 0;
2751    }
2752
2753    public BatteryStatsImpl(Parcel p) {
2754        mFile = null;
2755        readFromParcel(p);
2756    }
2757
2758    public void setNumSpeedSteps(int steps) {
2759        if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
2760    }
2761
2762    public void setRadioScanningTimeout(long timeout) {
2763        if (mPhoneSignalScanningTimer != null) {
2764            mPhoneSignalScanningTimer.setTimeout(timeout);
2765        }
2766    }
2767
2768    @Override
2769    public int getStartCount() {
2770        return mStartCount;
2771    }
2772
2773    public boolean isOnBattery() {
2774        return mOnBattery;
2775    }
2776
2777    public void setOnBattery(boolean onBattery, int level) {
2778        synchronized(this) {
2779            updateKernelWakelocksLocked();
2780            if (mOnBattery != onBattery) {
2781                mOnBattery = mOnBatteryInternal = onBattery;
2782
2783                long uptime = SystemClock.uptimeMillis() * 1000;
2784                long mSecRealtime = SystemClock.elapsedRealtime();
2785                long realtime = mSecRealtime * 1000;
2786                if (onBattery) {
2787                    mTrackBatteryUptimeStart = uptime;
2788                    mTrackBatteryRealtimeStart = realtime;
2789                    mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
2790                    mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
2791                    mDischargeCurrentLevel = mDischargeStartLevel = level;
2792                    doUnplug(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
2793                } else {
2794                    mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
2795                    mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
2796                    mDischargeCurrentLevel = level;
2797                    doPlug(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
2798                }
2799                if ((mLastWriteTime + (60 * 1000)) < mSecRealtime) {
2800                    if (mFile != null) {
2801                        writeLocked();
2802                    }
2803                }
2804            }
2805        }
2806    }
2807
2808    public void recordCurrentLevel(int level) {
2809        mDischargeCurrentLevel = level;
2810    }
2811
2812    public void updateKernelWakelocksLocked() {
2813        Map<String, KernelWakelockStats> m = readKernelWakelockStats();
2814
2815        if (m == null) {
2816            // Not crashing might make board bringup easier.
2817            Slog.w(TAG, "Couldn't get kernel wake lock stats");
2818            return;
2819        }
2820
2821        for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
2822            String name = ent.getKey();
2823            KernelWakelockStats kws = ent.getValue();
2824
2825            SamplingTimer kwlt = mKernelWakelockStats.get(name);
2826            if (kwlt == null) {
2827                kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
2828                        true /* track reported values */);
2829                mKernelWakelockStats.put(name, kwlt);
2830            }
2831            kwlt.updateCurrentReportedCount(kws.mCount);
2832            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
2833            kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
2834        }
2835
2836        if (m.size() != mKernelWakelockStats.size()) {
2837            // Set timers to stale if they didn't appear in /proc/wakelocks this time.
2838            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
2839                SamplingTimer st = ent.getValue();
2840                if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
2841                    st.setStale();
2842                }
2843            }
2844        }
2845    }
2846
2847    public long getAwakeTimeBattery() {
2848        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
2849    }
2850
2851    public long getAwakeTimePlugged() {
2852        return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
2853    }
2854
2855    @Override
2856    public long computeUptime(long curTime, int which) {
2857        switch (which) {
2858            case STATS_TOTAL: return mUptime + (curTime-mUptimeStart);
2859            case STATS_LAST: return mLastUptime;
2860            case STATS_CURRENT: return (curTime-mUptimeStart);
2861            case STATS_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
2862        }
2863        return 0;
2864    }
2865
2866    @Override
2867    public long computeRealtime(long curTime, int which) {
2868        switch (which) {
2869            case STATS_TOTAL: return mRealtime + (curTime-mRealtimeStart);
2870            case STATS_LAST: return mLastRealtime;
2871            case STATS_CURRENT: return (curTime-mRealtimeStart);
2872            case STATS_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
2873        }
2874        return 0;
2875    }
2876
2877    @Override
2878    public long computeBatteryUptime(long curTime, int which) {
2879        switch (which) {
2880            case STATS_TOTAL:
2881                return mBatteryUptime + getBatteryUptime(curTime);
2882            case STATS_LAST:
2883                return mBatteryLastUptime;
2884            case STATS_CURRENT:
2885                return getBatteryUptime(curTime);
2886            case STATS_UNPLUGGED:
2887                return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
2888        }
2889        return 0;
2890    }
2891
2892    @Override
2893    public long computeBatteryRealtime(long curTime, int which) {
2894        switch (which) {
2895            case STATS_TOTAL:
2896                return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
2897            case STATS_LAST:
2898                return mBatteryLastRealtime;
2899            case STATS_CURRENT:
2900                return getBatteryRealtimeLocked(curTime);
2901            case STATS_UNPLUGGED:
2902                return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
2903        }
2904        return 0;
2905    }
2906
2907    long getBatteryUptimeLocked(long curTime) {
2908        long time = mTrackBatteryPastUptime;
2909        if (mOnBatteryInternal) {
2910            time += curTime - mTrackBatteryUptimeStart;
2911        }
2912        return time;
2913    }
2914
2915    long getBatteryUptimeLocked() {
2916        return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
2917    }
2918
2919    @Override
2920    public long getBatteryUptime(long curTime) {
2921        return getBatteryUptimeLocked(curTime);
2922    }
2923
2924    long getBatteryRealtimeLocked(long curTime) {
2925        long time = mTrackBatteryPastRealtime;
2926        if (mOnBatteryInternal) {
2927            time += curTime - mTrackBatteryRealtimeStart;
2928        }
2929        return time;
2930    }
2931
2932    @Override
2933    public long getBatteryRealtime(long curTime) {
2934        return getBatteryRealtimeLocked(curTime);
2935    }
2936
2937    private long getTcpBytes(long current, long[] dataBytes, int which) {
2938        if (which == STATS_LAST) {
2939            return dataBytes[STATS_LAST];
2940        } else {
2941            if (which == STATS_UNPLUGGED) {
2942                if (dataBytes[STATS_UNPLUGGED] < 0) {
2943                    return dataBytes[STATS_LAST];
2944                } else {
2945                    return current - dataBytes[STATS_UNPLUGGED];
2946                }
2947            } else if (which == STATS_TOTAL) {
2948                return (current - dataBytes[STATS_CURRENT]) + dataBytes[STATS_TOTAL];
2949            }
2950            return current - dataBytes[STATS_CURRENT];
2951        }
2952    }
2953
2954    /** Only STATS_UNPLUGGED works properly */
2955    public long getMobileTcpBytesSent(int which) {
2956        return getTcpBytes(TrafficStats.getMobileTxBytes(), mMobileDataTx, which);
2957    }
2958
2959    /** Only STATS_UNPLUGGED works properly */
2960    public long getMobileTcpBytesReceived(int which) {
2961        return getTcpBytes(TrafficStats.getMobileRxBytes(), mMobileDataRx, which);
2962    }
2963
2964    /** Only STATS_UNPLUGGED works properly */
2965    public long getTotalTcpBytesSent(int which) {
2966        return getTcpBytes(TrafficStats.getTotalTxBytes(), mTotalDataTx, which);
2967    }
2968
2969    /** Only STATS_UNPLUGGED works properly */
2970    public long getTotalTcpBytesReceived(int which) {
2971        return getTcpBytes(TrafficStats.getTotalRxBytes(), mTotalDataRx, which);
2972    }
2973
2974    @Override
2975    public int getDischargeStartLevel() {
2976        synchronized(this) {
2977            return getDischargeStartLevelLocked();
2978        }
2979    }
2980
2981    public int getDischargeStartLevelLocked() {
2982            return mDischargeStartLevel;
2983    }
2984
2985    @Override
2986    public int getDischargeCurrentLevel() {
2987        synchronized(this) {
2988            return getDischargeCurrentLevelLocked();
2989        }
2990    }
2991
2992    public int getDischargeCurrentLevelLocked() {
2993            return mDischargeCurrentLevel;
2994    }
2995
2996    @Override
2997    public int getCpuSpeedSteps() {
2998        return sNumSpeedSteps;
2999    }
3000
3001    /**
3002     * Retrieve the statistics object for a particular uid, creating if needed.
3003     */
3004    public Uid getUidStatsLocked(int uid) {
3005        Uid u = mUidStats.get(uid);
3006        if (u == null) {
3007            u = new Uid(uid);
3008            mUidStats.put(uid, u);
3009        }
3010        return u;
3011    }
3012
3013    /**
3014     * Remove the statistics object for a particular uid.
3015     */
3016    public void removeUidStatsLocked(int uid) {
3017        mUidStats.remove(uid);
3018    }
3019
3020    /**
3021     * Retrieve the statistics object for a particular process, creating
3022     * if needed.
3023     */
3024    public Uid.Proc getProcessStatsLocked(int uid, String name) {
3025        Uid u = getUidStatsLocked(uid);
3026        return u.getProcessStatsLocked(name);
3027    }
3028
3029    /**
3030     * Retrieve the statistics object for a particular process, given
3031     * the name of the process.
3032     * @param name process name
3033     * @return the statistics object for the process
3034     */
3035    public Uid.Proc getProcessStatsLocked(String name, int pid) {
3036        int uid;
3037        if (mUidCache.containsKey(name)) {
3038            uid = mUidCache.get(name);
3039        } else {
3040            uid = Process.getUidForPid(pid);
3041            mUidCache.put(name, uid);
3042        }
3043        Uid u = getUidStatsLocked(uid);
3044        return u.getProcessStatsLocked(name);
3045    }
3046
3047    /**
3048     * Retrieve the statistics object for a particular process, creating
3049     * if needed.
3050     */
3051    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
3052        Uid u = getUidStatsLocked(uid);
3053        return u.getPackageStatsLocked(pkg);
3054    }
3055
3056    /**
3057     * Retrieve the statistics object for a particular service, creating
3058     * if needed.
3059     */
3060    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
3061        Uid u = getUidStatsLocked(uid);
3062        return u.getServiceStatsLocked(pkg, name);
3063    }
3064
3065    private static JournaledFile makeJournaledFile() {
3066        final String base = "/data/system/device_policies.xml";
3067        return new JournaledFile(new File(base), new File(base + ".tmp"));
3068    }
3069
3070    public void writeLocked() {
3071        if (mFile == null) {
3072            Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
3073            return;
3074        }
3075
3076        try {
3077            FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
3078            Parcel out = Parcel.obtain();
3079            writeSummaryToParcel(out);
3080            stream.write(out.marshall());
3081            out.recycle();
3082
3083            stream.flush();
3084            stream.close();
3085            mFile.commit();
3086
3087            mLastWriteTime = SystemClock.elapsedRealtime();
3088            return;
3089        } catch (IOException e) {
3090            Slog.w("BatteryStats", "Error writing battery statistics", e);
3091        }
3092        mFile.rollback();
3093    }
3094
3095    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
3096        int pos = 0;
3097        int avail = stream.available();
3098        byte[] data = new byte[avail];
3099        while (true) {
3100            int amt = stream.read(data, pos, data.length-pos);
3101            //Log.i("foo", "Read " + amt + " bytes at " + pos
3102            //        + " of avail " + data.length);
3103            if (amt <= 0) {
3104                //Log.i("foo", "**** FINISHED READING: pos=" + pos
3105                //        + " len=" + data.length);
3106                return data;
3107            }
3108            pos += amt;
3109            avail = stream.available();
3110            if (avail > data.length-pos) {
3111                byte[] newData = new byte[pos+avail];
3112                System.arraycopy(data, 0, newData, 0, pos);
3113                data = newData;
3114            }
3115        }
3116    }
3117
3118    public void readLocked() {
3119        if (mFile == null) {
3120            Slog.w("BatteryStats", "readLocked: no file associated with this instance");
3121            return;
3122        }
3123
3124        mUidStats.clear();
3125
3126        try {
3127            File file = mFile.chooseForRead();
3128            if (!file.exists()) {
3129                return;
3130            }
3131            FileInputStream stream = new FileInputStream(file);
3132
3133            byte[] raw = readFully(stream);
3134            Parcel in = Parcel.obtain();
3135            in.unmarshall(raw, 0, raw.length);
3136            in.setDataPosition(0);
3137            stream.close();
3138
3139            readSummaryFromParcel(in);
3140        } catch(java.io.IOException e) {
3141            Slog.e("BatteryStats", "Error reading battery statistics", e);
3142        }
3143    }
3144
3145    public int describeContents() {
3146        return 0;
3147    }
3148
3149    private void readSummaryFromParcel(Parcel in) {
3150        final int version = in.readInt();
3151        if (version != VERSION) {
3152            Slog.w("BatteryStats", "readFromParcel: version got " + version
3153                + ", expected " + VERSION + "; erasing old stats");
3154            return;
3155        }
3156
3157        mStartCount = in.readInt();
3158        mBatteryUptime = in.readLong();
3159        mBatteryLastUptime = in.readLong();
3160        mBatteryRealtime = in.readLong();
3161        mBatteryLastRealtime = in.readLong();
3162        mUptime = in.readLong();
3163        mLastUptime = in.readLong();
3164        mRealtime = in.readLong();
3165        mLastRealtime = in.readLong();
3166        mDischargeStartLevel = in.readInt();
3167        mDischargeCurrentLevel = in.readInt();
3168
3169        mStartCount++;
3170
3171        mScreenOn = false;
3172        mScreenOnTimer.readSummaryFromParcelLocked(in);
3173        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3174            mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
3175        }
3176        mInputEventCounter.readSummaryFromParcelLocked(in);
3177        mPhoneOn = false;
3178        mPhoneOnTimer.readSummaryFromParcelLocked(in);
3179        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3180            mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
3181        }
3182        mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
3183        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3184            mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
3185        }
3186        mWifiOn = false;
3187        mWifiOnTimer.readSummaryFromParcelLocked(in);
3188        mWifiRunning = false;
3189        mWifiRunningTimer.readSummaryFromParcelLocked(in);
3190        mBluetoothOn = false;
3191        mBluetoothOnTimer.readSummaryFromParcelLocked(in);
3192
3193        int NKW = in.readInt();
3194        if (NKW > 10000) {
3195            Slog.w(TAG, "File corrupt: too many kernel wake locks " + NKW);
3196            return;
3197        }
3198        for (int ikw = 0; ikw < NKW; ikw++) {
3199            if (in.readInt() != 0) {
3200                String kwltName = in.readString();
3201                getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
3202            }
3203        }
3204
3205        sNumSpeedSteps = in.readInt();
3206
3207        final int NU = in.readInt();
3208        if (NU > 10000) {
3209            Slog.w(TAG, "File corrupt: too many uids " + NU);
3210            return;
3211        }
3212        for (int iu = 0; iu < NU; iu++) {
3213            int uid = in.readInt();
3214            Uid u = new Uid(uid);
3215            mUidStats.put(uid, u);
3216
3217            u.mWifiTurnedOn = false;
3218            u.mWifiTurnedOnTimer.readSummaryFromParcelLocked(in);
3219            u.mFullWifiLockOut = false;
3220            u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
3221            u.mAudioTurnedOn = false;
3222            u.mAudioTurnedOnTimer.readSummaryFromParcelLocked(in);
3223            u.mVideoTurnedOn = false;
3224            u.mVideoTurnedOnTimer.readSummaryFromParcelLocked(in);
3225            u.mScanWifiLockOut = false;
3226            u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
3227            u.mWifiMulticastEnabled = false;
3228            u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
3229
3230            if (in.readInt() != 0) {
3231                if (u.mUserActivityCounters == null) {
3232                    u.initUserActivityLocked();
3233                }
3234                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
3235                    u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
3236                }
3237            }
3238
3239            int NW = in.readInt();
3240            if (NW > 10000) {
3241                Slog.w(TAG, "File corrupt: too many wake locks " + NW);
3242                return;
3243            }
3244            for (int iw = 0; iw < NW; iw++) {
3245                String wlName = in.readString();
3246                if (in.readInt() != 0) {
3247                    u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
3248                }
3249                if (in.readInt() != 0) {
3250                    u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
3251                }
3252                if (in.readInt() != 0) {
3253                    u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
3254                }
3255            }
3256
3257            int NP = in.readInt();
3258            if (NP > 10000) {
3259                Slog.w(TAG, "File corrupt: too many sensors " + NP);
3260                return;
3261            }
3262            for (int is = 0; is < NP; is++) {
3263                int seNumber = in.readInt();
3264                if (in.readInt() != 0) {
3265                    u.getSensorTimerLocked(seNumber, true)
3266                            .readSummaryFromParcelLocked(in);
3267                }
3268            }
3269
3270            NP = in.readInt();
3271            if (NP > 10000) {
3272                Slog.w(TAG, "File corrupt: too many processes " + NP);
3273                return;
3274            }
3275            for (int ip = 0; ip < NP; ip++) {
3276                String procName = in.readString();
3277                Uid.Proc p = u.getProcessStatsLocked(procName);
3278                p.mUserTime = p.mLoadedUserTime = in.readLong();
3279                p.mLastUserTime = in.readLong();
3280                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
3281                p.mLastSystemTime = in.readLong();
3282                p.mStarts = p.mLoadedStarts = in.readInt();
3283                p.mLastStarts = in.readInt();
3284            }
3285
3286            NP = in.readInt();
3287            if (NP > 10000) {
3288                Slog.w(TAG, "File corrupt: too many packages " + NP);
3289                return;
3290            }
3291            for (int ip = 0; ip < NP; ip++) {
3292                String pkgName = in.readString();
3293                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
3294                p.mWakeups = p.mLoadedWakeups = in.readInt();
3295                p.mLastWakeups = in.readInt();
3296                final int NS = in.readInt();
3297                for (int is = 0; is < NS; is++) {
3298                    String servName = in.readString();
3299                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
3300                    s.mStartTime = s.mLoadedStartTime = in.readLong();
3301                    s.mLastStartTime = in.readLong();
3302                    s.mStarts = s.mLoadedStarts = in.readInt();
3303                    s.mLastStarts = in.readInt();
3304                    s.mLaunches = s.mLoadedLaunches = in.readInt();
3305                    s.mLastLaunches = in.readInt();
3306                }
3307            }
3308
3309            u.mLoadedTcpBytesReceived = in.readLong();
3310            u.mLoadedTcpBytesSent = in.readLong();
3311        }
3312    }
3313
3314    /**
3315     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
3316     * disk.  This format does not allow a lossless round-trip.
3317     *
3318     * @param out the Parcel to be written to.
3319     */
3320    public void writeSummaryToParcel(Parcel out) {
3321        final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
3322        final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
3323        final long NOW = getBatteryUptimeLocked(NOW_SYS);
3324        final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
3325
3326        out.writeInt(VERSION);
3327
3328        out.writeInt(mStartCount);
3329        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_TOTAL));
3330        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_CURRENT));
3331        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_TOTAL));
3332        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_CURRENT));
3333        out.writeLong(computeUptime(NOW_SYS, STATS_TOTAL));
3334        out.writeLong(computeUptime(NOW_SYS, STATS_CURRENT));
3335        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_TOTAL));
3336        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_CURRENT));
3337        out.writeInt(mDischargeStartLevel);
3338        out.writeInt(mDischargeCurrentLevel);
3339
3340
3341        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3342        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3343            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
3344        }
3345        mInputEventCounter.writeSummaryFromParcelLocked(out);
3346        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3347        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3348            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
3349        }
3350        mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3351        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3352            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
3353        }
3354        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3355        mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3356        mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3357
3358        out.writeInt(mKernelWakelockStats.size());
3359        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
3360            Timer kwlt = ent.getValue();
3361            if (kwlt != null) {
3362                out.writeInt(1);
3363                out.writeString(ent.getKey());
3364                ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
3365            } else {
3366                out.writeInt(0);
3367            }
3368        }
3369
3370        out.writeInt(sNumSpeedSteps);
3371        final int NU = mUidStats.size();
3372        out.writeInt(NU);
3373        for (int iu = 0; iu < NU; iu++) {
3374            out.writeInt(mUidStats.keyAt(iu));
3375            Uid u = mUidStats.valueAt(iu);
3376
3377            u.mWifiTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3378            u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3379            u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3380            u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3381            u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3382            u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3383
3384            if (u.mUserActivityCounters == null) {
3385                out.writeInt(0);
3386            } else {
3387                out.writeInt(1);
3388                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
3389                    u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
3390                }
3391            }
3392
3393            int NW = u.mWakelockStats.size();
3394            out.writeInt(NW);
3395            if (NW > 0) {
3396                for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
3397                        : u.mWakelockStats.entrySet()) {
3398                    out.writeString(ent.getKey());
3399                    Uid.Wakelock wl = ent.getValue();
3400                    if (wl.mTimerFull != null) {
3401                        out.writeInt(1);
3402                        wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
3403                    } else {
3404                        out.writeInt(0);
3405                    }
3406                    if (wl.mTimerPartial != null) {
3407                        out.writeInt(1);
3408                        wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
3409                    } else {
3410                        out.writeInt(0);
3411                    }
3412                    if (wl.mTimerWindow != null) {
3413                        out.writeInt(1);
3414                        wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
3415                    } else {
3416                        out.writeInt(0);
3417                    }
3418                }
3419            }
3420
3421            int NSE = u.mSensorStats.size();
3422            out.writeInt(NSE);
3423            if (NSE > 0) {
3424                for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
3425                        : u.mSensorStats.entrySet()) {
3426                    out.writeInt(ent.getKey());
3427                    Uid.Sensor se = ent.getValue();
3428                    if (se.mTimer != null) {
3429                        out.writeInt(1);
3430                        se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
3431                    } else {
3432                        out.writeInt(0);
3433                    }
3434                }
3435            }
3436
3437            int NP = u.mProcessStats.size();
3438            out.writeInt(NP);
3439            if (NP > 0) {
3440                for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
3441                    : u.mProcessStats.entrySet()) {
3442                    out.writeString(ent.getKey());
3443                    Uid.Proc ps = ent.getValue();
3444                    out.writeLong(ps.mUserTime);
3445                    out.writeLong(ps.mUserTime - ps.mLoadedUserTime);
3446                    out.writeLong(ps.mSystemTime);
3447                    out.writeLong(ps.mSystemTime - ps.mLoadedSystemTime);
3448                    out.writeInt(ps.mStarts);
3449                    out.writeInt(ps.mStarts - ps.mLoadedStarts);
3450                }
3451            }
3452
3453            NP = u.mPackageStats.size();
3454            out.writeInt(NP);
3455            if (NP > 0) {
3456                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
3457                    : u.mPackageStats.entrySet()) {
3458                    out.writeString(ent.getKey());
3459                    Uid.Pkg ps = ent.getValue();
3460                    out.writeInt(ps.mWakeups);
3461                    out.writeInt(ps.mWakeups - ps.mLoadedWakeups);
3462                    final int NS = ps.mServiceStats.size();
3463                    out.writeInt(NS);
3464                    if (NS > 0) {
3465                        for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
3466                                : ps.mServiceStats.entrySet()) {
3467                            out.writeString(sent.getKey());
3468                            BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
3469                            long time = ss.getStartTimeToNowLocked(NOW);
3470                            out.writeLong(time);
3471                            out.writeLong(time - ss.mLoadedStartTime);
3472                            out.writeInt(ss.mStarts);
3473                            out.writeInt(ss.mStarts - ss.mLoadedStarts);
3474                            out.writeInt(ss.mLaunches);
3475                            out.writeInt(ss.mLaunches - ss.mLoadedLaunches);
3476                        }
3477                    }
3478                }
3479            }
3480
3481            out.writeLong(u.getTcpBytesReceived(STATS_TOTAL));
3482            out.writeLong(u.getTcpBytesSent(STATS_TOTAL));
3483        }
3484    }
3485
3486    public void readFromParcel(Parcel in) {
3487        readFromParcelLocked(in);
3488    }
3489
3490    void readFromParcelLocked(Parcel in) {
3491        int magic = in.readInt();
3492        if (magic != MAGIC) {
3493            throw new ParcelFormatException("Bad magic number");
3494        }
3495
3496        mStartCount = in.readInt();
3497        mBatteryUptime = in.readLong();
3498        mBatteryLastUptime = in.readLong();
3499        mBatteryRealtime = in.readLong();
3500        mBatteryLastRealtime = in.readLong();
3501        mScreenOn = false;
3502        mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables, in);
3503        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3504            mScreenBrightnessTimer[i] = new StopwatchTimer(-100-i, null, mUnpluggables, in);
3505        }
3506        mInputEventCounter = new Counter(mUnpluggables, in);
3507        mPhoneOn = false;
3508        mPhoneOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
3509        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3510            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(-200-i, null, mUnpluggables, in);
3511        }
3512        mPhoneSignalScanningTimer = new StopwatchTimer(-200+1, null, mUnpluggables, in);
3513        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3514            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(-300-i, null, mUnpluggables, in);
3515        }
3516        mWifiOn = false;
3517        mWifiOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
3518        mWifiRunning = false;
3519        mWifiRunningTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
3520        mBluetoothOn = false;
3521        mBluetoothOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
3522        mUptime = in.readLong();
3523        mUptimeStart = in.readLong();
3524        mLastUptime = in.readLong();
3525        mRealtime = in.readLong();
3526        mRealtimeStart = in.readLong();
3527        mLastRealtime = in.readLong();
3528        mOnBattery = in.readInt() != 0;
3529        mOnBatteryInternal = false; // we are no longer really running.
3530        mTrackBatteryPastUptime = in.readLong();
3531        mTrackBatteryUptimeStart = in.readLong();
3532        mTrackBatteryPastRealtime = in.readLong();
3533        mTrackBatteryRealtimeStart = in.readLong();
3534        mUnpluggedBatteryUptime = in.readLong();
3535        mUnpluggedBatteryRealtime = in.readLong();
3536        mDischargeStartLevel = in.readInt();
3537        mDischargeCurrentLevel = in.readInt();
3538        mLastWriteTime = in.readLong();
3539
3540        mMobileDataRx[STATS_LAST] = in.readLong();
3541        mMobileDataRx[STATS_UNPLUGGED] = -1;
3542        mMobileDataTx[STATS_LAST] = in.readLong();
3543        mMobileDataTx[STATS_UNPLUGGED] = -1;
3544        mTotalDataRx[STATS_LAST] = in.readLong();
3545        mTotalDataRx[STATS_UNPLUGGED] = -1;
3546        mTotalDataTx[STATS_LAST] = in.readLong();
3547        mTotalDataTx[STATS_UNPLUGGED] = -1;
3548
3549        mRadioDataUptime = in.readLong();
3550        mRadioDataStart = -1;
3551
3552        mBluetoothPingCount = in.readInt();
3553        mBluetoothPingStart = -1;
3554
3555        mKernelWakelockStats.clear();
3556        int NKW = in.readInt();
3557        for (int ikw = 0; ikw < NKW; ikw++) {
3558            if (in.readInt() != 0) {
3559                String wakelockName = in.readString();
3560                in.readInt(); // Extra 0/1 written by Timer.writeTimerToParcel
3561                SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
3562                mKernelWakelockStats.put(wakelockName, kwlt);
3563            }
3564        }
3565
3566        mPartialTimers.clear();
3567        mFullTimers.clear();
3568        mWindowTimers.clear();
3569
3570        sNumSpeedSteps = in.readInt();
3571
3572        int numUids = in.readInt();
3573        mUidStats.clear();
3574        for (int i = 0; i < numUids; i++) {
3575            int uid = in.readInt();
3576            Uid u = new Uid(uid);
3577            u.readFromParcelLocked(mUnpluggables, in);
3578            mUidStats.append(uid, u);
3579        }
3580    }
3581
3582    public void writeToParcel(Parcel out, int flags) {
3583        writeToParcelLocked(out, flags);
3584    }
3585
3586    @SuppressWarnings("unused")
3587    void writeToParcelLocked(Parcel out, int flags) {
3588        final long uSecUptime = SystemClock.uptimeMillis() * 1000;
3589        final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
3590        final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
3591        final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
3592
3593        out.writeInt(MAGIC);
3594        out.writeInt(mStartCount);
3595        out.writeLong(mBatteryUptime);
3596        out.writeLong(mBatteryLastUptime);
3597        out.writeLong(mBatteryRealtime);
3598        out.writeLong(mBatteryLastRealtime);
3599        mScreenOnTimer.writeToParcel(out, batteryRealtime);
3600        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3601            mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
3602        }
3603        mInputEventCounter.writeToParcel(out);
3604        mPhoneOnTimer.writeToParcel(out, batteryRealtime);
3605        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3606            mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
3607        }
3608        mPhoneSignalScanningTimer.writeToParcel(out, batteryRealtime);
3609        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3610            mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
3611        }
3612        mWifiOnTimer.writeToParcel(out, batteryRealtime);
3613        mWifiRunningTimer.writeToParcel(out, batteryRealtime);
3614        mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
3615        out.writeLong(mUptime);
3616        out.writeLong(mUptimeStart);
3617        out.writeLong(mLastUptime);
3618        out.writeLong(mRealtime);
3619        out.writeLong(mRealtimeStart);
3620        out.writeLong(mLastRealtime);
3621        out.writeInt(mOnBattery ? 1 : 0);
3622        out.writeLong(batteryUptime);
3623        out.writeLong(mTrackBatteryUptimeStart);
3624        out.writeLong(batteryRealtime);
3625        out.writeLong(mTrackBatteryRealtimeStart);
3626        out.writeLong(mUnpluggedBatteryUptime);
3627        out.writeLong(mUnpluggedBatteryRealtime);
3628        out.writeInt(mDischargeStartLevel);
3629        out.writeInt(mDischargeCurrentLevel);
3630        out.writeLong(mLastWriteTime);
3631
3632        out.writeLong(getMobileTcpBytesReceived(STATS_UNPLUGGED));
3633        out.writeLong(getMobileTcpBytesSent(STATS_UNPLUGGED));
3634        out.writeLong(getTotalTcpBytesReceived(STATS_UNPLUGGED));
3635        out.writeLong(getTotalTcpBytesSent(STATS_UNPLUGGED));
3636
3637        // Write radio uptime for data
3638        out.writeLong(getRadioDataUptime());
3639
3640        out.writeInt(getBluetoothPingCount());
3641
3642        out.writeInt(mKernelWakelockStats.size());
3643        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
3644            SamplingTimer kwlt = ent.getValue();
3645            if (kwlt != null) {
3646                out.writeInt(1);
3647                out.writeString(ent.getKey());
3648                Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
3649            } else {
3650                out.writeInt(0);
3651            }
3652        }
3653
3654        out.writeInt(sNumSpeedSteps);
3655
3656        int size = mUidStats.size();
3657        out.writeInt(size);
3658        for (int i = 0; i < size; i++) {
3659            out.writeInt(mUidStats.keyAt(i));
3660            Uid uid = mUidStats.valueAt(i);
3661
3662            uid.writeToParcelLocked(out, batteryRealtime);
3663        }
3664    }
3665
3666    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
3667        new Parcelable.Creator<BatteryStatsImpl>() {
3668        public BatteryStatsImpl createFromParcel(Parcel in) {
3669            return new BatteryStatsImpl(in);
3670        }
3671
3672        public BatteryStatsImpl[] newArray(int size) {
3673            return new BatteryStatsImpl[size];
3674        }
3675    };
3676
3677    public void dumpLocked(PrintWriter pw) {
3678        if (DEBUG) {
3679            Printer pr = new PrintWriterPrinter(pw);
3680            pr.println("*** Screen timer:");
3681            mScreenOnTimer.logState(pr, "  ");
3682            for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3683                pr.println("*** Screen brightness #" + i + ":");
3684                mScreenBrightnessTimer[i].logState(pr, "  ");
3685            }
3686            pr.println("*** Input event counter:");
3687            mInputEventCounter.logState(pr, "  ");
3688            pr.println("*** Phone timer:");
3689            mPhoneOnTimer.logState(pr, "  ");
3690            for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3691                pr.println("*** Signal strength #" + i + ":");
3692                mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
3693            }
3694            pr.println("*** Signal scanning :");
3695            mPhoneSignalScanningTimer.logState(pr, "  ");
3696            for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3697                pr.println("*** Data connection type #" + i + ":");
3698                mPhoneDataConnectionsTimer[i].logState(pr, "  ");
3699            }
3700            pr.println("*** Wifi timer:");
3701            mWifiOnTimer.logState(pr, "  ");
3702            pr.println("*** WifiRunning timer:");
3703            mWifiRunningTimer.logState(pr, "  ");
3704            pr.println("*** Bluetooth timer:");
3705            mBluetoothOnTimer.logState(pr, "  ");
3706        }
3707        super.dumpLocked(pw);
3708    }
3709}
3710