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