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