BatteryStatsImpl.java revision af17baa27196e785989e99b0ecbe7f1c98a1f0cb
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 = 64 + (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 = mUidStats.get(entry.uid);
1583            if (u == null) continue;
1584
1585            u.mStartedTcpBytesReceived = entry.rxBytes;
1586            u.mStartedTcpBytesSent = entry.txBytes;
1587            u.mTcpBytesReceivedAtLastUnplug = u.mCurrentTcpBytesReceived;
1588            u.mTcpBytesSentAtLastUnplug = u.mCurrentTcpBytesSent;
1589        }
1590
1591        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
1592            mUnpluggables.get(i).unplug(elapsedRealtime, batteryUptime, batteryRealtime);
1593        }
1594
1595        // Track both mobile and total overall data
1596        final NetworkStats ifaceStats = getNetworkStatsSummary();
1597        entry = ifaceStats.getTotal(entry, mMobileIfaces);
1598        doDataUnplug(mMobileDataRx, entry.rxBytes);
1599        doDataUnplug(mMobileDataTx, entry.txBytes);
1600        entry = ifaceStats.getTotal(entry);
1601        doDataUnplug(mTotalDataRx, entry.rxBytes);
1602        doDataUnplug(mTotalDataTx, entry.txBytes);
1603
1604        // Track radio awake time
1605        mRadioDataStart = getCurrentRadioDataUptime();
1606        mRadioDataUptime = 0;
1607
1608        // Track bt headset ping count
1609        mBluetoothPingStart = getCurrentBluetoothPingCount();
1610        mBluetoothPingCount = 0;
1611    }
1612
1613    public void doPlugLocked(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
1614        NetworkStats.Entry entry = null;
1615
1616        for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
1617            Uid u = mUidStats.valueAt(iu);
1618            if (u.mStartedTcpBytesReceived >= 0) {
1619                u.mCurrentTcpBytesReceived = u.computeCurrentTcpBytesReceived();
1620                u.mStartedTcpBytesReceived = -1;
1621            }
1622            if (u.mStartedTcpBytesSent >= 0) {
1623                u.mCurrentTcpBytesSent = u.computeCurrentTcpBytesSent();
1624                u.mStartedTcpBytesSent = -1;
1625            }
1626        }
1627        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
1628            mUnpluggables.get(i).plug(elapsedRealtime, batteryUptime, batteryRealtime);
1629        }
1630
1631        // Track both mobile and total overall data
1632        final NetworkStats ifaceStats = getNetworkStatsSummary();
1633        entry = ifaceStats.getTotal(entry, mMobileIfaces);
1634        doDataPlug(mMobileDataRx, entry.rxBytes);
1635        doDataPlug(mMobileDataTx, entry.txBytes);
1636        entry = ifaceStats.getTotal(entry);
1637        doDataPlug(mTotalDataRx, entry.rxBytes);
1638        doDataPlug(mTotalDataTx, entry.txBytes);
1639
1640        // Track radio awake time
1641        mRadioDataUptime = getRadioDataUptime();
1642        mRadioDataStart = -1;
1643
1644        // Track bt headset ping count
1645        mBluetoothPingCount = getBluetoothPingCount();
1646        mBluetoothPingStart = -1;
1647    }
1648
1649    int mWakeLockNesting;
1650
1651    public void noteStartWakeLocked(int uid, int pid, String name, int type) {
1652        if (type == WAKE_TYPE_PARTIAL) {
1653            // Only care about partial wake locks, since full wake locks
1654            // will be canceled when the user puts the screen to sleep.
1655            if (mWakeLockNesting == 0) {
1656                mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG;
1657                if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
1658                        + Integer.toHexString(mHistoryCur.states));
1659                addHistoryRecordLocked(SystemClock.elapsedRealtime());
1660            }
1661            mWakeLockNesting++;
1662        }
1663        if (uid >= 0) {
1664            if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
1665                Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
1666                mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
1667            }
1668            getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type);
1669        }
1670    }
1671
1672    public void noteStopWakeLocked(int uid, int pid, String name, int type) {
1673        if (type == WAKE_TYPE_PARTIAL) {
1674            mWakeLockNesting--;
1675            if (mWakeLockNesting == 0) {
1676                mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
1677                if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
1678                        + Integer.toHexString(mHistoryCur.states));
1679                addHistoryRecordLocked(SystemClock.elapsedRealtime());
1680            }
1681        }
1682        if (uid >= 0) {
1683            if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
1684                Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
1685                mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
1686            }
1687            getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type);
1688        }
1689    }
1690
1691    public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
1692        int N = ws.size();
1693        for (int i=0; i<N; i++) {
1694            noteStartWakeLocked(ws.get(i), pid, name, type);
1695        }
1696    }
1697
1698    public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
1699        int N = ws.size();
1700        for (int i=0; i<N; i++) {
1701            noteStopWakeLocked(ws.get(i), pid, name, type);
1702        }
1703    }
1704
1705    public int startAddingCpuLocked() {
1706        mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
1707
1708        if (mScreenOn) {
1709            return 0;
1710        }
1711
1712        final int N = mPartialTimers.size();
1713        if (N == 0) {
1714            mLastPartialTimers.clear();
1715            return 0;
1716        }
1717
1718        // How many timers should consume CPU?  Only want to include ones
1719        // that have already been in the list.
1720        for (int i=0; i<N; i++) {
1721            StopwatchTimer st = mPartialTimers.get(i);
1722            if (st.mInList) {
1723                Uid uid = st.mUid;
1724                // We don't include the system UID, because it so often
1725                // holds wake locks at one request or another of an app.
1726                if (uid != null && uid.mUid != Process.SYSTEM_UID) {
1727                    return 50;
1728                }
1729            }
1730        }
1731
1732        return 0;
1733    }
1734
1735    public void finishAddingCpuLocked(int perc, int utime, int stime, long[] cpuSpeedTimes) {
1736        final int N = mPartialTimers.size();
1737        if (perc != 0) {
1738            int num = 0;
1739            for (int i=0; i<N; i++) {
1740                StopwatchTimer st = mPartialTimers.get(i);
1741                if (st.mInList) {
1742                    Uid uid = st.mUid;
1743                    // We don't include the system UID, because it so often
1744                    // holds wake locks at one request or another of an app.
1745                    if (uid != null && uid.mUid != Process.SYSTEM_UID) {
1746                        num++;
1747                    }
1748                }
1749            }
1750            if (num != 0) {
1751                for (int i=0; i<N; i++) {
1752                    StopwatchTimer st = mPartialTimers.get(i);
1753                    if (st.mInList) {
1754                        Uid uid = st.mUid;
1755                        if (uid != null && uid.mUid != Process.SYSTEM_UID) {
1756                            int myUTime = utime/num;
1757                            int mySTime = stime/num;
1758                            utime -= myUTime;
1759                            stime -= mySTime;
1760                            num--;
1761                            Uid.Proc proc = uid.getProcessStatsLocked("*wakelock*");
1762                            proc.addCpuTimeLocked(myUTime, mySTime);
1763                            proc.addSpeedStepTimes(cpuSpeedTimes);
1764                        }
1765                    }
1766                }
1767            }
1768
1769            // Just in case, collect any lost CPU time.
1770            if (utime != 0 || stime != 0) {
1771                Uid uid = getUidStatsLocked(Process.SYSTEM_UID);
1772                if (uid != null) {
1773                    Uid.Proc proc = uid.getProcessStatsLocked("*lost*");
1774                    proc.addCpuTimeLocked(utime, stime);
1775                    proc.addSpeedStepTimes(cpuSpeedTimes);
1776                }
1777            }
1778        }
1779
1780        final int NL = mLastPartialTimers.size();
1781        boolean diff = N != NL;
1782        for (int i=0; i<NL && !diff; i++) {
1783            diff |= mPartialTimers.get(i) != mLastPartialTimers.get(i);
1784        }
1785        if (!diff) {
1786            for (int i=0; i<NL; i++) {
1787                mPartialTimers.get(i).mInList = true;
1788            }
1789            return;
1790        }
1791
1792        for (int i=0; i<NL; i++) {
1793            mLastPartialTimers.get(i).mInList = false;
1794        }
1795        mLastPartialTimers.clear();
1796        for (int i=0; i<N; i++) {
1797            StopwatchTimer st = mPartialTimers.get(i);
1798            st.mInList = true;
1799            mLastPartialTimers.add(st);
1800        }
1801    }
1802
1803    public void noteProcessDiedLocked(int uid, int pid) {
1804        Uid u = mUidStats.get(uid);
1805        if (u != null) {
1806            u.mPids.remove(pid);
1807        }
1808    }
1809
1810    public long getProcessWakeTime(int uid, int pid, long realtime) {
1811        Uid u = mUidStats.get(uid);
1812        if (u != null) {
1813            Uid.Pid p = u.mPids.get(pid);
1814            if (p != null) {
1815                return p.mWakeSum + (p.mWakeStart != 0 ? (realtime - p.mWakeStart) : 0);
1816            }
1817        }
1818        return 0;
1819    }
1820
1821    public void reportExcessiveWakeLocked(int uid, String proc, long overTime, long usedTime) {
1822        Uid u = mUidStats.get(uid);
1823        if (u != null) {
1824            u.reportExcessiveWakeLocked(proc, overTime, usedTime);
1825        }
1826    }
1827
1828    public void reportExcessiveCpuLocked(int uid, String proc, long overTime, long usedTime) {
1829        Uid u = mUidStats.get(uid);
1830        if (u != null) {
1831            u.reportExcessiveCpuLocked(proc, overTime, usedTime);
1832        }
1833    }
1834
1835    int mSensorNesting;
1836
1837    public void noteStartSensorLocked(int uid, int sensor) {
1838        if (mSensorNesting == 0) {
1839            mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
1840            if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
1841                    + Integer.toHexString(mHistoryCur.states));
1842            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1843        }
1844        mSensorNesting++;
1845        getUidStatsLocked(uid).noteStartSensor(sensor);
1846    }
1847
1848    public void noteStopSensorLocked(int uid, int sensor) {
1849        mSensorNesting--;
1850        if (mSensorNesting == 0) {
1851            mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG;
1852            if (DEBUG_HISTORY) Slog.v(TAG, "Stop sensor to: "
1853                    + Integer.toHexString(mHistoryCur.states));
1854            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1855        }
1856        getUidStatsLocked(uid).noteStopSensor(sensor);
1857    }
1858
1859    int mGpsNesting;
1860
1861    public void noteStartGpsLocked(int uid) {
1862        if (mGpsNesting == 0) {
1863            mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
1864            if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
1865                    + Integer.toHexString(mHistoryCur.states));
1866            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1867        }
1868        mGpsNesting++;
1869        getUidStatsLocked(uid).noteStartGps();
1870    }
1871
1872    public void noteStopGpsLocked(int uid) {
1873        mGpsNesting--;
1874        if (mGpsNesting == 0) {
1875            mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
1876            if (DEBUG_HISTORY) Slog.v(TAG, "Stop GPS to: "
1877                    + Integer.toHexString(mHistoryCur.states));
1878            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1879        }
1880        getUidStatsLocked(uid).noteStopGps();
1881    }
1882
1883    public void noteScreenOnLocked() {
1884        if (!mScreenOn) {
1885            mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
1886            if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
1887                    + Integer.toHexString(mHistoryCur.states));
1888            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1889            mScreenOn = true;
1890            mScreenOnTimer.startRunningLocked(this);
1891            if (mScreenBrightnessBin >= 0) {
1892                mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
1893            }
1894
1895            // Fake a wake lock, so we consider the device waked as long
1896            // as the screen is on.
1897            noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
1898
1899            // Update discharge amounts.
1900            if (mOnBatteryInternal) {
1901                updateDischargeScreenLevelsLocked(false, true);
1902            }
1903        }
1904    }
1905
1906    public void noteScreenOffLocked() {
1907        if (mScreenOn) {
1908            mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
1909            if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
1910                    + Integer.toHexString(mHistoryCur.states));
1911            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1912            mScreenOn = false;
1913            mScreenOnTimer.stopRunningLocked(this);
1914            if (mScreenBrightnessBin >= 0) {
1915                mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
1916            }
1917
1918            noteStopWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
1919
1920            // Update discharge amounts.
1921            if (mOnBatteryInternal) {
1922                updateDischargeScreenLevelsLocked(true, false);
1923            }
1924        }
1925    }
1926
1927    public void noteScreenBrightnessLocked(int brightness) {
1928        // Bin the brightness.
1929        int bin = brightness / (256/NUM_SCREEN_BRIGHTNESS_BINS);
1930        if (bin < 0) bin = 0;
1931        else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
1932        if (mScreenBrightnessBin != bin) {
1933            mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_BRIGHTNESS_MASK)
1934                    | (bin << HistoryItem.STATE_BRIGHTNESS_SHIFT);
1935            if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
1936                    + Integer.toHexString(mHistoryCur.states));
1937            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1938            if (mScreenOn) {
1939                if (mScreenBrightnessBin >= 0) {
1940                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
1941                }
1942                mScreenBrightnessTimer[bin].startRunningLocked(this);
1943            }
1944            mScreenBrightnessBin = bin;
1945        }
1946    }
1947
1948    public void noteInputEventAtomic() {
1949        mInputEventCounter.stepAtomic();
1950    }
1951
1952    public void noteUserActivityLocked(int uid, int event) {
1953        getUidStatsLocked(uid).noteUserActivityLocked(event);
1954    }
1955
1956    public void notePhoneOnLocked() {
1957        if (!mPhoneOn) {
1958            mHistoryCur.states |= HistoryItem.STATE_PHONE_IN_CALL_FLAG;
1959            if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
1960                    + Integer.toHexString(mHistoryCur.states));
1961            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1962            mPhoneOn = true;
1963            mPhoneOnTimer.startRunningLocked(this);
1964        }
1965    }
1966
1967    public void notePhoneOffLocked() {
1968        if (mPhoneOn) {
1969            mHistoryCur.states &= ~HistoryItem.STATE_PHONE_IN_CALL_FLAG;
1970            if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
1971                    + Integer.toHexString(mHistoryCur.states));
1972            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1973            mPhoneOn = false;
1974            mPhoneOnTimer.stopRunningLocked(this);
1975        }
1976    }
1977
1978    void stopAllSignalStrengthTimersLocked(int except) {
1979        for (int i = 0; i < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
1980            if (i == except) {
1981                continue;
1982            }
1983            while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
1984                mPhoneSignalStrengthsTimer[i].stopRunningLocked(this);
1985            }
1986        }
1987    }
1988
1989    private int fixPhoneServiceState(int state, int signalBin) {
1990        if (mPhoneSimStateRaw == TelephonyManager.SIM_STATE_ABSENT) {
1991            // In this case we will always be STATE_OUT_OF_SERVICE, so need
1992            // to infer that we are scanning from other data.
1993            if (state == ServiceState.STATE_OUT_OF_SERVICE
1994                    && signalBin > SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
1995                state = ServiceState.STATE_IN_SERVICE;
1996            }
1997        }
1998
1999        return state;
2000    }
2001
2002    private void updateAllPhoneStateLocked(int state, int simState, int bin) {
2003        boolean scanning = false;
2004        boolean newHistory = false;
2005
2006        mPhoneServiceStateRaw = state;
2007        mPhoneSimStateRaw = simState;
2008        mPhoneSignalStrengthBinRaw = bin;
2009
2010        if (simState == TelephonyManager.SIM_STATE_ABSENT) {
2011            // In this case we will always be STATE_OUT_OF_SERVICE, so need
2012            // to infer that we are scanning from other data.
2013            if (state == ServiceState.STATE_OUT_OF_SERVICE
2014                    && bin > SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
2015                state = ServiceState.STATE_IN_SERVICE;
2016            }
2017        }
2018
2019        // If the phone is powered off, stop all timers.
2020        if (state == ServiceState.STATE_POWER_OFF) {
2021            bin = -1;
2022
2023        // If we are in service, make sure the correct signal string timer is running.
2024        } else if (state == ServiceState.STATE_IN_SERVICE) {
2025            // Bin will be changed below.
2026
2027        // If we're out of service, we are in the lowest signal strength
2028        // bin and have the scanning bit set.
2029        } else if (state == ServiceState.STATE_OUT_OF_SERVICE) {
2030            scanning = true;
2031            bin = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
2032            if (!mPhoneSignalScanningTimer.isRunningLocked()) {
2033                mHistoryCur.states |= HistoryItem.STATE_PHONE_SCANNING_FLAG;
2034                newHistory = true;
2035                if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: "
2036                        + Integer.toHexString(mHistoryCur.states));
2037                mPhoneSignalScanningTimer.startRunningLocked(this);
2038            }
2039        }
2040
2041        if (!scanning) {
2042            // If we are no longer scanning, then stop the scanning timer.
2043            if (mPhoneSignalScanningTimer.isRunningLocked()) {
2044                mHistoryCur.states &= ~HistoryItem.STATE_PHONE_SCANNING_FLAG;
2045                if (DEBUG_HISTORY) Slog.v(TAG, "Phone stopped scanning to: "
2046                        + Integer.toHexString(mHistoryCur.states));
2047                newHistory = true;
2048                mPhoneSignalScanningTimer.stopRunningLocked(this);
2049            }
2050        }
2051
2052        if (mPhoneServiceState != state) {
2053            mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_PHONE_STATE_MASK)
2054                    | (state << HistoryItem.STATE_PHONE_STATE_SHIFT);
2055            if (DEBUG_HISTORY) Slog.v(TAG, "Phone state " + state + " to: "
2056                    + Integer.toHexString(mHistoryCur.states));
2057            newHistory = true;
2058            mPhoneServiceState = state;
2059        }
2060
2061        if (mPhoneSignalStrengthBin != bin) {
2062            if (mPhoneSignalStrengthBin >= 0) {
2063                mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this);
2064            }
2065            if (bin >= 0) {
2066                if (!mPhoneSignalStrengthsTimer[bin].isRunningLocked()) {
2067                    mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
2068                }
2069                mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_SIGNAL_STRENGTH_MASK)
2070                        | (bin << HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT);
2071                if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + bin + " to: "
2072                        + Integer.toHexString(mHistoryCur.states));
2073                newHistory = true;
2074            } else {
2075                stopAllSignalStrengthTimersLocked(-1);
2076            }
2077            mPhoneSignalStrengthBin = bin;
2078        }
2079
2080        if (newHistory) {
2081            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2082        }
2083    }
2084
2085    /**
2086     * Telephony stack updates the phone state.
2087     * @param state phone state from ServiceState.getState()
2088     */
2089    public void notePhoneStateLocked(int state, int simState) {
2090        updateAllPhoneStateLocked(state, simState, mPhoneSignalStrengthBinRaw);
2091    }
2092
2093    public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
2094        // Bin the strength.
2095        int bin = signalStrength.getLevel();
2096        updateAllPhoneStateLocked(mPhoneServiceStateRaw, mPhoneSimStateRaw, bin);
2097    }
2098
2099    public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData) {
2100        int bin = DATA_CONNECTION_NONE;
2101        if (hasData) {
2102            switch (dataType) {
2103                case TelephonyManager.NETWORK_TYPE_EDGE:
2104                    bin = DATA_CONNECTION_EDGE;
2105                    break;
2106                case TelephonyManager.NETWORK_TYPE_GPRS:
2107                    bin = DATA_CONNECTION_GPRS;
2108                    break;
2109                case TelephonyManager.NETWORK_TYPE_UMTS:
2110                    bin = DATA_CONNECTION_UMTS;
2111                    break;
2112                case TelephonyManager.NETWORK_TYPE_CDMA:
2113                    bin = DATA_CONNECTION_CDMA;
2114                    break;
2115                case TelephonyManager.NETWORK_TYPE_EVDO_0:
2116                    bin = DATA_CONNECTION_EVDO_0;
2117                    break;
2118                case TelephonyManager.NETWORK_TYPE_EVDO_A:
2119                    bin = DATA_CONNECTION_EVDO_A;
2120                    break;
2121                case TelephonyManager.NETWORK_TYPE_1xRTT:
2122                    bin = DATA_CONNECTION_1xRTT;
2123                    break;
2124                case TelephonyManager.NETWORK_TYPE_HSDPA:
2125                    bin = DATA_CONNECTION_HSDPA;
2126                    break;
2127                case TelephonyManager.NETWORK_TYPE_HSUPA:
2128                    bin = DATA_CONNECTION_HSUPA;
2129                    break;
2130                case TelephonyManager.NETWORK_TYPE_HSPA:
2131                    bin = DATA_CONNECTION_HSPA;
2132                    break;
2133                case TelephonyManager.NETWORK_TYPE_IDEN:
2134                    bin = DATA_CONNECTION_IDEN;
2135                    break;
2136                case TelephonyManager.NETWORK_TYPE_EVDO_B:
2137                    bin = DATA_CONNECTION_EVDO_B;
2138                    break;
2139                case TelephonyManager.NETWORK_TYPE_LTE:
2140                    bin = DATA_CONNECTION_LTE;
2141                    break;
2142                case TelephonyManager.NETWORK_TYPE_EHRPD:
2143                    bin = DATA_CONNECTION_EHRPD;
2144                    break;
2145                default:
2146                    bin = DATA_CONNECTION_OTHER;
2147                    break;
2148            }
2149        }
2150        if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
2151        if (mPhoneDataConnectionType != bin) {
2152            mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
2153                    | (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
2154            if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
2155                    + Integer.toHexString(mHistoryCur.states));
2156            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2157            if (mPhoneDataConnectionType >= 0) {
2158                mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this);
2159            }
2160            mPhoneDataConnectionType = bin;
2161            mPhoneDataConnectionsTimer[bin].startRunningLocked(this);
2162        }
2163    }
2164
2165    public void noteWifiOnLocked() {
2166        if (!mWifiOn) {
2167            mHistoryCur.states |= HistoryItem.STATE_WIFI_ON_FLAG;
2168            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
2169                    + Integer.toHexString(mHistoryCur.states));
2170            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2171            mWifiOn = true;
2172            mWifiOnTimer.startRunningLocked(this);
2173        }
2174    }
2175
2176    public void noteWifiOffLocked() {
2177        if (mWifiOn) {
2178            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_ON_FLAG;
2179            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
2180                    + Integer.toHexString(mHistoryCur.states));
2181            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2182            mWifiOn = false;
2183            mWifiOnTimer.stopRunningLocked(this);
2184        }
2185        if (mWifiOnUid >= 0) {
2186            getUidStatsLocked(mWifiOnUid).noteWifiStoppedLocked();
2187            mWifiOnUid = -1;
2188        }
2189    }
2190
2191    public void noteAudioOnLocked(int uid) {
2192        if (!mAudioOn) {
2193            mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
2194            if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
2195                    + Integer.toHexString(mHistoryCur.states));
2196            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2197            mAudioOn = true;
2198            mAudioOnTimer.startRunningLocked(this);
2199        }
2200        getUidStatsLocked(uid).noteAudioTurnedOnLocked();
2201    }
2202
2203    public void noteAudioOffLocked(int uid) {
2204        if (mAudioOn) {
2205            mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
2206            if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
2207                    + Integer.toHexString(mHistoryCur.states));
2208            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2209            mAudioOn = false;
2210            mAudioOnTimer.stopRunningLocked(this);
2211        }
2212        getUidStatsLocked(uid).noteAudioTurnedOffLocked();
2213    }
2214
2215    public void noteVideoOnLocked(int uid) {
2216        if (!mVideoOn) {
2217            mHistoryCur.states |= HistoryItem.STATE_VIDEO_ON_FLAG;
2218            if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
2219                    + Integer.toHexString(mHistoryCur.states));
2220            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2221            mVideoOn = true;
2222            mVideoOnTimer.startRunningLocked(this);
2223        }
2224        getUidStatsLocked(uid).noteVideoTurnedOnLocked();
2225    }
2226
2227    public void noteVideoOffLocked(int uid) {
2228        if (mVideoOn) {
2229            mHistoryCur.states &= ~HistoryItem.STATE_VIDEO_ON_FLAG;
2230            if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
2231                    + Integer.toHexString(mHistoryCur.states));
2232            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2233            mVideoOn = false;
2234            mVideoOnTimer.stopRunningLocked(this);
2235        }
2236        getUidStatsLocked(uid).noteVideoTurnedOffLocked();
2237    }
2238
2239    public void noteVibratorOnLocked(int uid, long durationMillis) {
2240        getUidStatsLocked(uid).noteVibratorOnLocked(durationMillis);
2241    }
2242
2243    public void noteVibratorOffLocked(int uid) {
2244        getUidStatsLocked(uid).noteVibratorOffLocked();
2245    }
2246
2247    public void noteWifiRunningLocked(WorkSource ws) {
2248        if (!mGlobalWifiRunning) {
2249            mHistoryCur.states |= HistoryItem.STATE_WIFI_RUNNING_FLAG;
2250            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
2251                    + Integer.toHexString(mHistoryCur.states));
2252            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2253            mGlobalWifiRunning = true;
2254            mGlobalWifiRunningTimer.startRunningLocked(this);
2255            int N = ws.size();
2256            for (int i=0; i<N; i++) {
2257                getUidStatsLocked(ws.get(i)).noteWifiRunningLocked();
2258            }
2259        } else {
2260            Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
2261        }
2262    }
2263
2264    public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
2265        if (mGlobalWifiRunning) {
2266            int N = oldWs.size();
2267            for (int i=0; i<N; i++) {
2268                getUidStatsLocked(oldWs.get(i)).noteWifiStoppedLocked();
2269            }
2270            N = newWs.size();
2271            for (int i=0; i<N; i++) {
2272                getUidStatsLocked(newWs.get(i)).noteWifiRunningLocked();
2273            }
2274        } else {
2275            Log.w(TAG, "noteWifiRunningChangedLocked -- called while WIFI not running");
2276        }
2277    }
2278
2279    public void noteWifiStoppedLocked(WorkSource ws) {
2280        if (mGlobalWifiRunning) {
2281            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RUNNING_FLAG;
2282            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
2283                    + Integer.toHexString(mHistoryCur.states));
2284            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2285            mGlobalWifiRunning = false;
2286            mGlobalWifiRunningTimer.stopRunningLocked(this);
2287            int N = ws.size();
2288            for (int i=0; i<N; i++) {
2289                getUidStatsLocked(ws.get(i)).noteWifiStoppedLocked();
2290            }
2291        } else {
2292            Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
2293        }
2294    }
2295
2296    public void noteBluetoothOnLocked() {
2297        if (!mBluetoothOn) {
2298            mHistoryCur.states |= HistoryItem.STATE_BLUETOOTH_ON_FLAG;
2299            if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth on to: "
2300                    + Integer.toHexString(mHistoryCur.states));
2301            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2302            mBluetoothOn = true;
2303            mBluetoothOnTimer.startRunningLocked(this);
2304        }
2305    }
2306
2307    public void noteBluetoothOffLocked() {
2308        if (mBluetoothOn) {
2309            mHistoryCur.states &= ~HistoryItem.STATE_BLUETOOTH_ON_FLAG;
2310            if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth off to: "
2311                    + Integer.toHexString(mHistoryCur.states));
2312            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2313            mBluetoothOn = false;
2314            mBluetoothOnTimer.stopRunningLocked(this);
2315        }
2316    }
2317
2318    int mWifiFullLockNesting = 0;
2319
2320    public void noteFullWifiLockAcquiredLocked(int uid) {
2321        if (mWifiFullLockNesting == 0) {
2322            mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
2323            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
2324                    + Integer.toHexString(mHistoryCur.states));
2325            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2326        }
2327        mWifiFullLockNesting++;
2328        getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
2329    }
2330
2331    public void noteFullWifiLockReleasedLocked(int uid) {
2332        mWifiFullLockNesting--;
2333        if (mWifiFullLockNesting == 0) {
2334            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
2335            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
2336                    + Integer.toHexString(mHistoryCur.states));
2337            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2338        }
2339        getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
2340    }
2341
2342    int mWifiScanNesting = 0;
2343
2344    public void noteWifiScanStartedLocked(int uid) {
2345        if (mWifiScanNesting == 0) {
2346            mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG;
2347            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: "
2348                    + Integer.toHexString(mHistoryCur.states));
2349            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2350        }
2351        mWifiScanNesting++;
2352        getUidStatsLocked(uid).noteWifiScanStartedLocked();
2353    }
2354
2355    public void noteWifiScanStoppedLocked(int uid) {
2356        mWifiScanNesting--;
2357        if (mWifiScanNesting == 0) {
2358            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG;
2359            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan stopped for: "
2360                    + Integer.toHexString(mHistoryCur.states));
2361            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2362        }
2363        getUidStatsLocked(uid).noteWifiScanStoppedLocked();
2364    }
2365
2366    int mWifiMulticastNesting = 0;
2367
2368    public void noteWifiMulticastEnabledLocked(int uid) {
2369        if (mWifiMulticastNesting == 0) {
2370            mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
2371            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
2372                    + Integer.toHexString(mHistoryCur.states));
2373            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2374        }
2375        mWifiMulticastNesting++;
2376        getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
2377    }
2378
2379    public void noteWifiMulticastDisabledLocked(int uid) {
2380        mWifiMulticastNesting--;
2381        if (mWifiMulticastNesting == 0) {
2382            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
2383            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
2384                    + Integer.toHexString(mHistoryCur.states));
2385            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2386        }
2387        getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
2388    }
2389
2390    public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
2391        int N = ws.size();
2392        for (int i=0; i<N; i++) {
2393            noteFullWifiLockAcquiredLocked(ws.get(i));
2394        }
2395    }
2396
2397    public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
2398        int N = ws.size();
2399        for (int i=0; i<N; i++) {
2400            noteFullWifiLockReleasedLocked(ws.get(i));
2401        }
2402    }
2403
2404    public void noteWifiScanStartedFromSourceLocked(WorkSource ws) {
2405        int N = ws.size();
2406        for (int i=0; i<N; i++) {
2407            noteWifiScanStartedLocked(ws.get(i));
2408        }
2409    }
2410
2411    public void noteWifiScanStoppedFromSourceLocked(WorkSource ws) {
2412        int N = ws.size();
2413        for (int i=0; i<N; i++) {
2414            noteWifiScanStoppedLocked(ws.get(i));
2415        }
2416    }
2417
2418    public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
2419        int N = ws.size();
2420        for (int i=0; i<N; i++) {
2421            noteWifiMulticastEnabledLocked(ws.get(i));
2422        }
2423    }
2424
2425    public void noteWifiMulticastDisabledFromSourceLocked(WorkSource ws) {
2426        int N = ws.size();
2427        for (int i=0; i<N; i++) {
2428            noteWifiMulticastDisabledLocked(ws.get(i));
2429        }
2430    }
2431
2432    public void noteNetworkInterfaceTypeLocked(String iface, int networkType) {
2433        if (ConnectivityManager.isNetworkTypeMobile(networkType)) {
2434            mMobileIfaces.add(iface);
2435        } else {
2436            mMobileIfaces.remove(iface);
2437        }
2438    }
2439
2440    @Override public long getScreenOnTime(long batteryRealtime, int which) {
2441        return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
2442    }
2443
2444    @Override public long getScreenBrightnessTime(int brightnessBin,
2445            long batteryRealtime, int which) {
2446        return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
2447                batteryRealtime, which);
2448    }
2449
2450    @Override public int getInputEventCount(int which) {
2451        return mInputEventCounter.getCountLocked(which);
2452    }
2453
2454    @Override public long getPhoneOnTime(long batteryRealtime, int which) {
2455        return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
2456    }
2457
2458    @Override public long getPhoneSignalStrengthTime(int strengthBin,
2459            long batteryRealtime, int which) {
2460        return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
2461                batteryRealtime, which);
2462    }
2463
2464    @Override public long getPhoneSignalScanningTime(
2465            long batteryRealtime, int which) {
2466        return mPhoneSignalScanningTimer.getTotalTimeLocked(
2467                batteryRealtime, which);
2468    }
2469
2470    @Override public int getPhoneSignalStrengthCount(int strengthBin, int which) {
2471        return mPhoneSignalStrengthsTimer[strengthBin].getCountLocked(which);
2472    }
2473
2474    @Override public long getPhoneDataConnectionTime(int dataType,
2475            long batteryRealtime, int which) {
2476        return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
2477                batteryRealtime, which);
2478    }
2479
2480    @Override public int getPhoneDataConnectionCount(int dataType, int which) {
2481        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
2482    }
2483
2484    @Override public long getWifiOnTime(long batteryRealtime, int which) {
2485        return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
2486    }
2487
2488    @Override public long getGlobalWifiRunningTime(long batteryRealtime, int which) {
2489        return mGlobalWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
2490    }
2491
2492    @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
2493        return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
2494    }
2495
2496    @Override public boolean getIsOnBattery() {
2497        return mOnBattery;
2498    }
2499
2500    @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
2501        return mUidStats;
2502    }
2503
2504    /**
2505     * The statistics associated with a particular uid.
2506     */
2507    public final class Uid extends BatteryStats.Uid {
2508
2509        final int mUid;
2510        long mLoadedTcpBytesReceived;
2511        long mLoadedTcpBytesSent;
2512        long mCurrentTcpBytesReceived;
2513        long mCurrentTcpBytesSent;
2514        long mTcpBytesReceivedAtLastUnplug;
2515        long mTcpBytesSentAtLastUnplug;
2516
2517        // These are not saved/restored when parcelling, since we want
2518        // to return from the parcel with a snapshot of the state.
2519        long mStartedTcpBytesReceived = -1;
2520        long mStartedTcpBytesSent = -1;
2521
2522        boolean mWifiRunning;
2523        StopwatchTimer mWifiRunningTimer;
2524
2525        boolean mFullWifiLockOut;
2526        StopwatchTimer mFullWifiLockTimer;
2527
2528        boolean mWifiScanStarted;
2529        StopwatchTimer mWifiScanTimer;
2530
2531        boolean mWifiMulticastEnabled;
2532        StopwatchTimer mWifiMulticastTimer;
2533
2534        boolean mAudioTurnedOn;
2535        StopwatchTimer mAudioTurnedOnTimer;
2536
2537        boolean mVideoTurnedOn;
2538        StopwatchTimer mVideoTurnedOnTimer;
2539
2540        BatchTimer mVibratorOnTimer;
2541
2542        Counter[] mUserActivityCounters;
2543
2544        /**
2545         * The statistics we have collected for this uid's wake locks.
2546         */
2547        final HashMap<String, Wakelock> mWakelockStats = new HashMap<String, Wakelock>();
2548
2549        /**
2550         * The statistics we have collected for this uid's sensor activations.
2551         */
2552        final HashMap<Integer, Sensor> mSensorStats = new HashMap<Integer, Sensor>();
2553
2554        /**
2555         * The statistics we have collected for this uid's processes.
2556         */
2557        final HashMap<String, Proc> mProcessStats = new HashMap<String, Proc>();
2558
2559        /**
2560         * The statistics we have collected for this uid's processes.
2561         */
2562        final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
2563
2564        /**
2565         * The transient wake stats we have collected for this uid's pids.
2566         */
2567        final SparseArray<Pid> mPids = new SparseArray<Pid>();
2568
2569        public Uid(int uid) {
2570            mUid = uid;
2571            mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
2572                    mWifiRunningTimers, mUnpluggables);
2573            mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
2574                    mFullWifiLockTimers, mUnpluggables);
2575            mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
2576                    mWifiScanTimers, mUnpluggables);
2577            mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
2578                    mWifiMulticastTimers, mUnpluggables);
2579        }
2580
2581        @Override
2582        public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
2583            return mWakelockStats;
2584        }
2585
2586        @Override
2587        public Map<Integer, ? extends BatteryStats.Uid.Sensor> getSensorStats() {
2588            return mSensorStats;
2589        }
2590
2591        @Override
2592        public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
2593            return mProcessStats;
2594        }
2595
2596        @Override
2597        public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
2598            return mPackageStats;
2599        }
2600
2601        @Override
2602        public int getUid() {
2603            return mUid;
2604        }
2605
2606        @Override
2607        public long getTcpBytesReceived(int which) {
2608            if (which == STATS_LAST) {
2609                return mLoadedTcpBytesReceived;
2610            } else {
2611                long current = computeCurrentTcpBytesReceived();
2612                if (which == STATS_SINCE_UNPLUGGED) {
2613                    current -= mTcpBytesReceivedAtLastUnplug;
2614                } else if (which == STATS_SINCE_CHARGED) {
2615                    current += mLoadedTcpBytesReceived;
2616                }
2617                return current;
2618            }
2619        }
2620
2621        public long computeCurrentTcpBytesReceived() {
2622            final long uidRxBytes = getNetworkStatsDetailGroupedByUid().getTotal(
2623                    null, mUid).rxBytes;
2624            return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
2625                    ? (uidRxBytes - mStartedTcpBytesReceived) : 0);
2626        }
2627
2628        @Override
2629        public long getTcpBytesSent(int which) {
2630            if (which == STATS_LAST) {
2631                return mLoadedTcpBytesSent;
2632            } else {
2633                long current = computeCurrentTcpBytesSent();
2634                if (which == STATS_SINCE_UNPLUGGED) {
2635                    current -= mTcpBytesSentAtLastUnplug;
2636                } else if (which == STATS_SINCE_CHARGED) {
2637                    current += mLoadedTcpBytesSent;
2638                }
2639                return current;
2640            }
2641        }
2642
2643        @Override
2644        public void noteWifiRunningLocked() {
2645            if (!mWifiRunning) {
2646                mWifiRunning = true;
2647                if (mWifiRunningTimer == null) {
2648                    mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
2649                            mWifiRunningTimers, mUnpluggables);
2650                }
2651                mWifiRunningTimer.startRunningLocked(BatteryStatsImpl.this);
2652            }
2653        }
2654
2655        @Override
2656        public void noteWifiStoppedLocked() {
2657            if (mWifiRunning) {
2658                mWifiRunning = false;
2659                mWifiRunningTimer.stopRunningLocked(BatteryStatsImpl.this);
2660            }
2661        }
2662
2663        @Override
2664        public void noteFullWifiLockAcquiredLocked() {
2665            if (!mFullWifiLockOut) {
2666                mFullWifiLockOut = true;
2667                if (mFullWifiLockTimer == null) {
2668                    mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
2669                            mFullWifiLockTimers, mUnpluggables);
2670                }
2671                mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
2672            }
2673        }
2674
2675        @Override
2676        public void noteFullWifiLockReleasedLocked() {
2677            if (mFullWifiLockOut) {
2678                mFullWifiLockOut = false;
2679                mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
2680            }
2681        }
2682
2683        @Override
2684        public void noteWifiScanStartedLocked() {
2685            if (!mWifiScanStarted) {
2686                mWifiScanStarted = true;
2687                if (mWifiScanTimer == null) {
2688                    mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
2689                            mWifiScanTimers, mUnpluggables);
2690                }
2691                mWifiScanTimer.startRunningLocked(BatteryStatsImpl.this);
2692            }
2693        }
2694
2695        @Override
2696        public void noteWifiScanStoppedLocked() {
2697            if (mWifiScanStarted) {
2698                mWifiScanStarted = false;
2699                mWifiScanTimer.stopRunningLocked(BatteryStatsImpl.this);
2700            }
2701        }
2702
2703        @Override
2704        public void noteWifiMulticastEnabledLocked() {
2705            if (!mWifiMulticastEnabled) {
2706                mWifiMulticastEnabled = true;
2707                if (mWifiMulticastTimer == null) {
2708                    mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
2709                            mWifiMulticastTimers, mUnpluggables);
2710                }
2711                mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
2712            }
2713        }
2714
2715        @Override
2716        public void noteWifiMulticastDisabledLocked() {
2717            if (mWifiMulticastEnabled) {
2718                mWifiMulticastEnabled = false;
2719                mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
2720            }
2721        }
2722
2723        public StopwatchTimer createAudioTurnedOnTimerLocked() {
2724            if (mAudioTurnedOnTimer == null) {
2725                mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
2726                        null, mUnpluggables);
2727            }
2728            return mAudioTurnedOnTimer;
2729        }
2730
2731        @Override
2732        public void noteAudioTurnedOnLocked() {
2733            if (!mAudioTurnedOn) {
2734                mAudioTurnedOn = true;
2735                createAudioTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this);
2736            }
2737        }
2738
2739        @Override
2740        public void noteAudioTurnedOffLocked() {
2741            if (mAudioTurnedOn) {
2742                mAudioTurnedOn = false;
2743                if (mAudioTurnedOnTimer != null) {
2744                    mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
2745                }
2746            }
2747        }
2748
2749        public StopwatchTimer createVideoTurnedOnTimerLocked() {
2750            if (mVideoTurnedOnTimer == null) {
2751                mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
2752                        null, mUnpluggables);
2753            }
2754            return mVideoTurnedOnTimer;
2755        }
2756
2757        @Override
2758        public void noteVideoTurnedOnLocked() {
2759            if (!mVideoTurnedOn) {
2760                mVideoTurnedOn = true;
2761                createVideoTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this);
2762            }
2763        }
2764
2765        @Override
2766        public void noteVideoTurnedOffLocked() {
2767            if (mVideoTurnedOn) {
2768                mVideoTurnedOn = false;
2769                if (mVideoTurnedOnTimer != null) {
2770                    mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
2771                }
2772            }
2773        }
2774
2775        public BatchTimer createVibratorOnTimerLocked() {
2776            if (mVibratorOnTimer == null) {
2777                mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON,
2778                        mUnpluggables, BatteryStatsImpl.this.mOnBatteryInternal);
2779            }
2780            return mVibratorOnTimer;
2781        }
2782
2783        public void noteVibratorOnLocked(long durationMillis) {
2784            createVibratorOnTimerLocked().addDuration(BatteryStatsImpl.this, durationMillis);
2785        }
2786
2787        public void noteVibratorOffLocked() {
2788            if (mVibratorOnTimer != null) {
2789                mVibratorOnTimer.abortLastDuration(BatteryStatsImpl.this);
2790            }
2791        }
2792
2793        @Override
2794        public long getWifiRunningTime(long batteryRealtime, int which) {
2795            if (mWifiRunningTimer == null) {
2796                return 0;
2797            }
2798            return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
2799        }
2800
2801        @Override
2802        public long getFullWifiLockTime(long batteryRealtime, int which) {
2803            if (mFullWifiLockTimer == null) {
2804                return 0;
2805            }
2806            return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
2807        }
2808
2809        @Override
2810        public long getWifiScanTime(long batteryRealtime, int which) {
2811            if (mWifiScanTimer == null) {
2812                return 0;
2813            }
2814            return mWifiScanTimer.getTotalTimeLocked(batteryRealtime, which);
2815        }
2816
2817        @Override
2818        public long getWifiMulticastTime(long batteryRealtime, int which) {
2819            if (mWifiMulticastTimer == null) {
2820                return 0;
2821            }
2822            return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime,
2823                                                          which);
2824        }
2825
2826        @Override
2827        public long getAudioTurnedOnTime(long batteryRealtime, int which) {
2828            if (mAudioTurnedOnTimer == null) {
2829                return 0;
2830            }
2831            return mAudioTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
2832        }
2833
2834        @Override
2835        public long getVideoTurnedOnTime(long batteryRealtime, int which) {
2836            if (mVideoTurnedOnTimer == null) {
2837                return 0;
2838            }
2839            return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
2840        }
2841
2842        @Override
2843        public Timer getVibratorOnTimer() {
2844            return mVibratorOnTimer;
2845        }
2846
2847        @Override
2848        public void noteUserActivityLocked(int type) {
2849            if (mUserActivityCounters == null) {
2850                initUserActivityLocked();
2851            }
2852            if (type >= 0 && type < NUM_USER_ACTIVITY_TYPES) {
2853                mUserActivityCounters[type].stepAtomic();
2854            } else {
2855                Slog.w(TAG, "Unknown user activity type " + type + " was specified.",
2856                        new Throwable());
2857            }
2858        }
2859
2860        @Override
2861        public boolean hasUserActivity() {
2862            return mUserActivityCounters != null;
2863        }
2864
2865        @Override
2866        public int getUserActivityCount(int type, int which) {
2867            if (mUserActivityCounters == null) {
2868                return 0;
2869            }
2870            return mUserActivityCounters[type].getCountLocked(which);
2871        }
2872
2873        void initUserActivityLocked() {
2874            mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
2875            for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2876                mUserActivityCounters[i] = new Counter(mUnpluggables);
2877            }
2878        }
2879
2880        public long computeCurrentTcpBytesSent() {
2881            final long uidTxBytes = getNetworkStatsDetailGroupedByUid().getTotal(
2882                    null, mUid).txBytes;
2883            return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
2884                    ? (uidTxBytes - mStartedTcpBytesSent) : 0);
2885        }
2886
2887        /**
2888         * Clear all stats for this uid.  Returns true if the uid is completely
2889         * inactive so can be dropped.
2890         */
2891        boolean reset() {
2892            boolean active = false;
2893
2894            if (mWifiRunningTimer != null) {
2895                active |= !mWifiRunningTimer.reset(BatteryStatsImpl.this, false);
2896                active |= mWifiRunning;
2897            }
2898            if (mFullWifiLockTimer != null) {
2899                active |= !mFullWifiLockTimer.reset(BatteryStatsImpl.this, false);
2900                active |= mFullWifiLockOut;
2901            }
2902            if (mWifiScanTimer != null) {
2903                active |= !mWifiScanTimer.reset(BatteryStatsImpl.this, false);
2904                active |= mWifiScanStarted;
2905            }
2906            if (mWifiMulticastTimer != null) {
2907                active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
2908                active |= mWifiMulticastEnabled;
2909            }
2910            if (mAudioTurnedOnTimer != null) {
2911                active |= !mAudioTurnedOnTimer.reset(BatteryStatsImpl.this, false);
2912                active |= mAudioTurnedOn;
2913            }
2914            if (mVideoTurnedOnTimer != null) {
2915                active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
2916                active |= mVideoTurnedOn;
2917            }
2918            if (mVibratorOnTimer != null) {
2919                if (mVibratorOnTimer.reset(BatteryStatsImpl.this, false)) {
2920                    mVibratorOnTimer.detach();
2921                    mVibratorOnTimer = null;
2922                } else {
2923                    active = true;
2924                }
2925            }
2926
2927            mLoadedTcpBytesReceived = mLoadedTcpBytesSent = 0;
2928            mCurrentTcpBytesReceived = mCurrentTcpBytesSent = 0;
2929
2930            if (mUserActivityCounters != null) {
2931                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2932                    mUserActivityCounters[i].reset(false);
2933                }
2934            }
2935
2936            if (mWakelockStats.size() > 0) {
2937                Iterator<Map.Entry<String, Wakelock>> it = mWakelockStats.entrySet().iterator();
2938                while (it.hasNext()) {
2939                    Map.Entry<String, Wakelock> wakelockEntry = it.next();
2940                    Wakelock wl = wakelockEntry.getValue();
2941                    if (wl.reset()) {
2942                        it.remove();
2943                    } else {
2944                        active = true;
2945                    }
2946                }
2947            }
2948            if (mSensorStats.size() > 0) {
2949                Iterator<Map.Entry<Integer, Sensor>> it = mSensorStats.entrySet().iterator();
2950                while (it.hasNext()) {
2951                    Map.Entry<Integer, Sensor> sensorEntry = it.next();
2952                    Sensor s = sensorEntry.getValue();
2953                    if (s.reset()) {
2954                        it.remove();
2955                    } else {
2956                        active = true;
2957                    }
2958                }
2959            }
2960            if (mProcessStats.size() > 0) {
2961                Iterator<Map.Entry<String, Proc>> it = mProcessStats.entrySet().iterator();
2962                while (it.hasNext()) {
2963                    Map.Entry<String, Proc> procEntry = it.next();
2964                    procEntry.getValue().detach();
2965                }
2966                mProcessStats.clear();
2967            }
2968            if (mPids.size() > 0) {
2969                for (int i=0; !active && i<mPids.size(); i++) {
2970                    Pid pid = mPids.valueAt(i);
2971                    if (pid.mWakeStart != 0) {
2972                        active = true;
2973                    }
2974                }
2975            }
2976            if (mPackageStats.size() > 0) {
2977                Iterator<Map.Entry<String, Pkg>> it = mPackageStats.entrySet().iterator();
2978                while (it.hasNext()) {
2979                    Map.Entry<String, Pkg> pkgEntry = it.next();
2980                    Pkg p = pkgEntry.getValue();
2981                    p.detach();
2982                    if (p.mServiceStats.size() > 0) {
2983                        Iterator<Map.Entry<String, Pkg.Serv>> it2
2984                                = p.mServiceStats.entrySet().iterator();
2985                        while (it2.hasNext()) {
2986                            Map.Entry<String, Pkg.Serv> servEntry = it2.next();
2987                            servEntry.getValue().detach();
2988                        }
2989                    }
2990                }
2991                mPackageStats.clear();
2992            }
2993
2994            mPids.clear();
2995
2996            if (!active) {
2997                if (mWifiRunningTimer != null) {
2998                    mWifiRunningTimer.detach();
2999                }
3000                if (mFullWifiLockTimer != null) {
3001                    mFullWifiLockTimer.detach();
3002                }
3003                if (mWifiScanTimer != null) {
3004                    mWifiScanTimer.detach();
3005                }
3006                if (mWifiMulticastTimer != null) {
3007                    mWifiMulticastTimer.detach();
3008                }
3009                if (mAudioTurnedOnTimer != null) {
3010                    mAudioTurnedOnTimer.detach();
3011                    mAudioTurnedOnTimer = null;
3012                }
3013                if (mVideoTurnedOnTimer != null) {
3014                    mVideoTurnedOnTimer.detach();
3015                    mVideoTurnedOnTimer = null;
3016                }
3017                if (mUserActivityCounters != null) {
3018                    for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
3019                        mUserActivityCounters[i].detach();
3020                    }
3021                }
3022            }
3023
3024            return !active;
3025        }
3026
3027        void writeToParcelLocked(Parcel out, long batteryRealtime) {
3028            out.writeInt(mWakelockStats.size());
3029            for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
3030                out.writeString(wakelockEntry.getKey());
3031                Uid.Wakelock wakelock = wakelockEntry.getValue();
3032                wakelock.writeToParcelLocked(out, batteryRealtime);
3033            }
3034
3035            out.writeInt(mSensorStats.size());
3036            for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
3037                out.writeInt(sensorEntry.getKey());
3038                Uid.Sensor sensor = sensorEntry.getValue();
3039                sensor.writeToParcelLocked(out, batteryRealtime);
3040            }
3041
3042            out.writeInt(mProcessStats.size());
3043            for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
3044                out.writeString(procEntry.getKey());
3045                Uid.Proc proc = procEntry.getValue();
3046                proc.writeToParcelLocked(out);
3047            }
3048
3049            out.writeInt(mPackageStats.size());
3050            for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
3051                out.writeString(pkgEntry.getKey());
3052                Uid.Pkg pkg = pkgEntry.getValue();
3053                pkg.writeToParcelLocked(out);
3054            }
3055
3056            out.writeLong(mLoadedTcpBytesReceived);
3057            out.writeLong(mLoadedTcpBytesSent);
3058            out.writeLong(computeCurrentTcpBytesReceived());
3059            out.writeLong(computeCurrentTcpBytesSent());
3060            out.writeLong(mTcpBytesReceivedAtLastUnplug);
3061            out.writeLong(mTcpBytesSentAtLastUnplug);
3062            if (mWifiRunningTimer != null) {
3063                out.writeInt(1);
3064                mWifiRunningTimer.writeToParcel(out, batteryRealtime);
3065            } else {
3066                out.writeInt(0);
3067            }
3068            if (mFullWifiLockTimer != null) {
3069                out.writeInt(1);
3070                mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
3071            } else {
3072                out.writeInt(0);
3073            }
3074            if (mWifiScanTimer != null) {
3075                out.writeInt(1);
3076                mWifiScanTimer.writeToParcel(out, batteryRealtime);
3077            } else {
3078                out.writeInt(0);
3079            }
3080            if (mWifiMulticastTimer != null) {
3081                out.writeInt(1);
3082                mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
3083            } else {
3084                out.writeInt(0);
3085            }
3086            if (mAudioTurnedOnTimer != null) {
3087                out.writeInt(1);
3088                mAudioTurnedOnTimer.writeToParcel(out, batteryRealtime);
3089            } else {
3090                out.writeInt(0);
3091            }
3092            if (mVideoTurnedOnTimer != null) {
3093                out.writeInt(1);
3094                mVideoTurnedOnTimer.writeToParcel(out, batteryRealtime);
3095            } else {
3096                out.writeInt(0);
3097            }
3098            if (mVibratorOnTimer != null) {
3099                out.writeInt(1);
3100                mVibratorOnTimer.writeToParcel(out, batteryRealtime);
3101            } else {
3102                out.writeInt(0);
3103            }
3104            if (mUserActivityCounters != null) {
3105                out.writeInt(1);
3106                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
3107                    mUserActivityCounters[i].writeToParcel(out);
3108                }
3109            } else {
3110                out.writeInt(0);
3111            }
3112        }
3113
3114        void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
3115            int numWakelocks = in.readInt();
3116            mWakelockStats.clear();
3117            for (int j = 0; j < numWakelocks; j++) {
3118                String wakelockName = in.readString();
3119                Uid.Wakelock wakelock = new Wakelock();
3120                wakelock.readFromParcelLocked(unpluggables, in);
3121                // We will just drop some random set of wakelocks if
3122                // the previous run of the system was an older version
3123                // that didn't impose a limit.
3124                mWakelockStats.put(wakelockName, wakelock);
3125            }
3126
3127            int numSensors = in.readInt();
3128            mSensorStats.clear();
3129            for (int k = 0; k < numSensors; k++) {
3130                int sensorNumber = in.readInt();
3131                Uid.Sensor sensor = new Sensor(sensorNumber);
3132                sensor.readFromParcelLocked(mUnpluggables, in);
3133                mSensorStats.put(sensorNumber, sensor);
3134            }
3135
3136            int numProcs = in.readInt();
3137            mProcessStats.clear();
3138            for (int k = 0; k < numProcs; k++) {
3139                String processName = in.readString();
3140                Uid.Proc proc = new Proc();
3141                proc.readFromParcelLocked(in);
3142                mProcessStats.put(processName, proc);
3143            }
3144
3145            int numPkgs = in.readInt();
3146            mPackageStats.clear();
3147            for (int l = 0; l < numPkgs; l++) {
3148                String packageName = in.readString();
3149                Uid.Pkg pkg = new Pkg();
3150                pkg.readFromParcelLocked(in);
3151                mPackageStats.put(packageName, pkg);
3152            }
3153
3154            mLoadedTcpBytesReceived = in.readLong();
3155            mLoadedTcpBytesSent = in.readLong();
3156            mCurrentTcpBytesReceived = in.readLong();
3157            mCurrentTcpBytesSent = in.readLong();
3158            mTcpBytesReceivedAtLastUnplug = in.readLong();
3159            mTcpBytesSentAtLastUnplug = in.readLong();
3160            mWifiRunning = false;
3161            if (in.readInt() != 0) {
3162                mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
3163                        mWifiRunningTimers, mUnpluggables, in);
3164            } else {
3165                mWifiRunningTimer = null;
3166            }
3167            mFullWifiLockOut = false;
3168            if (in.readInt() != 0) {
3169                mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
3170                        mFullWifiLockTimers, mUnpluggables, in);
3171            } else {
3172                mFullWifiLockTimer = null;
3173            }
3174            mWifiScanStarted = false;
3175            if (in.readInt() != 0) {
3176                mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
3177                        mWifiScanTimers, mUnpluggables, in);
3178            } else {
3179                mWifiScanTimer = null;
3180            }
3181            mWifiMulticastEnabled = false;
3182            if (in.readInt() != 0) {
3183                mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
3184                        mWifiMulticastTimers, mUnpluggables, in);
3185            } else {
3186                mWifiMulticastTimer = null;
3187            }
3188            mAudioTurnedOn = false;
3189            if (in.readInt() != 0) {
3190                mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
3191                        null, mUnpluggables, in);
3192            } else {
3193                mAudioTurnedOnTimer = null;
3194            }
3195            mVideoTurnedOn = false;
3196            if (in.readInt() != 0) {
3197                mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
3198                        null, mUnpluggables, in);
3199            } else {
3200                mVideoTurnedOnTimer = null;
3201            }
3202            if (in.readInt() != 0) {
3203                mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON,
3204                        mUnpluggables, BatteryStatsImpl.this.mOnBatteryInternal, in);
3205            } else {
3206                mVibratorOnTimer = null;
3207            }
3208            if (in.readInt() != 0) {
3209                mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
3210                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
3211                    mUserActivityCounters[i] = new Counter(mUnpluggables, in);
3212                }
3213            } else {
3214                mUserActivityCounters = null;
3215            }
3216        }
3217
3218        /**
3219         * The statistics associated with a particular wake lock.
3220         */
3221        public final class Wakelock extends BatteryStats.Uid.Wakelock {
3222            /**
3223             * How long (in ms) this uid has been keeping the device partially awake.
3224             */
3225            StopwatchTimer mTimerPartial;
3226
3227            /**
3228             * How long (in ms) this uid has been keeping the device fully awake.
3229             */
3230            StopwatchTimer mTimerFull;
3231
3232            /**
3233             * How long (in ms) this uid has had a window keeping the device awake.
3234             */
3235            StopwatchTimer mTimerWindow;
3236
3237            /**
3238             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
3239             * proper timer pool from the given BatteryStatsImpl object.
3240             *
3241             * @param in the Parcel to be read from.
3242             * return a new Timer, or null.
3243             */
3244            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
3245                    ArrayList<Unpluggable> unpluggables, Parcel in) {
3246                if (in.readInt() == 0) {
3247                    return null;
3248                }
3249
3250                return new StopwatchTimer(Uid.this, type, pool, unpluggables, in);
3251            }
3252
3253            boolean reset() {
3254                boolean wlactive = false;
3255                if (mTimerFull != null) {
3256                    wlactive |= !mTimerFull.reset(BatteryStatsImpl.this, false);
3257                }
3258                if (mTimerPartial != null) {
3259                    wlactive |= !mTimerPartial.reset(BatteryStatsImpl.this, false);
3260                }
3261                if (mTimerWindow != null) {
3262                    wlactive |= !mTimerWindow.reset(BatteryStatsImpl.this, false);
3263                }
3264                if (!wlactive) {
3265                    if (mTimerFull != null) {
3266                        mTimerFull.detach();
3267                        mTimerFull = null;
3268                    }
3269                    if (mTimerPartial != null) {
3270                        mTimerPartial.detach();
3271                        mTimerPartial = null;
3272                    }
3273                    if (mTimerWindow != null) {
3274                        mTimerWindow.detach();
3275                        mTimerWindow = null;
3276                    }
3277                }
3278                return !wlactive;
3279            }
3280
3281            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
3282                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
3283                        mPartialTimers, unpluggables, in);
3284                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
3285                        mFullTimers, unpluggables, in);
3286                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
3287                        mWindowTimers, unpluggables, in);
3288            }
3289
3290            void writeToParcelLocked(Parcel out, long batteryRealtime) {
3291                Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
3292                Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
3293                Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
3294            }
3295
3296            @Override
3297            public Timer getWakeTime(int type) {
3298                switch (type) {
3299                case WAKE_TYPE_FULL: return mTimerFull;
3300                case WAKE_TYPE_PARTIAL: return mTimerPartial;
3301                case WAKE_TYPE_WINDOW: return mTimerWindow;
3302                default: throw new IllegalArgumentException("type = " + type);
3303                }
3304            }
3305        }
3306
3307        public final class Sensor extends BatteryStats.Uid.Sensor {
3308            final int mHandle;
3309            StopwatchTimer mTimer;
3310
3311            public Sensor(int handle) {
3312                mHandle = handle;
3313            }
3314
3315            private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
3316                    Parcel in) {
3317                if (in.readInt() == 0) {
3318                    return null;
3319                }
3320
3321                ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
3322                if (pool == null) {
3323                    pool = new ArrayList<StopwatchTimer>();
3324                    mSensorTimers.put(mHandle, pool);
3325                }
3326                return new StopwatchTimer(Uid.this, 0, pool, unpluggables, in);
3327            }
3328
3329            boolean reset() {
3330                if (mTimer.reset(BatteryStatsImpl.this, true)) {
3331                    mTimer = null;
3332                    return true;
3333                }
3334                return false;
3335            }
3336
3337            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
3338                mTimer = readTimerFromParcel(unpluggables, in);
3339            }
3340
3341            void writeToParcelLocked(Parcel out, long batteryRealtime) {
3342                Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
3343            }
3344
3345            @Override
3346            public Timer getSensorTime() {
3347                return mTimer;
3348            }
3349
3350            @Override
3351            public int getHandle() {
3352                return mHandle;
3353            }
3354        }
3355
3356        /**
3357         * The statistics associated with a particular process.
3358         */
3359        public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
3360            /**
3361             * Total time (in 1/100 sec) spent executing in user code.
3362             */
3363            long mUserTime;
3364
3365            /**
3366             * Total time (in 1/100 sec) spent executing in kernel code.
3367             */
3368            long mSystemTime;
3369
3370            /**
3371             * Number of times the process has been started.
3372             */
3373            int mStarts;
3374
3375            /**
3376             * Amount of time the process was running in the foreground.
3377             */
3378            long mForegroundTime;
3379
3380            /**
3381             * The amount of user time loaded from a previous save.
3382             */
3383            long mLoadedUserTime;
3384
3385            /**
3386             * The amount of system time loaded from a previous save.
3387             */
3388            long mLoadedSystemTime;
3389
3390            /**
3391             * The number of times the process has started from a previous save.
3392             */
3393            int mLoadedStarts;
3394
3395            /**
3396             * The amount of foreground time loaded from a previous save.
3397             */
3398            long mLoadedForegroundTime;
3399
3400            /**
3401             * The amount of user time loaded from the previous run.
3402             */
3403            long mLastUserTime;
3404
3405            /**
3406             * The amount of system time loaded from the previous run.
3407             */
3408            long mLastSystemTime;
3409
3410            /**
3411             * The number of times the process has started from the previous run.
3412             */
3413            int mLastStarts;
3414
3415            /**
3416             * The amount of foreground time loaded from the previous run
3417             */
3418            long mLastForegroundTime;
3419
3420            /**
3421             * The amount of user time when last unplugged.
3422             */
3423            long mUnpluggedUserTime;
3424
3425            /**
3426             * The amount of system time when last unplugged.
3427             */
3428            long mUnpluggedSystemTime;
3429
3430            /**
3431             * The number of times the process has started before unplugged.
3432             */
3433            int mUnpluggedStarts;
3434
3435            /**
3436             * The amount of foreground time since unplugged.
3437             */
3438            long mUnpluggedForegroundTime;
3439
3440            SamplingCounter[] mSpeedBins;
3441
3442            ArrayList<ExcessivePower> mExcessivePower;
3443
3444            Proc() {
3445                mUnpluggables.add(this);
3446                mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
3447            }
3448
3449            public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
3450                mUnpluggedUserTime = mUserTime;
3451                mUnpluggedSystemTime = mSystemTime;
3452                mUnpluggedStarts = mStarts;
3453                mUnpluggedForegroundTime = mForegroundTime;
3454            }
3455
3456            public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
3457            }
3458
3459            void detach() {
3460                mUnpluggables.remove(this);
3461                for (int i = 0; i < mSpeedBins.length; i++) {
3462                    SamplingCounter c = mSpeedBins[i];
3463                    if (c != null) {
3464                        mUnpluggables.remove(c);
3465                        mSpeedBins[i] = null;
3466                    }
3467                }
3468            }
3469
3470            public int countExcessivePowers() {
3471                return mExcessivePower != null ? mExcessivePower.size() : 0;
3472            }
3473
3474            public ExcessivePower getExcessivePower(int i) {
3475                if (mExcessivePower != null) {
3476                    return mExcessivePower.get(i);
3477                }
3478                return null;
3479            }
3480
3481            public void addExcessiveWake(long overTime, long usedTime) {
3482                if (mExcessivePower == null) {
3483                    mExcessivePower = new ArrayList<ExcessivePower>();
3484                }
3485                ExcessivePower ew = new ExcessivePower();
3486                ew.type = ExcessivePower.TYPE_WAKE;
3487                ew.overTime = overTime;
3488                ew.usedTime = usedTime;
3489                mExcessivePower.add(ew);
3490            }
3491
3492            public void addExcessiveCpu(long overTime, long usedTime) {
3493                if (mExcessivePower == null) {
3494                    mExcessivePower = new ArrayList<ExcessivePower>();
3495                }
3496                ExcessivePower ew = new ExcessivePower();
3497                ew.type = ExcessivePower.TYPE_CPU;
3498                ew.overTime = overTime;
3499                ew.usedTime = usedTime;
3500                mExcessivePower.add(ew);
3501            }
3502
3503            void writeExcessivePowerToParcelLocked(Parcel out) {
3504                if (mExcessivePower == null) {
3505                    out.writeInt(0);
3506                    return;
3507                }
3508
3509                final int N = mExcessivePower.size();
3510                out.writeInt(N);
3511                for (int i=0; i<N; i++) {
3512                    ExcessivePower ew = mExcessivePower.get(i);
3513                    out.writeInt(ew.type);
3514                    out.writeLong(ew.overTime);
3515                    out.writeLong(ew.usedTime);
3516                }
3517            }
3518
3519            boolean readExcessivePowerFromParcelLocked(Parcel in) {
3520                final int N = in.readInt();
3521                if (N == 0) {
3522                    mExcessivePower = null;
3523                    return true;
3524                }
3525
3526                if (N > 10000) {
3527                    Slog.w(TAG, "File corrupt: too many excessive power entries " + N);
3528                    return false;
3529                }
3530
3531                mExcessivePower = new ArrayList<ExcessivePower>();
3532                for (int i=0; i<N; i++) {
3533                    ExcessivePower ew = new ExcessivePower();
3534                    ew.type = in.readInt();
3535                    ew.overTime = in.readLong();
3536                    ew.usedTime = in.readLong();
3537                    mExcessivePower.add(ew);
3538                }
3539                return true;
3540            }
3541
3542            void writeToParcelLocked(Parcel out) {
3543                out.writeLong(mUserTime);
3544                out.writeLong(mSystemTime);
3545                out.writeLong(mForegroundTime);
3546                out.writeInt(mStarts);
3547                out.writeLong(mLoadedUserTime);
3548                out.writeLong(mLoadedSystemTime);
3549                out.writeLong(mLoadedForegroundTime);
3550                out.writeInt(mLoadedStarts);
3551                out.writeLong(mUnpluggedUserTime);
3552                out.writeLong(mUnpluggedSystemTime);
3553                out.writeLong(mUnpluggedForegroundTime);
3554                out.writeInt(mUnpluggedStarts);
3555
3556                out.writeInt(mSpeedBins.length);
3557                for (int i = 0; i < mSpeedBins.length; i++) {
3558                    SamplingCounter c = mSpeedBins[i];
3559                    if (c != null) {
3560                        out.writeInt(1);
3561                        c.writeToParcel(out);
3562                    } else {
3563                        out.writeInt(0);
3564                    }
3565                }
3566
3567                writeExcessivePowerToParcelLocked(out);
3568            }
3569
3570            void readFromParcelLocked(Parcel in) {
3571                mUserTime = in.readLong();
3572                mSystemTime = in.readLong();
3573                mForegroundTime = in.readLong();
3574                mStarts = in.readInt();
3575                mLoadedUserTime = in.readLong();
3576                mLoadedSystemTime = in.readLong();
3577                mLoadedForegroundTime = in.readLong();
3578                mLoadedStarts = in.readInt();
3579                mLastUserTime = 0;
3580                mLastSystemTime = 0;
3581                mLastForegroundTime = 0;
3582                mLastStarts = 0;
3583                mUnpluggedUserTime = in.readLong();
3584                mUnpluggedSystemTime = in.readLong();
3585                mUnpluggedForegroundTime = in.readLong();
3586                mUnpluggedStarts = in.readInt();
3587
3588                int bins = in.readInt();
3589                int steps = getCpuSpeedSteps();
3590                mSpeedBins = new SamplingCounter[bins >= steps ? bins : steps];
3591                for (int i = 0; i < bins; i++) {
3592                    if (in.readInt() != 0) {
3593                        mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
3594                    }
3595                }
3596
3597                readExcessivePowerFromParcelLocked(in);
3598            }
3599
3600            public BatteryStatsImpl getBatteryStats() {
3601                return BatteryStatsImpl.this;
3602            }
3603
3604            public void addCpuTimeLocked(int utime, int stime) {
3605                mUserTime += utime;
3606                mSystemTime += stime;
3607            }
3608
3609            public void addForegroundTimeLocked(long ttime) {
3610                mForegroundTime += ttime;
3611            }
3612
3613            public void incStartsLocked() {
3614                mStarts++;
3615            }
3616
3617            @Override
3618            public long getUserTime(int which) {
3619                long val;
3620                if (which == STATS_LAST) {
3621                    val = mLastUserTime;
3622                } else {
3623                    val = mUserTime;
3624                    if (which == STATS_CURRENT) {
3625                        val -= mLoadedUserTime;
3626                    } else if (which == STATS_SINCE_UNPLUGGED) {
3627                        val -= mUnpluggedUserTime;
3628                    }
3629                }
3630                return val;
3631            }
3632
3633            @Override
3634            public long getSystemTime(int which) {
3635                long val;
3636                if (which == STATS_LAST) {
3637                    val = mLastSystemTime;
3638                } else {
3639                    val = mSystemTime;
3640                    if (which == STATS_CURRENT) {
3641                        val -= mLoadedSystemTime;
3642                    } else if (which == STATS_SINCE_UNPLUGGED) {
3643                        val -= mUnpluggedSystemTime;
3644                    }
3645                }
3646                return val;
3647            }
3648
3649            @Override
3650            public long getForegroundTime(int which) {
3651                long val;
3652                if (which == STATS_LAST) {
3653                    val = mLastForegroundTime;
3654                } else {
3655                    val = mForegroundTime;
3656                    if (which == STATS_CURRENT) {
3657                        val -= mLoadedForegroundTime;
3658                    } else if (which == STATS_SINCE_UNPLUGGED) {
3659                        val -= mUnpluggedForegroundTime;
3660                    }
3661                }
3662                return val;
3663            }
3664
3665            @Override
3666            public int getStarts(int which) {
3667                int val;
3668                if (which == STATS_LAST) {
3669                    val = mLastStarts;
3670                } else {
3671                    val = mStarts;
3672                    if (which == STATS_CURRENT) {
3673                        val -= mLoadedStarts;
3674                    } else if (which == STATS_SINCE_UNPLUGGED) {
3675                        val -= mUnpluggedStarts;
3676                    }
3677                }
3678                return val;
3679            }
3680
3681            /* Called by ActivityManagerService when CPU times are updated. */
3682            public void addSpeedStepTimes(long[] values) {
3683                for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
3684                    long amt = values[i];
3685                    if (amt != 0) {
3686                        SamplingCounter c = mSpeedBins[i];
3687                        if (c == null) {
3688                            mSpeedBins[i] = c = new SamplingCounter(mUnpluggables);
3689                        }
3690                        c.addCountAtomic(values[i]);
3691                    }
3692                }
3693            }
3694
3695            @Override
3696            public long getTimeAtCpuSpeedStep(int speedStep, int which) {
3697                if (speedStep < mSpeedBins.length) {
3698                    SamplingCounter c = mSpeedBins[speedStep];
3699                    return c != null ? c.getCountLocked(which) : 0;
3700                } else {
3701                    return 0;
3702                }
3703            }
3704        }
3705
3706        /**
3707         * The statistics associated with a particular package.
3708         */
3709        public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
3710            /**
3711             * Number of times this package has done something that could wake up the
3712             * device from sleep.
3713             */
3714            int mWakeups;
3715
3716            /**
3717             * Number of things that could wake up the device loaded from a
3718             * previous save.
3719             */
3720            int mLoadedWakeups;
3721
3722            /**
3723             * Number of things that could wake up the device as of the
3724             * last run.
3725             */
3726            int mLastWakeups;
3727
3728            /**
3729             * Number of things that could wake up the device as of the
3730             * last run.
3731             */
3732            int mUnpluggedWakeups;
3733
3734            /**
3735             * The statics we have collected for this package's services.
3736             */
3737            final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
3738
3739            Pkg() {
3740                mUnpluggables.add(this);
3741            }
3742
3743            public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
3744                mUnpluggedWakeups = mWakeups;
3745            }
3746
3747            public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
3748            }
3749
3750            void detach() {
3751                mUnpluggables.remove(this);
3752            }
3753
3754            void readFromParcelLocked(Parcel in) {
3755                mWakeups = in.readInt();
3756                mLoadedWakeups = in.readInt();
3757                mLastWakeups = 0;
3758                mUnpluggedWakeups = in.readInt();
3759
3760                int numServs = in.readInt();
3761                mServiceStats.clear();
3762                for (int m = 0; m < numServs; m++) {
3763                    String serviceName = in.readString();
3764                    Uid.Pkg.Serv serv = new Serv();
3765                    mServiceStats.put(serviceName, serv);
3766
3767                    serv.readFromParcelLocked(in);
3768                }
3769            }
3770
3771            void writeToParcelLocked(Parcel out) {
3772                out.writeInt(mWakeups);
3773                out.writeInt(mLoadedWakeups);
3774                out.writeInt(mUnpluggedWakeups);
3775
3776                out.writeInt(mServiceStats.size());
3777                for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
3778                    out.writeString(servEntry.getKey());
3779                    Uid.Pkg.Serv serv = servEntry.getValue();
3780
3781                    serv.writeToParcelLocked(out);
3782                }
3783            }
3784
3785            @Override
3786            public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
3787                return mServiceStats;
3788            }
3789
3790            @Override
3791            public int getWakeups(int which) {
3792                int val;
3793                if (which == STATS_LAST) {
3794                    val = mLastWakeups;
3795                } else {
3796                    val = mWakeups;
3797                    if (which == STATS_CURRENT) {
3798                        val -= mLoadedWakeups;
3799                    } else if (which == STATS_SINCE_UNPLUGGED) {
3800                        val -= mUnpluggedWakeups;
3801                    }
3802                }
3803
3804                return val;
3805            }
3806
3807            /**
3808             * The statistics associated with a particular service.
3809             */
3810            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
3811                /**
3812                 * Total time (ms in battery uptime) the service has been left started.
3813                 */
3814                long mStartTime;
3815
3816                /**
3817                 * If service has been started and not yet stopped, this is
3818                 * when it was started.
3819                 */
3820                long mRunningSince;
3821
3822                /**
3823                 * True if we are currently running.
3824                 */
3825                boolean mRunning;
3826
3827                /**
3828                 * Total number of times startService() has been called.
3829                 */
3830                int mStarts;
3831
3832                /**
3833                 * Total time (ms in battery uptime) the service has been left launched.
3834                 */
3835                long mLaunchedTime;
3836
3837                /**
3838                 * If service has been launched and not yet exited, this is
3839                 * when it was launched (ms in battery uptime).
3840                 */
3841                long mLaunchedSince;
3842
3843                /**
3844                 * True if we are currently launched.
3845                 */
3846                boolean mLaunched;
3847
3848                /**
3849                 * Total number times the service has been launched.
3850                 */
3851                int mLaunches;
3852
3853                /**
3854                 * The amount of time spent started loaded from a previous save
3855                 * (ms in battery uptime).
3856                 */
3857                long mLoadedStartTime;
3858
3859                /**
3860                 * The number of starts loaded from a previous save.
3861                 */
3862                int mLoadedStarts;
3863
3864                /**
3865                 * The number of launches loaded from a previous save.
3866                 */
3867                int mLoadedLaunches;
3868
3869                /**
3870                 * The amount of time spent started as of the last run (ms
3871                 * in battery uptime).
3872                 */
3873                long mLastStartTime;
3874
3875                /**
3876                 * The number of starts as of the last run.
3877                 */
3878                int mLastStarts;
3879
3880                /**
3881                 * The number of launches as of the last run.
3882                 */
3883                int mLastLaunches;
3884
3885                /**
3886                 * The amount of time spent started when last unplugged (ms
3887                 * in battery uptime).
3888                 */
3889                long mUnpluggedStartTime;
3890
3891                /**
3892                 * The number of starts when last unplugged.
3893                 */
3894                int mUnpluggedStarts;
3895
3896                /**
3897                 * The number of launches when last unplugged.
3898                 */
3899                int mUnpluggedLaunches;
3900
3901                Serv() {
3902                    mUnpluggables.add(this);
3903                }
3904
3905                public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
3906                    mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
3907                    mUnpluggedStarts = mStarts;
3908                    mUnpluggedLaunches = mLaunches;
3909                }
3910
3911                public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
3912                }
3913
3914                void detach() {
3915                    mUnpluggables.remove(this);
3916                }
3917
3918                void readFromParcelLocked(Parcel in) {
3919                    mStartTime = in.readLong();
3920                    mRunningSince = in.readLong();
3921                    mRunning = in.readInt() != 0;
3922                    mStarts = in.readInt();
3923                    mLaunchedTime = in.readLong();
3924                    mLaunchedSince = in.readLong();
3925                    mLaunched = in.readInt() != 0;
3926                    mLaunches = in.readInt();
3927                    mLoadedStartTime = in.readLong();
3928                    mLoadedStarts = in.readInt();
3929                    mLoadedLaunches = in.readInt();
3930                    mLastStartTime = 0;
3931                    mLastStarts = 0;
3932                    mLastLaunches = 0;
3933                    mUnpluggedStartTime = in.readLong();
3934                    mUnpluggedStarts = in.readInt();
3935                    mUnpluggedLaunches = in.readInt();
3936                }
3937
3938                void writeToParcelLocked(Parcel out) {
3939                    out.writeLong(mStartTime);
3940                    out.writeLong(mRunningSince);
3941                    out.writeInt(mRunning ? 1 : 0);
3942                    out.writeInt(mStarts);
3943                    out.writeLong(mLaunchedTime);
3944                    out.writeLong(mLaunchedSince);
3945                    out.writeInt(mLaunched ? 1 : 0);
3946                    out.writeInt(mLaunches);
3947                    out.writeLong(mLoadedStartTime);
3948                    out.writeInt(mLoadedStarts);
3949                    out.writeInt(mLoadedLaunches);
3950                    out.writeLong(mUnpluggedStartTime);
3951                    out.writeInt(mUnpluggedStarts);
3952                    out.writeInt(mUnpluggedLaunches);
3953                }
3954
3955                long getLaunchTimeToNowLocked(long batteryUptime) {
3956                    if (!mLaunched) return mLaunchedTime;
3957                    return mLaunchedTime + batteryUptime - mLaunchedSince;
3958                }
3959
3960                long getStartTimeToNowLocked(long batteryUptime) {
3961                    if (!mRunning) return mStartTime;
3962                    return mStartTime + batteryUptime - mRunningSince;
3963                }
3964
3965                public void startLaunchedLocked() {
3966                    if (!mLaunched) {
3967                        mLaunches++;
3968                        mLaunchedSince = getBatteryUptimeLocked();
3969                        mLaunched = true;
3970                    }
3971                }
3972
3973                public void stopLaunchedLocked() {
3974                    if (mLaunched) {
3975                        long time = getBatteryUptimeLocked() - mLaunchedSince;
3976                        if (time > 0) {
3977                            mLaunchedTime += time;
3978                        } else {
3979                            mLaunches--;
3980                        }
3981                        mLaunched = false;
3982                    }
3983                }
3984
3985                public void startRunningLocked() {
3986                    if (!mRunning) {
3987                        mStarts++;
3988                        mRunningSince = getBatteryUptimeLocked();
3989                        mRunning = true;
3990                    }
3991                }
3992
3993                public void stopRunningLocked() {
3994                    if (mRunning) {
3995                        long time = getBatteryUptimeLocked() - mRunningSince;
3996                        if (time > 0) {
3997                            mStartTime += time;
3998                        } else {
3999                            mStarts--;
4000                        }
4001                        mRunning = false;
4002                    }
4003                }
4004
4005                public BatteryStatsImpl getBatteryStats() {
4006                    return BatteryStatsImpl.this;
4007                }
4008
4009                @Override
4010                public int getLaunches(int which) {
4011                    int val;
4012
4013                    if (which == STATS_LAST) {
4014                        val = mLastLaunches;
4015                    } else {
4016                        val = mLaunches;
4017                        if (which == STATS_CURRENT) {
4018                            val -= mLoadedLaunches;
4019                        } else if (which == STATS_SINCE_UNPLUGGED) {
4020                            val -= mUnpluggedLaunches;
4021                        }
4022                    }
4023
4024                    return val;
4025                }
4026
4027                @Override
4028                public long getStartTime(long now, int which) {
4029                    long val;
4030                    if (which == STATS_LAST) {
4031                        val = mLastStartTime;
4032                    } else {
4033                        val = getStartTimeToNowLocked(now);
4034                        if (which == STATS_CURRENT) {
4035                            val -= mLoadedStartTime;
4036                        } else if (which == STATS_SINCE_UNPLUGGED) {
4037                            val -= mUnpluggedStartTime;
4038                        }
4039                    }
4040
4041                    return val;
4042                }
4043
4044                @Override
4045                public int getStarts(int which) {
4046                    int val;
4047                    if (which == STATS_LAST) {
4048                        val = mLastStarts;
4049                    } else {
4050                        val = mStarts;
4051                        if (which == STATS_CURRENT) {
4052                            val -= mLoadedStarts;
4053                        } else if (which == STATS_SINCE_UNPLUGGED) {
4054                            val -= mUnpluggedStarts;
4055                        }
4056                    }
4057
4058                    return val;
4059                }
4060            }
4061
4062            public BatteryStatsImpl getBatteryStats() {
4063                return BatteryStatsImpl.this;
4064            }
4065
4066            public void incWakeupsLocked() {
4067                mWakeups++;
4068            }
4069
4070            final Serv newServiceStatsLocked() {
4071                return new Serv();
4072            }
4073        }
4074
4075        /**
4076         * Retrieve the statistics object for a particular process, creating
4077         * if needed.
4078         */
4079        public Proc getProcessStatsLocked(String name) {
4080            Proc ps = mProcessStats.get(name);
4081            if (ps == null) {
4082                ps = new Proc();
4083                mProcessStats.put(name, ps);
4084            }
4085
4086            return ps;
4087        }
4088
4089        public SparseArray<? extends Pid> getPidStats() {
4090            return mPids;
4091        }
4092
4093        public Pid getPidStatsLocked(int pid) {
4094            Pid p = mPids.get(pid);
4095            if (p == null) {
4096                p = new Pid();
4097                mPids.put(pid, p);
4098            }
4099            return p;
4100        }
4101
4102        /**
4103         * Retrieve the statistics object for a particular service, creating
4104         * if needed.
4105         */
4106        public Pkg getPackageStatsLocked(String name) {
4107            Pkg ps = mPackageStats.get(name);
4108            if (ps == null) {
4109                ps = new Pkg();
4110                mPackageStats.put(name, ps);
4111            }
4112
4113            return ps;
4114        }
4115
4116        /**
4117         * Retrieve the statistics object for a particular service, creating
4118         * if needed.
4119         */
4120        public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
4121            Pkg ps = getPackageStatsLocked(pkg);
4122            Pkg.Serv ss = ps.mServiceStats.get(serv);
4123            if (ss == null) {
4124                ss = ps.newServiceStatsLocked();
4125                ps.mServiceStats.put(serv, ss);
4126            }
4127
4128            return ss;
4129        }
4130
4131        public StopwatchTimer getWakeTimerLocked(String name, int type) {
4132            Wakelock wl = mWakelockStats.get(name);
4133            if (wl == null) {
4134                final int N = mWakelockStats.size();
4135                if (N > MAX_WAKELOCKS_PER_UID) {
4136                    name = BATCHED_WAKELOCK_NAME;
4137                    wl = mWakelockStats.get(name);
4138                }
4139                if (wl == null) {
4140                    wl = new Wakelock();
4141                    mWakelockStats.put(name, wl);
4142                }
4143            }
4144            StopwatchTimer t = null;
4145            switch (type) {
4146                case WAKE_TYPE_PARTIAL:
4147                    t = wl.mTimerPartial;
4148                    if (t == null) {
4149                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
4150                                mPartialTimers, mUnpluggables);
4151                        wl.mTimerPartial = t;
4152                    }
4153                    return t;
4154                case WAKE_TYPE_FULL:
4155                    t = wl.mTimerFull;
4156                    if (t == null) {
4157                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
4158                                mFullTimers, mUnpluggables);
4159                        wl.mTimerFull = t;
4160                    }
4161                    return t;
4162                case WAKE_TYPE_WINDOW:
4163                    t = wl.mTimerWindow;
4164                    if (t == null) {
4165                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
4166                                mWindowTimers, mUnpluggables);
4167                        wl.mTimerWindow = t;
4168                    }
4169                    return t;
4170                default:
4171                    throw new IllegalArgumentException("type=" + type);
4172            }
4173        }
4174
4175        public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
4176            Sensor se = mSensorStats.get(sensor);
4177            if (se == null) {
4178                if (!create) {
4179                    return null;
4180                }
4181                se = new Sensor(sensor);
4182                mSensorStats.put(sensor, se);
4183            }
4184            StopwatchTimer t = se.mTimer;
4185            if (t != null) {
4186                return t;
4187            }
4188            ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
4189            if (timers == null) {
4190                timers = new ArrayList<StopwatchTimer>();
4191                mSensorTimers.put(sensor, timers);
4192            }
4193            t = new StopwatchTimer(Uid.this, BatteryStats.SENSOR, timers, mUnpluggables);
4194            se.mTimer = t;
4195            return t;
4196        }
4197
4198        public void noteStartWakeLocked(int pid, String name, int type) {
4199            StopwatchTimer t = getWakeTimerLocked(name, type);
4200            if (t != null) {
4201                t.startRunningLocked(BatteryStatsImpl.this);
4202            }
4203            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
4204                Pid p = getPidStatsLocked(pid);
4205                if (p.mWakeStart == 0) {
4206                    p.mWakeStart = SystemClock.elapsedRealtime();
4207                }
4208            }
4209        }
4210
4211        public void noteStopWakeLocked(int pid, String name, int type) {
4212            StopwatchTimer t = getWakeTimerLocked(name, type);
4213            if (t != null) {
4214                t.stopRunningLocked(BatteryStatsImpl.this);
4215            }
4216            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
4217                Pid p = mPids.get(pid);
4218                if (p != null && p.mWakeStart != 0) {
4219                    p.mWakeSum += SystemClock.elapsedRealtime() - p.mWakeStart;
4220                    p.mWakeStart = 0;
4221                }
4222            }
4223        }
4224
4225        public void reportExcessiveWakeLocked(String proc, long overTime, long usedTime) {
4226            Proc p = getProcessStatsLocked(proc);
4227            if (p != null) {
4228                p.addExcessiveWake(overTime, usedTime);
4229            }
4230        }
4231
4232        public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) {
4233            Proc p = getProcessStatsLocked(proc);
4234            if (p != null) {
4235                p.addExcessiveCpu(overTime, usedTime);
4236            }
4237        }
4238
4239        public void noteStartSensor(int sensor) {
4240            StopwatchTimer t = getSensorTimerLocked(sensor, true);
4241            if (t != null) {
4242                t.startRunningLocked(BatteryStatsImpl.this);
4243            }
4244        }
4245
4246        public void noteStopSensor(int sensor) {
4247            // Don't create a timer if one doesn't already exist
4248            StopwatchTimer t = getSensorTimerLocked(sensor, false);
4249            if (t != null) {
4250                t.stopRunningLocked(BatteryStatsImpl.this);
4251            }
4252        }
4253
4254        public void noteStartGps() {
4255            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
4256            if (t != null) {
4257                t.startRunningLocked(BatteryStatsImpl.this);
4258            }
4259        }
4260
4261        public void noteStopGps() {
4262            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
4263            if (t != null) {
4264                t.stopRunningLocked(BatteryStatsImpl.this);
4265            }
4266        }
4267
4268        public BatteryStatsImpl getBatteryStats() {
4269            return BatteryStatsImpl.this;
4270        }
4271    }
4272
4273    public BatteryStatsImpl(String filename) {
4274        mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
4275        mHandler = new MyHandler();
4276        mStartCount++;
4277        mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables);
4278        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4279            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mUnpluggables);
4280        }
4281        mInputEventCounter = new Counter(mUnpluggables);
4282        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables);
4283        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
4284            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null, mUnpluggables);
4285        }
4286        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables);
4287        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4288            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null, mUnpluggables);
4289        }
4290        mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables);
4291        mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
4292        mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables);
4293        mAudioOnTimer = new StopwatchTimer(null, -6, null, mUnpluggables);
4294        mVideoOnTimer = new StopwatchTimer(null, -7, null, mUnpluggables);
4295        mOnBattery = mOnBatteryInternal = false;
4296        initTimes();
4297        mTrackBatteryPastUptime = 0;
4298        mTrackBatteryPastRealtime = 0;
4299        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
4300        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
4301        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
4302        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
4303        mDischargeStartLevel = 0;
4304        mDischargeUnplugLevel = 0;
4305        mDischargeCurrentLevel = 0;
4306        initDischarge();
4307        clearHistoryLocked();
4308    }
4309
4310    public BatteryStatsImpl(Parcel p) {
4311        mFile = null;
4312        mHandler = null;
4313        clearHistoryLocked();
4314        readFromParcel(p);
4315    }
4316
4317    public void setCallback(BatteryCallback cb) {
4318        mCallback = cb;
4319    }
4320
4321    public void setNumSpeedSteps(int steps) {
4322        if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
4323    }
4324
4325    public void setRadioScanningTimeout(long timeout) {
4326        if (mPhoneSignalScanningTimer != null) {
4327            mPhoneSignalScanningTimer.setTimeout(timeout);
4328        }
4329    }
4330
4331    @Override
4332    public boolean startIteratingOldHistoryLocked() {
4333        if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
4334                + " pos=" + mHistoryBuffer.dataPosition());
4335        mHistoryBuffer.setDataPosition(0);
4336        mHistoryReadTmp.clear();
4337        mReadOverflow = false;
4338        mIteratingHistory = true;
4339        return (mHistoryIterator = mHistory) != null;
4340    }
4341
4342    @Override
4343    public boolean getNextOldHistoryLocked(HistoryItem out) {
4344        boolean end = mHistoryBuffer.dataPosition() >= mHistoryBuffer.dataSize();
4345        if (!end) {
4346            mHistoryReadTmp.readDelta(mHistoryBuffer);
4347            mReadOverflow |= mHistoryReadTmp.cmd == HistoryItem.CMD_OVERFLOW;
4348        }
4349        HistoryItem cur = mHistoryIterator;
4350        if (cur == null) {
4351            if (!mReadOverflow && !end) {
4352                Slog.w(TAG, "Old history ends before new history!");
4353            }
4354            return false;
4355        }
4356        out.setTo(cur);
4357        mHistoryIterator = cur.next;
4358        if (!mReadOverflow) {
4359            if (end) {
4360                Slog.w(TAG, "New history ends before old history!");
4361            } else if (!out.same(mHistoryReadTmp)) {
4362                long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
4363                PrintWriter pw = new PrintWriter(new LogWriter(android.util.Log.WARN, TAG));
4364                pw.println("Histories differ!");
4365                pw.println("Old history:");
4366                (new HistoryPrinter()).printNextItem(pw, out, now);
4367                pw.println("New history:");
4368                (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, now);
4369            }
4370        }
4371        return true;
4372    }
4373
4374    @Override
4375    public void finishIteratingOldHistoryLocked() {
4376        mIteratingHistory = false;
4377        mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
4378    }
4379
4380    @Override
4381    public boolean startIteratingHistoryLocked() {
4382        if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
4383                + " pos=" + mHistoryBuffer.dataPosition());
4384        mHistoryBuffer.setDataPosition(0);
4385        mReadOverflow = false;
4386        mIteratingHistory = true;
4387        return mHistoryBuffer.dataSize() > 0;
4388    }
4389
4390    @Override
4391    public boolean getNextHistoryLocked(HistoryItem out) {
4392        final int pos = mHistoryBuffer.dataPosition();
4393        if (pos == 0) {
4394            out.clear();
4395        }
4396        boolean end = pos >= mHistoryBuffer.dataSize();
4397        if (end) {
4398            return false;
4399        }
4400
4401        out.readDelta(mHistoryBuffer);
4402        return true;
4403    }
4404
4405    @Override
4406    public void finishIteratingHistoryLocked() {
4407        mIteratingHistory = false;
4408        mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
4409    }
4410
4411    @Override
4412    public long getHistoryBaseTime() {
4413        return mHistoryBaseTime;
4414    }
4415
4416    @Override
4417    public int getStartCount() {
4418        return mStartCount;
4419    }
4420
4421    public boolean isOnBattery() {
4422        return mOnBattery;
4423    }
4424
4425    public boolean isScreenOn() {
4426        return mScreenOn;
4427    }
4428
4429    void initTimes() {
4430        mBatteryRealtime = mTrackBatteryPastUptime = 0;
4431        mBatteryUptime = mTrackBatteryPastRealtime = 0;
4432        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
4433        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
4434        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
4435        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
4436    }
4437
4438    void initDischarge() {
4439        mLowDischargeAmountSinceCharge = 0;
4440        mHighDischargeAmountSinceCharge = 0;
4441        mDischargeAmountScreenOn = 0;
4442        mDischargeAmountScreenOnSinceCharge = 0;
4443        mDischargeAmountScreenOff = 0;
4444        mDischargeAmountScreenOffSinceCharge = 0;
4445    }
4446
4447    public void resetAllStatsLocked() {
4448        mStartCount = 0;
4449        initTimes();
4450        mScreenOnTimer.reset(this, false);
4451        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4452            mScreenBrightnessTimer[i].reset(this, false);
4453        }
4454        mInputEventCounter.reset(false);
4455        mPhoneOnTimer.reset(this, false);
4456        mAudioOnTimer.reset(this, false);
4457        mVideoOnTimer.reset(this, false);
4458        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
4459            mPhoneSignalStrengthsTimer[i].reset(this, false);
4460        }
4461        mPhoneSignalScanningTimer.reset(this, false);
4462        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4463            mPhoneDataConnectionsTimer[i].reset(this, false);
4464        }
4465        mWifiOnTimer.reset(this, false);
4466        mGlobalWifiRunningTimer.reset(this, false);
4467        mBluetoothOnTimer.reset(this, false);
4468
4469        for (int i=0; i<mUidStats.size(); i++) {
4470            if (mUidStats.valueAt(i).reset()) {
4471                mUidStats.remove(mUidStats.keyAt(i));
4472                i--;
4473            }
4474        }
4475
4476        if (mKernelWakelockStats.size() > 0) {
4477            for (SamplingTimer timer : mKernelWakelockStats.values()) {
4478                mUnpluggables.remove(timer);
4479            }
4480            mKernelWakelockStats.clear();
4481        }
4482
4483        initDischarge();
4484
4485        clearHistoryLocked();
4486    }
4487
4488    void updateDischargeScreenLevelsLocked(boolean oldScreenOn, boolean newScreenOn) {
4489        if (oldScreenOn) {
4490            int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
4491            if (diff > 0) {
4492                mDischargeAmountScreenOn += diff;
4493                mDischargeAmountScreenOnSinceCharge += diff;
4494            }
4495        } else {
4496            int diff = mDischargeScreenOffUnplugLevel - mDischargeCurrentLevel;
4497            if (diff > 0) {
4498                mDischargeAmountScreenOff += diff;
4499                mDischargeAmountScreenOffSinceCharge += diff;
4500            }
4501        }
4502        if (newScreenOn) {
4503            mDischargeScreenOnUnplugLevel = mDischargeCurrentLevel;
4504            mDischargeScreenOffUnplugLevel = 0;
4505        } else {
4506            mDischargeScreenOnUnplugLevel = 0;
4507            mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
4508        }
4509    }
4510
4511    void setOnBattery(boolean onBattery, int oldStatus, int level) {
4512        synchronized(this) {
4513            setOnBatteryLocked(onBattery, oldStatus, level);
4514        }
4515    }
4516
4517    void setOnBatteryLocked(boolean onBattery, int oldStatus, int level) {
4518        boolean doWrite = false;
4519        Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
4520        m.arg1 = onBattery ? 1 : 0;
4521        mHandler.sendMessage(m);
4522        mOnBattery = mOnBatteryInternal = onBattery;
4523
4524        long uptime = SystemClock.uptimeMillis() * 1000;
4525        long mSecRealtime = SystemClock.elapsedRealtime();
4526        long realtime = mSecRealtime * 1000;
4527        if (onBattery) {
4528            // We will reset our status if we are unplugging after the
4529            // battery was last full, or the level is at 100, or
4530            // we have gone through a significant charge (from a very low
4531            // level to a now very high level).
4532            if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
4533                    || level >= 90
4534                    || (mDischargeCurrentLevel < 20 && level >= 80)) {
4535                doWrite = true;
4536                resetAllStatsLocked();
4537                mDischargeStartLevel = level;
4538            }
4539            updateKernelWakelocksLocked();
4540            mHistoryCur.batteryLevel = (byte)level;
4541            mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4542            if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
4543                    + Integer.toHexString(mHistoryCur.states));
4544            addHistoryRecordLocked(mSecRealtime);
4545            mTrackBatteryUptimeStart = uptime;
4546            mTrackBatteryRealtimeStart = realtime;
4547            mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
4548            mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
4549            mDischargeCurrentLevel = mDischargeUnplugLevel = level;
4550            if (mScreenOn) {
4551                mDischargeScreenOnUnplugLevel = level;
4552                mDischargeScreenOffUnplugLevel = 0;
4553            } else {
4554                mDischargeScreenOnUnplugLevel = 0;
4555                mDischargeScreenOffUnplugLevel = level;
4556            }
4557            mDischargeAmountScreenOn = 0;
4558            mDischargeAmountScreenOff = 0;
4559            doUnplugLocked(realtime, mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
4560        } else {
4561            updateKernelWakelocksLocked();
4562            mHistoryCur.batteryLevel = (byte)level;
4563            mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4564            if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
4565                    + Integer.toHexString(mHistoryCur.states));
4566            addHistoryRecordLocked(mSecRealtime);
4567            mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
4568            mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
4569            mDischargeCurrentLevel = level;
4570            if (level < mDischargeUnplugLevel) {
4571                mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
4572                mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
4573            }
4574            updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
4575            doPlugLocked(realtime, getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
4576        }
4577        if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
4578            if (mFile != null) {
4579                writeAsyncLocked();
4580            }
4581        }
4582    }
4583
4584    // This should probably be exposed in the API, though it's not critical
4585    private static final int BATTERY_PLUGGED_NONE = 0;
4586
4587    public void setBatteryState(int status, int health, int plugType, int level,
4588            int temp, int volt) {
4589        synchronized(this) {
4590            boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
4591            int oldStatus = mHistoryCur.batteryStatus;
4592            if (!mHaveBatteryLevel) {
4593                mHaveBatteryLevel = true;
4594                // We start out assuming that the device is plugged in (not
4595                // on battery).  If our first report is now that we are indeed
4596                // plugged in, then twiddle our state to correctly reflect that
4597                // since we won't be going through the full setOnBattery().
4598                if (onBattery == mOnBattery) {
4599                    if (onBattery) {
4600                        mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4601                    } else {
4602                        mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4603                    }
4604                }
4605                oldStatus = status;
4606            }
4607            if (onBattery) {
4608                mDischargeCurrentLevel = level;
4609                mRecordingHistory = true;
4610            }
4611            if (onBattery != mOnBattery) {
4612                mHistoryCur.batteryLevel = (byte)level;
4613                mHistoryCur.batteryStatus = (byte)status;
4614                mHistoryCur.batteryHealth = (byte)health;
4615                mHistoryCur.batteryPlugType = (byte)plugType;
4616                mHistoryCur.batteryTemperature = (char)temp;
4617                mHistoryCur.batteryVoltage = (char)volt;
4618                setOnBatteryLocked(onBattery, oldStatus, level);
4619            } else {
4620                boolean changed = false;
4621                if (mHistoryCur.batteryLevel != level) {
4622                    mHistoryCur.batteryLevel = (byte)level;
4623                    changed = true;
4624                }
4625                if (mHistoryCur.batteryStatus != status) {
4626                    mHistoryCur.batteryStatus = (byte)status;
4627                    changed = true;
4628                }
4629                if (mHistoryCur.batteryHealth != health) {
4630                    mHistoryCur.batteryHealth = (byte)health;
4631                    changed = true;
4632                }
4633                if (mHistoryCur.batteryPlugType != plugType) {
4634                    mHistoryCur.batteryPlugType = (byte)plugType;
4635                    changed = true;
4636                }
4637                if (temp >= (mHistoryCur.batteryTemperature+10)
4638                        || temp <= (mHistoryCur.batteryTemperature-10)) {
4639                    mHistoryCur.batteryTemperature = (char)temp;
4640                    changed = true;
4641                }
4642                if (volt > (mHistoryCur.batteryVoltage+20)
4643                        || volt < (mHistoryCur.batteryVoltage-20)) {
4644                    mHistoryCur.batteryVoltage = (char)volt;
4645                    changed = true;
4646                }
4647                if (changed) {
4648                    addHistoryRecordLocked(SystemClock.elapsedRealtime());
4649                }
4650            }
4651            if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
4652                // We don't record history while we are plugged in and fully charged.
4653                // The next time we are unplugged, history will be cleared.
4654                mRecordingHistory = false;
4655            }
4656        }
4657    }
4658
4659    public void updateKernelWakelocksLocked() {
4660        Map<String, KernelWakelockStats> m = readKernelWakelockStats();
4661
4662        if (m == null) {
4663            // Not crashing might make board bringup easier.
4664            Slog.w(TAG, "Couldn't get kernel wake lock stats");
4665            return;
4666        }
4667
4668        for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
4669            String name = ent.getKey();
4670            KernelWakelockStats kws = ent.getValue();
4671
4672            SamplingTimer kwlt = mKernelWakelockStats.get(name);
4673            if (kwlt == null) {
4674                kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
4675                        true /* track reported values */);
4676                mKernelWakelockStats.put(name, kwlt);
4677            }
4678            kwlt.updateCurrentReportedCount(kws.mCount);
4679            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
4680            kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
4681        }
4682
4683        if (m.size() != mKernelWakelockStats.size()) {
4684            // Set timers to stale if they didn't appear in /proc/wakelocks this time.
4685            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
4686                SamplingTimer st = ent.getValue();
4687                if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
4688                    st.setStale();
4689                }
4690            }
4691        }
4692    }
4693
4694    public long getAwakeTimeBattery() {
4695        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
4696    }
4697
4698    public long getAwakeTimePlugged() {
4699        return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
4700    }
4701
4702    @Override
4703    public long computeUptime(long curTime, int which) {
4704        switch (which) {
4705            case STATS_SINCE_CHARGED: return mUptime + (curTime-mUptimeStart);
4706            case STATS_LAST: return mLastUptime;
4707            case STATS_CURRENT: return (curTime-mUptimeStart);
4708            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
4709        }
4710        return 0;
4711    }
4712
4713    @Override
4714    public long computeRealtime(long curTime, int which) {
4715        switch (which) {
4716            case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
4717            case STATS_LAST: return mLastRealtime;
4718            case STATS_CURRENT: return (curTime-mRealtimeStart);
4719            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
4720        }
4721        return 0;
4722    }
4723
4724    @Override
4725    public long computeBatteryUptime(long curTime, int which) {
4726        switch (which) {
4727            case STATS_SINCE_CHARGED:
4728                return mBatteryUptime + getBatteryUptime(curTime);
4729            case STATS_LAST:
4730                return mBatteryLastUptime;
4731            case STATS_CURRENT:
4732                return getBatteryUptime(curTime);
4733            case STATS_SINCE_UNPLUGGED:
4734                return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
4735        }
4736        return 0;
4737    }
4738
4739    @Override
4740    public long computeBatteryRealtime(long curTime, int which) {
4741        switch (which) {
4742            case STATS_SINCE_CHARGED:
4743                return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
4744            case STATS_LAST:
4745                return mBatteryLastRealtime;
4746            case STATS_CURRENT:
4747                return getBatteryRealtimeLocked(curTime);
4748            case STATS_SINCE_UNPLUGGED:
4749                return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
4750        }
4751        return 0;
4752    }
4753
4754    long getBatteryUptimeLocked(long curTime) {
4755        long time = mTrackBatteryPastUptime;
4756        if (mOnBatteryInternal) {
4757            time += curTime - mTrackBatteryUptimeStart;
4758        }
4759        return time;
4760    }
4761
4762    long getBatteryUptimeLocked() {
4763        return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
4764    }
4765
4766    @Override
4767    public long getBatteryUptime(long curTime) {
4768        return getBatteryUptimeLocked(curTime);
4769    }
4770
4771    long getBatteryRealtimeLocked(long curTime) {
4772        long time = mTrackBatteryPastRealtime;
4773        if (mOnBatteryInternal) {
4774            time += curTime - mTrackBatteryRealtimeStart;
4775        }
4776        return time;
4777    }
4778
4779    @Override
4780    public long getBatteryRealtime(long curTime) {
4781        return getBatteryRealtimeLocked(curTime);
4782    }
4783
4784    private long getTcpBytes(long current, long[] dataBytes, int which) {
4785        if (which == STATS_LAST) {
4786            return dataBytes[STATS_LAST];
4787        } else {
4788            if (which == STATS_SINCE_UNPLUGGED) {
4789                if (dataBytes[STATS_SINCE_UNPLUGGED] < 0) {
4790                    return dataBytes[STATS_LAST];
4791                } else {
4792                    return current - dataBytes[STATS_SINCE_UNPLUGGED];
4793                }
4794            } else if (which == STATS_SINCE_CHARGED) {
4795                return (current - dataBytes[STATS_CURRENT]) + dataBytes[STATS_SINCE_CHARGED];
4796            }
4797            return current - dataBytes[STATS_CURRENT];
4798        }
4799    }
4800
4801    /** Only STATS_UNPLUGGED works properly */
4802    public long getMobileTcpBytesSent(int which) {
4803        final long mobileTxBytes = getNetworkStatsSummary().getTotal(null, mMobileIfaces).txBytes;
4804        return getTcpBytes(mobileTxBytes, mMobileDataTx, which);
4805    }
4806
4807    /** Only STATS_UNPLUGGED works properly */
4808    public long getMobileTcpBytesReceived(int which) {
4809        final long mobileRxBytes = getNetworkStatsSummary().getTotal(null, mMobileIfaces).rxBytes;
4810        return getTcpBytes(mobileRxBytes, mMobileDataRx, which);
4811    }
4812
4813    /** Only STATS_UNPLUGGED works properly */
4814    public long getTotalTcpBytesSent(int which) {
4815        final long totalTxBytes = getNetworkStatsSummary().getTotal(null).txBytes;
4816        return getTcpBytes(totalTxBytes, mTotalDataTx, which);
4817    }
4818
4819    /** Only STATS_UNPLUGGED works properly */
4820    public long getTotalTcpBytesReceived(int which) {
4821        final long totalRxBytes = getNetworkStatsSummary().getTotal(null).rxBytes;
4822        return getTcpBytes(totalRxBytes, mTotalDataRx, which);
4823    }
4824
4825    @Override
4826    public int getDischargeStartLevel() {
4827        synchronized(this) {
4828            return getDischargeStartLevelLocked();
4829        }
4830    }
4831
4832    public int getDischargeStartLevelLocked() {
4833            return mDischargeUnplugLevel;
4834    }
4835
4836    @Override
4837    public int getDischargeCurrentLevel() {
4838        synchronized(this) {
4839            return getDischargeCurrentLevelLocked();
4840        }
4841    }
4842
4843    public int getDischargeCurrentLevelLocked() {
4844        return mDischargeCurrentLevel;
4845    }
4846
4847    @Override
4848    public int getLowDischargeAmountSinceCharge() {
4849        synchronized(this) {
4850            int val = mLowDischargeAmountSinceCharge;
4851            if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
4852                val += mDischargeUnplugLevel-mDischargeCurrentLevel-1;
4853            }
4854            return val;
4855        }
4856    }
4857
4858    @Override
4859    public int getHighDischargeAmountSinceCharge() {
4860        synchronized(this) {
4861            int val = mHighDischargeAmountSinceCharge;
4862            if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
4863                val += mDischargeUnplugLevel-mDischargeCurrentLevel;
4864            }
4865            return val;
4866        }
4867    }
4868
4869    public int getDischargeAmountScreenOn() {
4870        synchronized(this) {
4871            int val = mDischargeAmountScreenOn;
4872            if (mOnBattery && mScreenOn
4873                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
4874                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
4875            }
4876            return val;
4877        }
4878    }
4879
4880    public int getDischargeAmountScreenOnSinceCharge() {
4881        synchronized(this) {
4882            int val = mDischargeAmountScreenOnSinceCharge;
4883            if (mOnBattery && mScreenOn
4884                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
4885                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
4886            }
4887            return val;
4888        }
4889    }
4890
4891    public int getDischargeAmountScreenOff() {
4892        synchronized(this) {
4893            int val = mDischargeAmountScreenOff;
4894            if (mOnBattery && !mScreenOn
4895                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
4896                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
4897            }
4898            return val;
4899        }
4900    }
4901
4902    public int getDischargeAmountScreenOffSinceCharge() {
4903        synchronized(this) {
4904            int val = mDischargeAmountScreenOffSinceCharge;
4905            if (mOnBattery && !mScreenOn
4906                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
4907                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
4908            }
4909            return val;
4910        }
4911    }
4912
4913    @Override
4914    public int getCpuSpeedSteps() {
4915        return sNumSpeedSteps;
4916    }
4917
4918    /**
4919     * Retrieve the statistics object for a particular uid, creating if needed.
4920     */
4921    public Uid getUidStatsLocked(int uid) {
4922        Uid u = mUidStats.get(uid);
4923        if (u == null) {
4924            u = new Uid(uid);
4925            mUidStats.put(uid, u);
4926        }
4927        return u;
4928    }
4929
4930    /**
4931     * Remove the statistics object for a particular uid.
4932     */
4933    public void removeUidStatsLocked(int uid) {
4934        mUidStats.remove(uid);
4935    }
4936
4937    /**
4938     * Retrieve the statistics object for a particular process, creating
4939     * if needed.
4940     */
4941    public Uid.Proc getProcessStatsLocked(int uid, String name) {
4942        Uid u = getUidStatsLocked(uid);
4943        return u.getProcessStatsLocked(name);
4944    }
4945
4946    /**
4947     * Retrieve the statistics object for a particular process, given
4948     * the name of the process.
4949     * @param name process name
4950     * @return the statistics object for the process
4951     */
4952    public Uid.Proc getProcessStatsLocked(String name, int pid) {
4953        int uid;
4954        if (mUidCache.containsKey(name)) {
4955            uid = mUidCache.get(name);
4956        } else {
4957            uid = Process.getUidForPid(pid);
4958            mUidCache.put(name, uid);
4959        }
4960        Uid u = getUidStatsLocked(uid);
4961        return u.getProcessStatsLocked(name);
4962    }
4963
4964    /**
4965     * Retrieve the statistics object for a particular process, creating
4966     * if needed.
4967     */
4968    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
4969        Uid u = getUidStatsLocked(uid);
4970        return u.getPackageStatsLocked(pkg);
4971    }
4972
4973    /**
4974     * Retrieve the statistics object for a particular service, creating
4975     * if needed.
4976     */
4977    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
4978        Uid u = getUidStatsLocked(uid);
4979        return u.getServiceStatsLocked(pkg, name);
4980    }
4981
4982    /**
4983     * Massage data to distribute any reasonable work down to more specific
4984     * owners.  Must only be called on a dead BatteryStats object!
4985     */
4986    public void distributeWorkLocked(int which) {
4987        // Aggregate all CPU time associated with WIFI.
4988        Uid wifiUid = mUidStats.get(Process.WIFI_UID);
4989        if (wifiUid != null) {
4990            long uSecTime = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
4991            for (Uid.Proc proc : wifiUid.mProcessStats.values()) {
4992                long totalRunningTime = getGlobalWifiRunningTime(uSecTime, which);
4993                for (int i=0; i<mUidStats.size(); i++) {
4994                    Uid uid = mUidStats.valueAt(i);
4995                    if (uid.mUid != Process.WIFI_UID) {
4996                        long uidRunningTime = uid.getWifiRunningTime(uSecTime, which);
4997                        if (uidRunningTime > 0) {
4998                            Uid.Proc uidProc = uid.getProcessStatsLocked("*wifi*");
4999                            long time = proc.getUserTime(which);
5000                            time = (time*uidRunningTime)/totalRunningTime;
5001                            uidProc.mUserTime += time;
5002                            proc.mUserTime -= time;
5003                            time = proc.getSystemTime(which);
5004                            time = (time*uidRunningTime)/totalRunningTime;
5005                            uidProc.mSystemTime += time;
5006                            proc.mSystemTime -= time;
5007                            time = proc.getForegroundTime(which);
5008                            time = (time*uidRunningTime)/totalRunningTime;
5009                            uidProc.mForegroundTime += time;
5010                            proc.mForegroundTime -= time;
5011                            for (int sb=0; sb<proc.mSpeedBins.length; sb++) {
5012                                SamplingCounter sc = proc.mSpeedBins[sb];
5013                                if (sc != null) {
5014                                    time = sc.getCountLocked(which);
5015                                    time = (time*uidRunningTime)/totalRunningTime;
5016                                    SamplingCounter uidSc = uidProc.mSpeedBins[sb];
5017                                    if (uidSc == null) {
5018                                        uidSc = new SamplingCounter(mUnpluggables);
5019                                        uidProc.mSpeedBins[sb] = uidSc;
5020                                    }
5021                                    uidSc.mCount.addAndGet((int)time);
5022                                    sc.mCount.addAndGet((int)-time);
5023                                }
5024                            }
5025                            totalRunningTime -= uidRunningTime;
5026                        }
5027                    }
5028                }
5029            }
5030        }
5031    }
5032
5033    public void shutdownLocked() {
5034        writeSyncLocked();
5035        mShuttingDown = true;
5036    }
5037
5038    Parcel mPendingWrite = null;
5039    final ReentrantLock mWriteLock = new ReentrantLock();
5040
5041    public void writeAsyncLocked() {
5042        writeLocked(false);
5043    }
5044
5045    public void writeSyncLocked() {
5046        writeLocked(true);
5047    }
5048
5049    void writeLocked(boolean sync) {
5050        if (mFile == null) {
5051            Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
5052            return;
5053        }
5054
5055        if (mShuttingDown) {
5056            return;
5057        }
5058
5059        Parcel out = Parcel.obtain();
5060        writeSummaryToParcel(out);
5061        mLastWriteTime = SystemClock.elapsedRealtime();
5062
5063        if (mPendingWrite != null) {
5064            mPendingWrite.recycle();
5065        }
5066        mPendingWrite = out;
5067
5068        if (sync) {
5069            commitPendingDataToDisk();
5070        } else {
5071            Thread thr = new Thread("BatteryStats-Write") {
5072                @Override
5073                public void run() {
5074                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
5075                    commitPendingDataToDisk();
5076                }
5077            };
5078            thr.start();
5079        }
5080    }
5081
5082    public void commitPendingDataToDisk() {
5083        final Parcel next;
5084        synchronized (this) {
5085            next = mPendingWrite;
5086            mPendingWrite = null;
5087            if (next == null) {
5088                return;
5089            }
5090
5091            mWriteLock.lock();
5092        }
5093
5094        try {
5095            FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
5096            stream.write(next.marshall());
5097            stream.flush();
5098            FileUtils.sync(stream);
5099            stream.close();
5100            mFile.commit();
5101        } catch (IOException e) {
5102            Slog.w("BatteryStats", "Error writing battery statistics", e);
5103            mFile.rollback();
5104        } finally {
5105            next.recycle();
5106            mWriteLock.unlock();
5107        }
5108    }
5109
5110    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
5111        int pos = 0;
5112        int avail = stream.available();
5113        byte[] data = new byte[avail];
5114        while (true) {
5115            int amt = stream.read(data, pos, data.length-pos);
5116            //Log.i("foo", "Read " + amt + " bytes at " + pos
5117            //        + " of avail " + data.length);
5118            if (amt <= 0) {
5119                //Log.i("foo", "**** FINISHED READING: pos=" + pos
5120                //        + " len=" + data.length);
5121                return data;
5122            }
5123            pos += amt;
5124            avail = stream.available();
5125            if (avail > data.length-pos) {
5126                byte[] newData = new byte[pos+avail];
5127                System.arraycopy(data, 0, newData, 0, pos);
5128                data = newData;
5129            }
5130        }
5131    }
5132
5133    public void readLocked() {
5134        if (mFile == null) {
5135            Slog.w("BatteryStats", "readLocked: no file associated with this instance");
5136            return;
5137        }
5138
5139        mUidStats.clear();
5140
5141        try {
5142            File file = mFile.chooseForRead();
5143            if (!file.exists()) {
5144                return;
5145            }
5146            FileInputStream stream = new FileInputStream(file);
5147
5148            byte[] raw = readFully(stream);
5149            Parcel in = Parcel.obtain();
5150            in.unmarshall(raw, 0, raw.length);
5151            in.setDataPosition(0);
5152            stream.close();
5153
5154            readSummaryFromParcel(in);
5155        } catch(java.io.IOException e) {
5156            Slog.e("BatteryStats", "Error reading battery statistics", e);
5157        }
5158
5159        long now = SystemClock.elapsedRealtime();
5160        if (USE_OLD_HISTORY) {
5161            addHistoryRecordLocked(now, HistoryItem.CMD_START);
5162        }
5163        addHistoryBufferLocked(now, HistoryItem.CMD_START);
5164    }
5165
5166    public int describeContents() {
5167        return 0;
5168    }
5169
5170    void readHistory(Parcel in, boolean andOldHistory) {
5171        final long historyBaseTime = in.readLong();
5172
5173        mHistoryBuffer.setDataSize(0);
5174        mHistoryBuffer.setDataPosition(0);
5175
5176        int bufSize = in.readInt();
5177        int curPos = in.dataPosition();
5178        if (bufSize >= (MAX_MAX_HISTORY_BUFFER*3)) {
5179            Slog.w(TAG, "File corrupt: history data buffer too large " + bufSize);
5180        } else if ((bufSize&~3) != bufSize) {
5181            Slog.w(TAG, "File corrupt: history data buffer not aligned " + bufSize);
5182        } else {
5183            if (DEBUG_HISTORY) Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
5184                    + " bytes at " + curPos);
5185            mHistoryBuffer.appendFrom(in, curPos, bufSize);
5186            in.setDataPosition(curPos + bufSize);
5187        }
5188
5189        if (andOldHistory) {
5190            readOldHistory(in);
5191        }
5192
5193        if (DEBUG_HISTORY) {
5194            StringBuilder sb = new StringBuilder(128);
5195            sb.append("****************** OLD mHistoryBaseTime: ");
5196            TimeUtils.formatDuration(mHistoryBaseTime, sb);
5197            Slog.i(TAG, sb.toString());
5198        }
5199        mHistoryBaseTime = historyBaseTime;
5200        if (DEBUG_HISTORY) {
5201            StringBuilder sb = new StringBuilder(128);
5202            sb.append("****************** NEW mHistoryBaseTime: ");
5203            TimeUtils.formatDuration(mHistoryBaseTime, sb);
5204            Slog.i(TAG, sb.toString());
5205        }
5206
5207        // We are just arbitrarily going to insert 1 minute from the sample of
5208        // the last run until samples in this run.
5209        if (mHistoryBaseTime > 0) {
5210            long oldnow = SystemClock.elapsedRealtime();
5211            mHistoryBaseTime = (mHistoryBaseTime - oldnow) + 60*1000;
5212            if (DEBUG_HISTORY) {
5213                StringBuilder sb = new StringBuilder(128);
5214                sb.append("****************** ADJUSTED mHistoryBaseTime: ");
5215                TimeUtils.formatDuration(mHistoryBaseTime, sb);
5216                Slog.i(TAG, sb.toString());
5217            }
5218        }
5219    }
5220
5221    void readOldHistory(Parcel in) {
5222        if (!USE_OLD_HISTORY) {
5223            return;
5224        }
5225        mHistory = mHistoryEnd = mHistoryCache = null;
5226        long time;
5227        while (in.dataAvail() > 0 && (time=in.readLong()) >= 0) {
5228            HistoryItem rec = new HistoryItem(time, in);
5229            addHistoryRecordLocked(rec);
5230        }
5231    }
5232
5233    void writeHistory(Parcel out, boolean andOldHistory) {
5234        if (DEBUG_HISTORY) {
5235            StringBuilder sb = new StringBuilder(128);
5236            sb.append("****************** WRITING mHistoryBaseTime: ");
5237            TimeUtils.formatDuration(mHistoryBaseTime, sb);
5238            sb.append(" mLastHistoryTime: ");
5239            TimeUtils.formatDuration(mLastHistoryTime, sb);
5240            Slog.i(TAG, sb.toString());
5241        }
5242        out.writeLong(mHistoryBaseTime + mLastHistoryTime);
5243        out.writeInt(mHistoryBuffer.dataSize());
5244        if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
5245                + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
5246        out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
5247
5248        if (andOldHistory) {
5249            writeOldHistory(out);
5250        }
5251    }
5252
5253    void writeOldHistory(Parcel out) {
5254        if (!USE_OLD_HISTORY) {
5255            return;
5256        }
5257        HistoryItem rec = mHistory;
5258        while (rec != null) {
5259            if (rec.time >= 0) rec.writeToParcel(out, 0);
5260            rec = rec.next;
5261        }
5262        out.writeLong(-1);
5263    }
5264
5265    private void readSummaryFromParcel(Parcel in) {
5266        final int version = in.readInt();
5267        if (version != VERSION) {
5268            Slog.w("BatteryStats", "readFromParcel: version got " + version
5269                + ", expected " + VERSION + "; erasing old stats");
5270            return;
5271        }
5272
5273        readHistory(in, true);
5274
5275        mStartCount = in.readInt();
5276        mBatteryUptime = in.readLong();
5277        mBatteryRealtime = in.readLong();
5278        mUptime = in.readLong();
5279        mRealtime = in.readLong();
5280        mDischargeUnplugLevel = in.readInt();
5281        mDischargeCurrentLevel = in.readInt();
5282        mLowDischargeAmountSinceCharge = in.readInt();
5283        mHighDischargeAmountSinceCharge = in.readInt();
5284        mDischargeAmountScreenOnSinceCharge = in.readInt();
5285        mDischargeAmountScreenOffSinceCharge = in.readInt();
5286
5287        mStartCount++;
5288
5289        mScreenOn = false;
5290        mScreenOnTimer.readSummaryFromParcelLocked(in);
5291        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5292            mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
5293        }
5294        mInputEventCounter.readSummaryFromParcelLocked(in);
5295        mPhoneOn = false;
5296        mPhoneOnTimer.readSummaryFromParcelLocked(in);
5297        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5298            mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
5299        }
5300        mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
5301        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5302            mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
5303        }
5304        mWifiOn = false;
5305        mWifiOnTimer.readSummaryFromParcelLocked(in);
5306        mGlobalWifiRunning = false;
5307        mGlobalWifiRunningTimer.readSummaryFromParcelLocked(in);
5308        mBluetoothOn = false;
5309        mBluetoothOnTimer.readSummaryFromParcelLocked(in);
5310
5311        int NKW = in.readInt();
5312        if (NKW > 10000) {
5313            Slog.w(TAG, "File corrupt: too many kernel wake locks " + NKW);
5314            return;
5315        }
5316        for (int ikw = 0; ikw < NKW; ikw++) {
5317            if (in.readInt() != 0) {
5318                String kwltName = in.readString();
5319                getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
5320            }
5321        }
5322
5323        sNumSpeedSteps = in.readInt();
5324
5325        final int NU = in.readInt();
5326        if (NU > 10000) {
5327            Slog.w(TAG, "File corrupt: too many uids " + NU);
5328            return;
5329        }
5330        for (int iu = 0; iu < NU; iu++) {
5331            int uid = in.readInt();
5332            Uid u = new Uid(uid);
5333            mUidStats.put(uid, u);
5334
5335            u.mWifiRunning = false;
5336            if (in.readInt() != 0) {
5337                u.mWifiRunningTimer.readSummaryFromParcelLocked(in);
5338            }
5339            u.mFullWifiLockOut = false;
5340            if (in.readInt() != 0) {
5341                u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
5342            }
5343            u.mWifiScanStarted = false;
5344            if (in.readInt() != 0) {
5345                u.mWifiScanTimer.readSummaryFromParcelLocked(in);
5346            }
5347            u.mWifiMulticastEnabled = false;
5348            if (in.readInt() != 0) {
5349                u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
5350            }
5351            u.mAudioTurnedOn = false;
5352            if (in.readInt() != 0) {
5353                u.createAudioTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
5354            }
5355            u.mVideoTurnedOn = false;
5356            if (in.readInt() != 0) {
5357                u.createVideoTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
5358            }
5359            if (in.readInt() != 0) {
5360                u.createVibratorOnTimerLocked().readSummaryFromParcelLocked(in);
5361            }
5362
5363            if (in.readInt() != 0) {
5364                if (u.mUserActivityCounters == null) {
5365                    u.initUserActivityLocked();
5366                }
5367                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
5368                    u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
5369                }
5370            }
5371
5372            int NW = in.readInt();
5373            if (NW > 100) {
5374                Slog.w(TAG, "File corrupt: too many wake locks " + NW);
5375                return;
5376            }
5377            for (int iw = 0; iw < NW; iw++) {
5378                String wlName = in.readString();
5379                if (in.readInt() != 0) {
5380                    u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
5381                }
5382                if (in.readInt() != 0) {
5383                    u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
5384                }
5385                if (in.readInt() != 0) {
5386                    u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
5387                }
5388            }
5389
5390            int NP = in.readInt();
5391            if (NP > 1000) {
5392                Slog.w(TAG, "File corrupt: too many sensors " + NP);
5393                return;
5394            }
5395            for (int is = 0; is < NP; is++) {
5396                int seNumber = in.readInt();
5397                if (in.readInt() != 0) {
5398                    u.getSensorTimerLocked(seNumber, true)
5399                            .readSummaryFromParcelLocked(in);
5400                }
5401            }
5402
5403            NP = in.readInt();
5404            if (NP > 1000) {
5405                Slog.w(TAG, "File corrupt: too many processes " + NP);
5406                return;
5407            }
5408            for (int ip = 0; ip < NP; ip++) {
5409                String procName = in.readString();
5410                Uid.Proc p = u.getProcessStatsLocked(procName);
5411                p.mUserTime = p.mLoadedUserTime = in.readLong();
5412                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
5413                p.mStarts = p.mLoadedStarts = in.readInt();
5414                int NSB = in.readInt();
5415                if (NSB > 100) {
5416                    Slog.w(TAG, "File corrupt: too many speed bins " + NSB);
5417                    return;
5418                }
5419                p.mSpeedBins = new SamplingCounter[NSB];
5420                for (int i=0; i<NSB; i++) {
5421                    if (in.readInt() != 0) {
5422                        p.mSpeedBins[i] = new SamplingCounter(mUnpluggables);
5423                        p.mSpeedBins[i].readSummaryFromParcelLocked(in);
5424                    }
5425                }
5426                if (!p.readExcessivePowerFromParcelLocked(in)) {
5427                    return;
5428                }
5429            }
5430
5431            NP = in.readInt();
5432            if (NP > 10000) {
5433                Slog.w(TAG, "File corrupt: too many packages " + NP);
5434                return;
5435            }
5436            for (int ip = 0; ip < NP; ip++) {
5437                String pkgName = in.readString();
5438                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
5439                p.mWakeups = p.mLoadedWakeups = in.readInt();
5440                final int NS = in.readInt();
5441                if (NS > 1000) {
5442                    Slog.w(TAG, "File corrupt: too many services " + NS);
5443                    return;
5444                }
5445                for (int is = 0; is < NS; is++) {
5446                    String servName = in.readString();
5447                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
5448                    s.mStartTime = s.mLoadedStartTime = in.readLong();
5449                    s.mStarts = s.mLoadedStarts = in.readInt();
5450                    s.mLaunches = s.mLoadedLaunches = in.readInt();
5451                }
5452            }
5453
5454            u.mLoadedTcpBytesReceived = in.readLong();
5455            u.mLoadedTcpBytesSent = in.readLong();
5456        }
5457    }
5458
5459    /**
5460     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
5461     * disk.  This format does not allow a lossless round-trip.
5462     *
5463     * @param out the Parcel to be written to.
5464     */
5465    public void writeSummaryToParcel(Parcel out) {
5466        // Need to update with current kernel wake lock counts.
5467        updateKernelWakelocksLocked();
5468
5469        final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
5470        final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
5471        final long NOW = getBatteryUptimeLocked(NOW_SYS);
5472        final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
5473
5474        out.writeInt(VERSION);
5475
5476        writeHistory(out, true);
5477
5478        out.writeInt(mStartCount);
5479        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_SINCE_CHARGED));
5480        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
5481        out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
5482        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
5483        out.writeInt(mDischargeUnplugLevel);
5484        out.writeInt(mDischargeCurrentLevel);
5485        out.writeInt(getLowDischargeAmountSinceCharge());
5486        out.writeInt(getHighDischargeAmountSinceCharge());
5487        out.writeInt(getDischargeAmountScreenOnSinceCharge());
5488        out.writeInt(getDischargeAmountScreenOffSinceCharge());
5489
5490        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5491        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5492            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
5493        }
5494        mInputEventCounter.writeSummaryFromParcelLocked(out);
5495        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5496        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5497            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
5498        }
5499        mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5500        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5501            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
5502        }
5503        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5504        mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5505        mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5506
5507        out.writeInt(mKernelWakelockStats.size());
5508        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
5509            Timer kwlt = ent.getValue();
5510            if (kwlt != null) {
5511                out.writeInt(1);
5512                out.writeString(ent.getKey());
5513                ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
5514            } else {
5515                out.writeInt(0);
5516            }
5517        }
5518
5519        out.writeInt(sNumSpeedSteps);
5520        final int NU = mUidStats.size();
5521        out.writeInt(NU);
5522        for (int iu = 0; iu < NU; iu++) {
5523            out.writeInt(mUidStats.keyAt(iu));
5524            Uid u = mUidStats.valueAt(iu);
5525
5526            if (u.mWifiRunningTimer != null) {
5527                out.writeInt(1);
5528                u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5529            } else {
5530                out.writeInt(0);
5531            }
5532            if (u.mFullWifiLockTimer != null) {
5533                out.writeInt(1);
5534                u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5535            } else {
5536                out.writeInt(0);
5537            }
5538            if (u.mWifiScanTimer != null) {
5539                out.writeInt(1);
5540                u.mWifiScanTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5541            } else {
5542                out.writeInt(0);
5543            }
5544            if (u.mWifiMulticastTimer != null) {
5545                out.writeInt(1);
5546                u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5547            } else {
5548                out.writeInt(0);
5549            }
5550            if (u.mAudioTurnedOnTimer != null) {
5551                out.writeInt(1);
5552                u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5553            } else {
5554                out.writeInt(0);
5555            }
5556            if (u.mVideoTurnedOnTimer != null) {
5557                out.writeInt(1);
5558                u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5559            } else {
5560                out.writeInt(0);
5561            }
5562            if (u.mVibratorOnTimer != null) {
5563                out.writeInt(1);
5564                u.mVibratorOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5565            } else {
5566                out.writeInt(0);
5567            }
5568
5569            if (u.mUserActivityCounters == null) {
5570                out.writeInt(0);
5571            } else {
5572                out.writeInt(1);
5573                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
5574                    u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
5575                }
5576            }
5577
5578            int NW = u.mWakelockStats.size();
5579            out.writeInt(NW);
5580            if (NW > 0) {
5581                for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
5582                        : u.mWakelockStats.entrySet()) {
5583                    out.writeString(ent.getKey());
5584                    Uid.Wakelock wl = ent.getValue();
5585                    if (wl.mTimerFull != null) {
5586                        out.writeInt(1);
5587                        wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
5588                    } else {
5589                        out.writeInt(0);
5590                    }
5591                    if (wl.mTimerPartial != null) {
5592                        out.writeInt(1);
5593                        wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
5594                    } else {
5595                        out.writeInt(0);
5596                    }
5597                    if (wl.mTimerWindow != null) {
5598                        out.writeInt(1);
5599                        wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
5600                    } else {
5601                        out.writeInt(0);
5602                    }
5603                }
5604            }
5605
5606            int NSE = u.mSensorStats.size();
5607            out.writeInt(NSE);
5608            if (NSE > 0) {
5609                for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
5610                        : u.mSensorStats.entrySet()) {
5611                    out.writeInt(ent.getKey());
5612                    Uid.Sensor se = ent.getValue();
5613                    if (se.mTimer != null) {
5614                        out.writeInt(1);
5615                        se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5616                    } else {
5617                        out.writeInt(0);
5618                    }
5619                }
5620            }
5621
5622            int NP = u.mProcessStats.size();
5623            out.writeInt(NP);
5624            if (NP > 0) {
5625                for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
5626                    : u.mProcessStats.entrySet()) {
5627                    out.writeString(ent.getKey());
5628                    Uid.Proc ps = ent.getValue();
5629                    out.writeLong(ps.mUserTime);
5630                    out.writeLong(ps.mSystemTime);
5631                    out.writeInt(ps.mStarts);
5632                    final int N = ps.mSpeedBins.length;
5633                    out.writeInt(N);
5634                    for (int i=0; i<N; i++) {
5635                        if (ps.mSpeedBins[i] != null) {
5636                            out.writeInt(1);
5637                            ps.mSpeedBins[i].writeSummaryFromParcelLocked(out);
5638                        } else {
5639                            out.writeInt(0);
5640                        }
5641                    }
5642                    ps.writeExcessivePowerToParcelLocked(out);
5643                }
5644            }
5645
5646            NP = u.mPackageStats.size();
5647            out.writeInt(NP);
5648            if (NP > 0) {
5649                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
5650                    : u.mPackageStats.entrySet()) {
5651                    out.writeString(ent.getKey());
5652                    Uid.Pkg ps = ent.getValue();
5653                    out.writeInt(ps.mWakeups);
5654                    final int NS = ps.mServiceStats.size();
5655                    out.writeInt(NS);
5656                    if (NS > 0) {
5657                        for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
5658                                : ps.mServiceStats.entrySet()) {
5659                            out.writeString(sent.getKey());
5660                            BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
5661                            long time = ss.getStartTimeToNowLocked(NOW);
5662                            out.writeLong(time);
5663                            out.writeInt(ss.mStarts);
5664                            out.writeInt(ss.mLaunches);
5665                        }
5666                    }
5667                }
5668            }
5669
5670            out.writeLong(u.getTcpBytesReceived(STATS_SINCE_CHARGED));
5671            out.writeLong(u.getTcpBytesSent(STATS_SINCE_CHARGED));
5672        }
5673    }
5674
5675    public void readFromParcel(Parcel in) {
5676        readFromParcelLocked(in);
5677    }
5678
5679    void readFromParcelLocked(Parcel in) {
5680        int magic = in.readInt();
5681        if (magic != MAGIC) {
5682            throw new ParcelFormatException("Bad magic number");
5683        }
5684
5685        readHistory(in, false);
5686
5687        mStartCount = in.readInt();
5688        mBatteryUptime = in.readLong();
5689        mBatteryLastUptime = 0;
5690        mBatteryRealtime = in.readLong();
5691        mBatteryLastRealtime = 0;
5692        mScreenOn = false;
5693        mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables, in);
5694        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5695            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i,
5696                    null, mUnpluggables, in);
5697        }
5698        mInputEventCounter = new Counter(mUnpluggables, in);
5699        mPhoneOn = false;
5700        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5701        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5702            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
5703                    null, mUnpluggables, in);
5704        }
5705        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables, in);
5706        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5707            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
5708                    null, mUnpluggables, in);
5709        }
5710        mWifiOn = false;
5711        mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5712        mGlobalWifiRunning = false;
5713        mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5714        mBluetoothOn = false;
5715        mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5716        mUptime = in.readLong();
5717        mUptimeStart = in.readLong();
5718        mLastUptime = 0;
5719        mRealtime = in.readLong();
5720        mRealtimeStart = in.readLong();
5721        mLastRealtime = 0;
5722        mOnBattery = in.readInt() != 0;
5723        mOnBatteryInternal = false; // we are no longer really running.
5724        mTrackBatteryPastUptime = in.readLong();
5725        mTrackBatteryUptimeStart = in.readLong();
5726        mTrackBatteryPastRealtime = in.readLong();
5727        mTrackBatteryRealtimeStart = in.readLong();
5728        mUnpluggedBatteryUptime = in.readLong();
5729        mUnpluggedBatteryRealtime = in.readLong();
5730        mDischargeUnplugLevel = in.readInt();
5731        mDischargeCurrentLevel = in.readInt();
5732        mLowDischargeAmountSinceCharge = in.readInt();
5733        mHighDischargeAmountSinceCharge = in.readInt();
5734        mDischargeAmountScreenOn = in.readInt();
5735        mDischargeAmountScreenOnSinceCharge = in.readInt();
5736        mDischargeAmountScreenOff = in.readInt();
5737        mDischargeAmountScreenOffSinceCharge = in.readInt();
5738        mLastWriteTime = in.readLong();
5739
5740        mMobileDataRx[STATS_LAST] = in.readLong();
5741        mMobileDataRx[STATS_SINCE_UNPLUGGED] = -1;
5742        mMobileDataTx[STATS_LAST] = in.readLong();
5743        mMobileDataTx[STATS_SINCE_UNPLUGGED] = -1;
5744        mTotalDataRx[STATS_LAST] = in.readLong();
5745        mTotalDataRx[STATS_SINCE_UNPLUGGED] = -1;
5746        mTotalDataTx[STATS_LAST] = in.readLong();
5747        mTotalDataTx[STATS_SINCE_UNPLUGGED] = -1;
5748
5749        mRadioDataUptime = in.readLong();
5750        mRadioDataStart = -1;
5751
5752        mBluetoothPingCount = in.readInt();
5753        mBluetoothPingStart = -1;
5754
5755        mKernelWakelockStats.clear();
5756        int NKW = in.readInt();
5757        for (int ikw = 0; ikw < NKW; ikw++) {
5758            if (in.readInt() != 0) {
5759                String wakelockName = in.readString();
5760                in.readInt(); // Extra 0/1 written by Timer.writeTimerToParcel
5761                SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
5762                mKernelWakelockStats.put(wakelockName, kwlt);
5763            }
5764        }
5765
5766        mPartialTimers.clear();
5767        mFullTimers.clear();
5768        mWindowTimers.clear();
5769        mWifiRunningTimers.clear();
5770        mFullWifiLockTimers.clear();
5771        mWifiScanTimers.clear();
5772        mWifiMulticastTimers.clear();
5773
5774        sNumSpeedSteps = in.readInt();
5775
5776        int numUids = in.readInt();
5777        mUidStats.clear();
5778        for (int i = 0; i < numUids; i++) {
5779            int uid = in.readInt();
5780            Uid u = new Uid(uid);
5781            u.readFromParcelLocked(mUnpluggables, in);
5782            mUidStats.append(uid, u);
5783        }
5784    }
5785
5786    public void writeToParcel(Parcel out, int flags) {
5787        writeToParcelLocked(out, true, flags);
5788    }
5789
5790    public void writeToParcelWithoutUids(Parcel out, int flags) {
5791        writeToParcelLocked(out, false, flags);
5792    }
5793
5794    @SuppressWarnings("unused")
5795    void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
5796        // Need to update with current kernel wake lock counts.
5797        updateKernelWakelocksLocked();
5798
5799        final long uSecUptime = SystemClock.uptimeMillis() * 1000;
5800        final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
5801        final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
5802        final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
5803
5804        out.writeInt(MAGIC);
5805
5806        writeHistory(out, false);
5807
5808        out.writeInt(mStartCount);
5809        out.writeLong(mBatteryUptime);
5810        out.writeLong(mBatteryRealtime);
5811        mScreenOnTimer.writeToParcel(out, batteryRealtime);
5812        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5813            mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
5814        }
5815        mInputEventCounter.writeToParcel(out);
5816        mPhoneOnTimer.writeToParcel(out, batteryRealtime);
5817        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5818            mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
5819        }
5820        mPhoneSignalScanningTimer.writeToParcel(out, batteryRealtime);
5821        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5822            mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
5823        }
5824        mWifiOnTimer.writeToParcel(out, batteryRealtime);
5825        mGlobalWifiRunningTimer.writeToParcel(out, batteryRealtime);
5826        mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
5827        out.writeLong(mUptime);
5828        out.writeLong(mUptimeStart);
5829        out.writeLong(mRealtime);
5830        out.writeLong(mRealtimeStart);
5831        out.writeInt(mOnBattery ? 1 : 0);
5832        out.writeLong(batteryUptime);
5833        out.writeLong(mTrackBatteryUptimeStart);
5834        out.writeLong(batteryRealtime);
5835        out.writeLong(mTrackBatteryRealtimeStart);
5836        out.writeLong(mUnpluggedBatteryUptime);
5837        out.writeLong(mUnpluggedBatteryRealtime);
5838        out.writeInt(mDischargeUnplugLevel);
5839        out.writeInt(mDischargeCurrentLevel);
5840        out.writeInt(mLowDischargeAmountSinceCharge);
5841        out.writeInt(mHighDischargeAmountSinceCharge);
5842        out.writeInt(mDischargeAmountScreenOn);
5843        out.writeInt(mDischargeAmountScreenOnSinceCharge);
5844        out.writeInt(mDischargeAmountScreenOff);
5845        out.writeInt(mDischargeAmountScreenOffSinceCharge);
5846        out.writeLong(mLastWriteTime);
5847
5848        out.writeLong(getMobileTcpBytesReceived(STATS_SINCE_UNPLUGGED));
5849        out.writeLong(getMobileTcpBytesSent(STATS_SINCE_UNPLUGGED));
5850        out.writeLong(getTotalTcpBytesReceived(STATS_SINCE_UNPLUGGED));
5851        out.writeLong(getTotalTcpBytesSent(STATS_SINCE_UNPLUGGED));
5852
5853        // Write radio uptime for data
5854        out.writeLong(getRadioDataUptime());
5855
5856        out.writeInt(getBluetoothPingCount());
5857
5858        if (inclUids) {
5859            out.writeInt(mKernelWakelockStats.size());
5860            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
5861                SamplingTimer kwlt = ent.getValue();
5862                if (kwlt != null) {
5863                    out.writeInt(1);
5864                    out.writeString(ent.getKey());
5865                    Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
5866                } else {
5867                    out.writeInt(0);
5868                }
5869            }
5870        } else {
5871            out.writeInt(0);
5872        }
5873
5874        out.writeInt(sNumSpeedSteps);
5875
5876        if (inclUids) {
5877            int size = mUidStats.size();
5878            out.writeInt(size);
5879            for (int i = 0; i < size; i++) {
5880                out.writeInt(mUidStats.keyAt(i));
5881                Uid uid = mUidStats.valueAt(i);
5882
5883                uid.writeToParcelLocked(out, batteryRealtime);
5884            }
5885        } else {
5886            out.writeInt(0);
5887        }
5888    }
5889
5890    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
5891        new Parcelable.Creator<BatteryStatsImpl>() {
5892        public BatteryStatsImpl createFromParcel(Parcel in) {
5893            return new BatteryStatsImpl(in);
5894        }
5895
5896        public BatteryStatsImpl[] newArray(int size) {
5897            return new BatteryStatsImpl[size];
5898        }
5899    };
5900
5901    public void prepareForDumpLocked() {
5902        // Need to retrieve current kernel wake lock stats before printing.
5903        updateKernelWakelocksLocked();
5904    }
5905
5906    public void dumpLocked(PrintWriter pw) {
5907        if (DEBUG) {
5908            Printer pr = new PrintWriterPrinter(pw);
5909            pr.println("*** Screen timer:");
5910            mScreenOnTimer.logState(pr, "  ");
5911            for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5912                pr.println("*** Screen brightness #" + i + ":");
5913                mScreenBrightnessTimer[i].logState(pr, "  ");
5914            }
5915            pr.println("*** Input event counter:");
5916            mInputEventCounter.logState(pr, "  ");
5917            pr.println("*** Phone timer:");
5918            mPhoneOnTimer.logState(pr, "  ");
5919            for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5920                pr.println("*** Signal strength #" + i + ":");
5921                mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
5922            }
5923            pr.println("*** Signal scanning :");
5924            mPhoneSignalScanningTimer.logState(pr, "  ");
5925            for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5926                pr.println("*** Data connection type #" + i + ":");
5927                mPhoneDataConnectionsTimer[i].logState(pr, "  ");
5928            }
5929            pr.println("*** Wifi timer:");
5930            mWifiOnTimer.logState(pr, "  ");
5931            pr.println("*** WifiRunning timer:");
5932            mGlobalWifiRunningTimer.logState(pr, "  ");
5933            pr.println("*** Bluetooth timer:");
5934            mBluetoothOnTimer.logState(pr, "  ");
5935            pr.println("*** Mobile ifaces:");
5936            pr.println(mMobileIfaces.toString());
5937        }
5938        super.dumpLocked(pw);
5939    }
5940
5941    private NetworkStats mNetworkSummaryCache;
5942    private NetworkStats mNetworkDetailCache;
5943
5944    private NetworkStats getNetworkStatsSummary() {
5945        // NOTE: calls from BatteryStatsService already hold this lock
5946        synchronized (this) {
5947            if (mNetworkSummaryCache == null
5948                    || mNetworkSummaryCache.getElapsedRealtimeAge() > SECOND_IN_MILLIS) {
5949                mNetworkSummaryCache = null;
5950
5951                if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
5952                    try {
5953                        mNetworkSummaryCache = mNetworkStatsFactory.readNetworkStatsSummaryDev();
5954                    } catch (IOException e) {
5955                        Log.wtf(TAG, "problem reading network stats", e);
5956                    }
5957                }
5958
5959                if (mNetworkSummaryCache == null) {
5960                    mNetworkSummaryCache = new NetworkStats(SystemClock.elapsedRealtime(), 0);
5961                }
5962            }
5963            return mNetworkSummaryCache;
5964        }
5965    }
5966
5967    private NetworkStats getNetworkStatsDetailGroupedByUid() {
5968        // NOTE: calls from BatteryStatsService already hold this lock
5969        synchronized (this) {
5970            if (mNetworkDetailCache == null
5971                    || mNetworkDetailCache.getElapsedRealtimeAge() > SECOND_IN_MILLIS) {
5972                mNetworkDetailCache = null;
5973
5974                if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
5975                    try {
5976                        mNetworkDetailCache = mNetworkStatsFactory
5977                                .readNetworkStatsDetail().groupedByUid();
5978                    } catch (IOException e) {
5979                        Log.wtf(TAG, "problem reading network stats", e);
5980                    }
5981                }
5982
5983                if (mNetworkDetailCache == null) {
5984                    mNetworkDetailCache = new NetworkStats(SystemClock.elapsedRealtime(), 0);
5985                }
5986            }
5987            return mNetworkDetailCache;
5988        }
5989    }
5990}
5991