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