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