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