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