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