BatteryStatsImpl.java revision 73f534a2dd324d631696ced762f5c0ab1f254f74
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 = 61 + (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 dataType, int which) {
2336        return mPhoneDataConnectionsTimer[dataType].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 = 0;
2685            else if (type >= NUM_USER_ACTIVITY_TYPES) type = NUM_USER_ACTIVITY_TYPES-1;
2686            mUserActivityCounters[type].stepAtomic();
2687        }
2688
2689        @Override
2690        public boolean hasUserActivity() {
2691            return mUserActivityCounters != null;
2692        }
2693
2694        @Override
2695        public int getUserActivityCount(int type, int which) {
2696            if (mUserActivityCounters == null) {
2697                return 0;
2698            }
2699            return mUserActivityCounters[type].getCountLocked(which);
2700        }
2701
2702        void initUserActivityLocked() {
2703            mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
2704            for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2705                mUserActivityCounters[i] = new Counter(mUnpluggables);
2706            }
2707        }
2708
2709        public long computeCurrentTcpBytesSent() {
2710            final long uidTxBytes = getNetworkStatsDetailGroupedByUid().getTotal(
2711                    null, mUid).txBytes;
2712            return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
2713                    ? (uidTxBytes - mStartedTcpBytesSent) : 0);
2714        }
2715
2716        /**
2717         * Clear all stats for this uid.  Returns true if the uid is completely
2718         * inactive so can be dropped.
2719         */
2720        boolean reset() {
2721            boolean active = false;
2722
2723            if (mWifiRunningTimer != null) {
2724                active |= !mWifiRunningTimer.reset(BatteryStatsImpl.this, false);
2725                active |= mWifiRunning;
2726            }
2727            if (mFullWifiLockTimer != null) {
2728                active |= !mFullWifiLockTimer.reset(BatteryStatsImpl.this, false);
2729                active |= mFullWifiLockOut;
2730            }
2731            if (mWifiScanTimer != null) {
2732                active |= !mWifiScanTimer.reset(BatteryStatsImpl.this, false);
2733                active |= mWifiScanStarted;
2734            }
2735            if (mWifiMulticastTimer != null) {
2736                active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
2737                active |= mWifiMulticastEnabled;
2738            }
2739            if (mAudioTurnedOnTimer != null) {
2740                active |= !mAudioTurnedOnTimer.reset(BatteryStatsImpl.this, false);
2741                active |= mAudioTurnedOn;
2742            }
2743            if (mVideoTurnedOnTimer != null) {
2744                active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
2745                active |= mVideoTurnedOn;
2746            }
2747
2748            mLoadedTcpBytesReceived = mLoadedTcpBytesSent = 0;
2749            mCurrentTcpBytesReceived = mCurrentTcpBytesSent = 0;
2750
2751            if (mUserActivityCounters != null) {
2752                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2753                    mUserActivityCounters[i].reset(false);
2754                }
2755            }
2756
2757            if (mWakelockStats.size() > 0) {
2758                Iterator<Map.Entry<String, Wakelock>> it = mWakelockStats.entrySet().iterator();
2759                while (it.hasNext()) {
2760                    Map.Entry<String, Wakelock> wakelockEntry = it.next();
2761                    Wakelock wl = wakelockEntry.getValue();
2762                    if (wl.reset()) {
2763                        it.remove();
2764                    } else {
2765                        active = true;
2766                    }
2767                }
2768            }
2769            if (mSensorStats.size() > 0) {
2770                Iterator<Map.Entry<Integer, Sensor>> it = mSensorStats.entrySet().iterator();
2771                while (it.hasNext()) {
2772                    Map.Entry<Integer, Sensor> sensorEntry = it.next();
2773                    Sensor s = sensorEntry.getValue();
2774                    if (s.reset()) {
2775                        it.remove();
2776                    } else {
2777                        active = true;
2778                    }
2779                }
2780            }
2781            if (mProcessStats.size() > 0) {
2782                Iterator<Map.Entry<String, Proc>> it = mProcessStats.entrySet().iterator();
2783                while (it.hasNext()) {
2784                    Map.Entry<String, Proc> procEntry = it.next();
2785                    procEntry.getValue().detach();
2786                }
2787                mProcessStats.clear();
2788            }
2789            if (mPids.size() > 0) {
2790                for (int i=0; !active && i<mPids.size(); i++) {
2791                    Pid pid = mPids.valueAt(i);
2792                    if (pid.mWakeStart != 0) {
2793                        active = true;
2794                    }
2795                }
2796            }
2797            if (mPackageStats.size() > 0) {
2798                Iterator<Map.Entry<String, Pkg>> it = mPackageStats.entrySet().iterator();
2799                while (it.hasNext()) {
2800                    Map.Entry<String, Pkg> pkgEntry = it.next();
2801                    Pkg p = pkgEntry.getValue();
2802                    p.detach();
2803                    if (p.mServiceStats.size() > 0) {
2804                        Iterator<Map.Entry<String, Pkg.Serv>> it2
2805                                = p.mServiceStats.entrySet().iterator();
2806                        while (it2.hasNext()) {
2807                            Map.Entry<String, Pkg.Serv> servEntry = it2.next();
2808                            servEntry.getValue().detach();
2809                        }
2810                    }
2811                }
2812                mPackageStats.clear();
2813            }
2814
2815            mPids.clear();
2816
2817            if (!active) {
2818                if (mWifiRunningTimer != null) {
2819                    mWifiRunningTimer.detach();
2820                }
2821                if (mFullWifiLockTimer != null) {
2822                    mFullWifiLockTimer.detach();
2823                }
2824                if (mWifiScanTimer != null) {
2825                    mWifiScanTimer.detach();
2826                }
2827                if (mWifiMulticastTimer != null) {
2828                    mWifiMulticastTimer.detach();
2829                }
2830                if (mAudioTurnedOnTimer != null) {
2831                    mAudioTurnedOnTimer.detach();
2832                }
2833                if (mVideoTurnedOnTimer != null) {
2834                    mVideoTurnedOnTimer.detach();
2835                }
2836                if (mUserActivityCounters != null) {
2837                    for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2838                        mUserActivityCounters[i].detach();
2839                    }
2840                }
2841            }
2842
2843            return !active;
2844        }
2845
2846        void writeToParcelLocked(Parcel out, long batteryRealtime) {
2847            out.writeInt(mWakelockStats.size());
2848            for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
2849                out.writeString(wakelockEntry.getKey());
2850                Uid.Wakelock wakelock = wakelockEntry.getValue();
2851                wakelock.writeToParcelLocked(out, batteryRealtime);
2852            }
2853
2854            out.writeInt(mSensorStats.size());
2855            for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
2856                out.writeInt(sensorEntry.getKey());
2857                Uid.Sensor sensor = sensorEntry.getValue();
2858                sensor.writeToParcelLocked(out, batteryRealtime);
2859            }
2860
2861            out.writeInt(mProcessStats.size());
2862            for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
2863                out.writeString(procEntry.getKey());
2864                Uid.Proc proc = procEntry.getValue();
2865                proc.writeToParcelLocked(out);
2866            }
2867
2868            out.writeInt(mPackageStats.size());
2869            for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
2870                out.writeString(pkgEntry.getKey());
2871                Uid.Pkg pkg = pkgEntry.getValue();
2872                pkg.writeToParcelLocked(out);
2873            }
2874
2875            out.writeLong(mLoadedTcpBytesReceived);
2876            out.writeLong(mLoadedTcpBytesSent);
2877            out.writeLong(computeCurrentTcpBytesReceived());
2878            out.writeLong(computeCurrentTcpBytesSent());
2879            out.writeLong(mTcpBytesReceivedAtLastUnplug);
2880            out.writeLong(mTcpBytesSentAtLastUnplug);
2881            if (mWifiRunningTimer != null) {
2882                out.writeInt(1);
2883                mWifiRunningTimer.writeToParcel(out, batteryRealtime);
2884            } else {
2885                out.writeInt(0);
2886            }
2887            if (mFullWifiLockTimer != null) {
2888                out.writeInt(1);
2889                mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
2890            } else {
2891                out.writeInt(0);
2892            }
2893            if (mWifiScanTimer != null) {
2894                out.writeInt(1);
2895                mWifiScanTimer.writeToParcel(out, batteryRealtime);
2896            } else {
2897                out.writeInt(0);
2898            }
2899            if (mWifiMulticastTimer != null) {
2900                out.writeInt(1);
2901                mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
2902            } else {
2903                out.writeInt(0);
2904            }
2905            if (mAudioTurnedOnTimer != null) {
2906                out.writeInt(1);
2907                mAudioTurnedOnTimer.writeToParcel(out, batteryRealtime);
2908            } else {
2909                out.writeInt(0);
2910            }
2911            if (mVideoTurnedOnTimer != null) {
2912                out.writeInt(1);
2913                mVideoTurnedOnTimer.writeToParcel(out, batteryRealtime);
2914            } else {
2915                out.writeInt(0);
2916            }
2917            if (mUserActivityCounters != null) {
2918                out.writeInt(1);
2919                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2920                    mUserActivityCounters[i].writeToParcel(out);
2921                }
2922            } else {
2923                out.writeInt(0);
2924            }
2925        }
2926
2927        void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
2928            int numWakelocks = in.readInt();
2929            mWakelockStats.clear();
2930            for (int j = 0; j < numWakelocks; j++) {
2931                String wakelockName = in.readString();
2932                Uid.Wakelock wakelock = new Wakelock();
2933                wakelock.readFromParcelLocked(unpluggables, in);
2934                // We will just drop some random set of wakelocks if
2935                // the previous run of the system was an older version
2936                // that didn't impose a limit.
2937                mWakelockStats.put(wakelockName, wakelock);
2938            }
2939
2940            int numSensors = in.readInt();
2941            mSensorStats.clear();
2942            for (int k = 0; k < numSensors; k++) {
2943                int sensorNumber = in.readInt();
2944                Uid.Sensor sensor = new Sensor(sensorNumber);
2945                sensor.readFromParcelLocked(mUnpluggables, in);
2946                mSensorStats.put(sensorNumber, sensor);
2947            }
2948
2949            int numProcs = in.readInt();
2950            mProcessStats.clear();
2951            for (int k = 0; k < numProcs; k++) {
2952                String processName = in.readString();
2953                Uid.Proc proc = new Proc();
2954                proc.readFromParcelLocked(in);
2955                mProcessStats.put(processName, proc);
2956            }
2957
2958            int numPkgs = in.readInt();
2959            mPackageStats.clear();
2960            for (int l = 0; l < numPkgs; l++) {
2961                String packageName = in.readString();
2962                Uid.Pkg pkg = new Pkg();
2963                pkg.readFromParcelLocked(in);
2964                mPackageStats.put(packageName, pkg);
2965            }
2966
2967            mLoadedTcpBytesReceived = in.readLong();
2968            mLoadedTcpBytesSent = in.readLong();
2969            mCurrentTcpBytesReceived = in.readLong();
2970            mCurrentTcpBytesSent = in.readLong();
2971            mTcpBytesReceivedAtLastUnplug = in.readLong();
2972            mTcpBytesSentAtLastUnplug = in.readLong();
2973            mWifiRunning = false;
2974            if (in.readInt() != 0) {
2975                mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
2976                        mWifiRunningTimers, mUnpluggables, in);
2977            } else {
2978                mWifiRunningTimer = null;
2979            }
2980            mFullWifiLockOut = false;
2981            if (in.readInt() != 0) {
2982                mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
2983                        mFullWifiLockTimers, mUnpluggables, in);
2984            } else {
2985                mFullWifiLockTimer = null;
2986            }
2987            mWifiScanStarted = false;
2988            if (in.readInt() != 0) {
2989                mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
2990                        mWifiScanTimers, mUnpluggables, in);
2991            } else {
2992                mWifiScanTimer = null;
2993            }
2994            mWifiMulticastEnabled = false;
2995            if (in.readInt() != 0) {
2996                mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
2997                        mWifiMulticastTimers, mUnpluggables, in);
2998            } else {
2999                mWifiMulticastTimer = null;
3000            }
3001            mAudioTurnedOn = false;
3002            if (in.readInt() != 0) {
3003                mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
3004                        null, mUnpluggables, in);
3005            } else {
3006                mAudioTurnedOnTimer = null;
3007            }
3008            mVideoTurnedOn = false;
3009            if (in.readInt() != 0) {
3010                mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
3011                        null, mUnpluggables, in);
3012            } else {
3013                mVideoTurnedOnTimer = null;
3014            }
3015            if (in.readInt() != 0) {
3016                mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
3017                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
3018                    mUserActivityCounters[i] = new Counter(mUnpluggables, in);
3019                }
3020            } else {
3021                mUserActivityCounters = null;
3022            }
3023        }
3024
3025        /**
3026         * The statistics associated with a particular wake lock.
3027         */
3028        public final class Wakelock extends BatteryStats.Uid.Wakelock {
3029            /**
3030             * How long (in ms) this uid has been keeping the device partially awake.
3031             */
3032            StopwatchTimer mTimerPartial;
3033
3034            /**
3035             * How long (in ms) this uid has been keeping the device fully awake.
3036             */
3037            StopwatchTimer mTimerFull;
3038
3039            /**
3040             * How long (in ms) this uid has had a window keeping the device awake.
3041             */
3042            StopwatchTimer mTimerWindow;
3043
3044            /**
3045             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
3046             * proper timer pool from the given BatteryStatsImpl object.
3047             *
3048             * @param in the Parcel to be read from.
3049             * return a new Timer, or null.
3050             */
3051            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
3052                    ArrayList<Unpluggable> unpluggables, Parcel in) {
3053                if (in.readInt() == 0) {
3054                    return null;
3055                }
3056
3057                return new StopwatchTimer(Uid.this, type, pool, unpluggables, in);
3058            }
3059
3060            boolean reset() {
3061                boolean wlactive = false;
3062                if (mTimerFull != null) {
3063                    wlactive |= !mTimerFull.reset(BatteryStatsImpl.this, false);
3064                }
3065                if (mTimerPartial != null) {
3066                    wlactive |= !mTimerPartial.reset(BatteryStatsImpl.this, false);
3067                }
3068                if (mTimerWindow != null) {
3069                    wlactive |= !mTimerWindow.reset(BatteryStatsImpl.this, false);
3070                }
3071                if (!wlactive) {
3072                    if (mTimerFull != null) {
3073                        mTimerFull.detach();
3074                        mTimerFull = null;
3075                    }
3076                    if (mTimerPartial != null) {
3077                        mTimerPartial.detach();
3078                        mTimerPartial = null;
3079                    }
3080                    if (mTimerWindow != null) {
3081                        mTimerWindow.detach();
3082                        mTimerWindow = null;
3083                    }
3084                }
3085                return !wlactive;
3086            }
3087
3088            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
3089                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
3090                        mPartialTimers, unpluggables, in);
3091                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
3092                        mFullTimers, unpluggables, in);
3093                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
3094                        mWindowTimers, unpluggables, in);
3095            }
3096
3097            void writeToParcelLocked(Parcel out, long batteryRealtime) {
3098                Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
3099                Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
3100                Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
3101            }
3102
3103            @Override
3104            public Timer getWakeTime(int type) {
3105                switch (type) {
3106                case WAKE_TYPE_FULL: return mTimerFull;
3107                case WAKE_TYPE_PARTIAL: return mTimerPartial;
3108                case WAKE_TYPE_WINDOW: return mTimerWindow;
3109                default: throw new IllegalArgumentException("type = " + type);
3110                }
3111            }
3112        }
3113
3114        public final class Sensor extends BatteryStats.Uid.Sensor {
3115            final int mHandle;
3116            StopwatchTimer mTimer;
3117
3118            public Sensor(int handle) {
3119                mHandle = handle;
3120            }
3121
3122            private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
3123                    Parcel in) {
3124                if (in.readInt() == 0) {
3125                    return null;
3126                }
3127
3128                ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
3129                if (pool == null) {
3130                    pool = new ArrayList<StopwatchTimer>();
3131                    mSensorTimers.put(mHandle, pool);
3132                }
3133                return new StopwatchTimer(Uid.this, 0, pool, unpluggables, in);
3134            }
3135
3136            boolean reset() {
3137                if (mTimer.reset(BatteryStatsImpl.this, true)) {
3138                    mTimer = null;
3139                    return true;
3140                }
3141                return false;
3142            }
3143
3144            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
3145                mTimer = readTimerFromParcel(unpluggables, in);
3146            }
3147
3148            void writeToParcelLocked(Parcel out, long batteryRealtime) {
3149                Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
3150            }
3151
3152            @Override
3153            public Timer getSensorTime() {
3154                return mTimer;
3155            }
3156
3157            @Override
3158            public int getHandle() {
3159                return mHandle;
3160            }
3161        }
3162
3163        /**
3164         * The statistics associated with a particular process.
3165         */
3166        public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
3167            /**
3168             * Total time (in 1/100 sec) spent executing in user code.
3169             */
3170            long mUserTime;
3171
3172            /**
3173             * Total time (in 1/100 sec) spent executing in kernel code.
3174             */
3175            long mSystemTime;
3176
3177            /**
3178             * Number of times the process has been started.
3179             */
3180            int mStarts;
3181
3182            /**
3183             * Amount of time the process was running in the foreground.
3184             */
3185            long mForegroundTime;
3186
3187            /**
3188             * The amount of user time loaded from a previous save.
3189             */
3190            long mLoadedUserTime;
3191
3192            /**
3193             * The amount of system time loaded from a previous save.
3194             */
3195            long mLoadedSystemTime;
3196
3197            /**
3198             * The number of times the process has started from a previous save.
3199             */
3200            int mLoadedStarts;
3201
3202            /**
3203             * The amount of foreground time loaded from a previous save.
3204             */
3205            long mLoadedForegroundTime;
3206
3207            /**
3208             * The amount of user time loaded from the previous run.
3209             */
3210            long mLastUserTime;
3211
3212            /**
3213             * The amount of system time loaded from the previous run.
3214             */
3215            long mLastSystemTime;
3216
3217            /**
3218             * The number of times the process has started from the previous run.
3219             */
3220            int mLastStarts;
3221
3222            /**
3223             * The amount of foreground time loaded from the previous run
3224             */
3225            long mLastForegroundTime;
3226
3227            /**
3228             * The amount of user time when last unplugged.
3229             */
3230            long mUnpluggedUserTime;
3231
3232            /**
3233             * The amount of system time when last unplugged.
3234             */
3235            long mUnpluggedSystemTime;
3236
3237            /**
3238             * The number of times the process has started before unplugged.
3239             */
3240            int mUnpluggedStarts;
3241
3242            /**
3243             * The amount of foreground time since unplugged.
3244             */
3245            long mUnpluggedForegroundTime;
3246
3247            SamplingCounter[] mSpeedBins;
3248
3249            ArrayList<ExcessivePower> mExcessivePower;
3250
3251            Proc() {
3252                mUnpluggables.add(this);
3253                mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
3254            }
3255
3256            public void unplug(long batteryUptime, long batteryRealtime) {
3257                mUnpluggedUserTime = mUserTime;
3258                mUnpluggedSystemTime = mSystemTime;
3259                mUnpluggedStarts = mStarts;
3260                mUnpluggedForegroundTime = mForegroundTime;
3261            }
3262
3263            public void plug(long batteryUptime, long batteryRealtime) {
3264            }
3265
3266            void detach() {
3267                mUnpluggables.remove(this);
3268                for (int i = 0; i < mSpeedBins.length; i++) {
3269                    SamplingCounter c = mSpeedBins[i];
3270                    if (c != null) {
3271                        mUnpluggables.remove(c);
3272                        mSpeedBins[i] = null;
3273                    }
3274                }
3275            }
3276
3277            public int countExcessivePowers() {
3278                return mExcessivePower != null ? mExcessivePower.size() : 0;
3279            }
3280
3281            public ExcessivePower getExcessivePower(int i) {
3282                if (mExcessivePower != null) {
3283                    return mExcessivePower.get(i);
3284                }
3285                return null;
3286            }
3287
3288            public void addExcessiveWake(long overTime, long usedTime) {
3289                if (mExcessivePower == null) {
3290                    mExcessivePower = new ArrayList<ExcessivePower>();
3291                }
3292                ExcessivePower ew = new ExcessivePower();
3293                ew.type = ExcessivePower.TYPE_WAKE;
3294                ew.overTime = overTime;
3295                ew.usedTime = usedTime;
3296                mExcessivePower.add(ew);
3297            }
3298
3299            public void addExcessiveCpu(long overTime, long usedTime) {
3300                if (mExcessivePower == null) {
3301                    mExcessivePower = new ArrayList<ExcessivePower>();
3302                }
3303                ExcessivePower ew = new ExcessivePower();
3304                ew.type = ExcessivePower.TYPE_CPU;
3305                ew.overTime = overTime;
3306                ew.usedTime = usedTime;
3307                mExcessivePower.add(ew);
3308            }
3309
3310            void writeExcessivePowerToParcelLocked(Parcel out) {
3311                if (mExcessivePower == null) {
3312                    out.writeInt(0);
3313                    return;
3314                }
3315
3316                final int N = mExcessivePower.size();
3317                out.writeInt(N);
3318                for (int i=0; i<N; i++) {
3319                    ExcessivePower ew = mExcessivePower.get(i);
3320                    out.writeInt(ew.type);
3321                    out.writeLong(ew.overTime);
3322                    out.writeLong(ew.usedTime);
3323                }
3324            }
3325
3326            boolean readExcessivePowerFromParcelLocked(Parcel in) {
3327                final int N = in.readInt();
3328                if (N == 0) {
3329                    mExcessivePower = null;
3330                    return true;
3331                }
3332
3333                if (N > 10000) {
3334                    Slog.w(TAG, "File corrupt: too many excessive power entries " + N);
3335                    return false;
3336                }
3337
3338                mExcessivePower = new ArrayList<ExcessivePower>();
3339                for (int i=0; i<N; i++) {
3340                    ExcessivePower ew = new ExcessivePower();
3341                    ew.type = in.readInt();
3342                    ew.overTime = in.readLong();
3343                    ew.usedTime = in.readLong();
3344                    mExcessivePower.add(ew);
3345                }
3346                return true;
3347            }
3348
3349            void writeToParcelLocked(Parcel out) {
3350                out.writeLong(mUserTime);
3351                out.writeLong(mSystemTime);
3352                out.writeLong(mForegroundTime);
3353                out.writeInt(mStarts);
3354                out.writeLong(mLoadedUserTime);
3355                out.writeLong(mLoadedSystemTime);
3356                out.writeLong(mLoadedForegroundTime);
3357                out.writeInt(mLoadedStarts);
3358                out.writeLong(mUnpluggedUserTime);
3359                out.writeLong(mUnpluggedSystemTime);
3360                out.writeLong(mUnpluggedForegroundTime);
3361                out.writeInt(mUnpluggedStarts);
3362
3363                out.writeInt(mSpeedBins.length);
3364                for (int i = 0; i < mSpeedBins.length; i++) {
3365                    SamplingCounter c = mSpeedBins[i];
3366                    if (c != null) {
3367                        out.writeInt(1);
3368                        c.writeToParcel(out);
3369                    } else {
3370                        out.writeInt(0);
3371                    }
3372                }
3373
3374                writeExcessivePowerToParcelLocked(out);
3375            }
3376
3377            void readFromParcelLocked(Parcel in) {
3378                mUserTime = in.readLong();
3379                mSystemTime = in.readLong();
3380                mForegroundTime = in.readLong();
3381                mStarts = in.readInt();
3382                mLoadedUserTime = in.readLong();
3383                mLoadedSystemTime = in.readLong();
3384                mLoadedForegroundTime = in.readLong();
3385                mLoadedStarts = in.readInt();
3386                mLastUserTime = 0;
3387                mLastSystemTime = 0;
3388                mLastForegroundTime = 0;
3389                mLastStarts = 0;
3390                mUnpluggedUserTime = in.readLong();
3391                mUnpluggedSystemTime = in.readLong();
3392                mUnpluggedForegroundTime = in.readLong();
3393                mUnpluggedStarts = in.readInt();
3394
3395                int bins = in.readInt();
3396                int steps = getCpuSpeedSteps();
3397                mSpeedBins = new SamplingCounter[bins >= steps ? bins : steps];
3398                for (int i = 0; i < bins; i++) {
3399                    if (in.readInt() != 0) {
3400                        mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
3401                    }
3402                }
3403
3404                readExcessivePowerFromParcelLocked(in);
3405            }
3406
3407            public BatteryStatsImpl getBatteryStats() {
3408                return BatteryStatsImpl.this;
3409            }
3410
3411            public void addCpuTimeLocked(int utime, int stime) {
3412                mUserTime += utime;
3413                mSystemTime += stime;
3414            }
3415
3416            public void addForegroundTimeLocked(long ttime) {
3417                mForegroundTime += ttime;
3418            }
3419
3420            public void incStartsLocked() {
3421                mStarts++;
3422            }
3423
3424            @Override
3425            public long getUserTime(int which) {
3426                long val;
3427                if (which == STATS_LAST) {
3428                    val = mLastUserTime;
3429                } else {
3430                    val = mUserTime;
3431                    if (which == STATS_CURRENT) {
3432                        val -= mLoadedUserTime;
3433                    } else if (which == STATS_SINCE_UNPLUGGED) {
3434                        val -= mUnpluggedUserTime;
3435                    }
3436                }
3437                return val;
3438            }
3439
3440            @Override
3441            public long getSystemTime(int which) {
3442                long val;
3443                if (which == STATS_LAST) {
3444                    val = mLastSystemTime;
3445                } else {
3446                    val = mSystemTime;
3447                    if (which == STATS_CURRENT) {
3448                        val -= mLoadedSystemTime;
3449                    } else if (which == STATS_SINCE_UNPLUGGED) {
3450                        val -= mUnpluggedSystemTime;
3451                    }
3452                }
3453                return val;
3454            }
3455
3456            @Override
3457            public long getForegroundTime(int which) {
3458                long val;
3459                if (which == STATS_LAST) {
3460                    val = mLastForegroundTime;
3461                } else {
3462                    val = mForegroundTime;
3463                    if (which == STATS_CURRENT) {
3464                        val -= mLoadedForegroundTime;
3465                    } else if (which == STATS_SINCE_UNPLUGGED) {
3466                        val -= mUnpluggedForegroundTime;
3467                    }
3468                }
3469                return val;
3470            }
3471
3472            @Override
3473            public int getStarts(int which) {
3474                int val;
3475                if (which == STATS_LAST) {
3476                    val = mLastStarts;
3477                } else {
3478                    val = mStarts;
3479                    if (which == STATS_CURRENT) {
3480                        val -= mLoadedStarts;
3481                    } else if (which == STATS_SINCE_UNPLUGGED) {
3482                        val -= mUnpluggedStarts;
3483                    }
3484                }
3485                return val;
3486            }
3487
3488            /* Called by ActivityManagerService when CPU times are updated. */
3489            public void addSpeedStepTimes(long[] values) {
3490                for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
3491                    long amt = values[i];
3492                    if (amt != 0) {
3493                        SamplingCounter c = mSpeedBins[i];
3494                        if (c == null) {
3495                            mSpeedBins[i] = c = new SamplingCounter(mUnpluggables);
3496                        }
3497                        c.addCountAtomic(values[i]);
3498                    }
3499                }
3500            }
3501
3502            @Override
3503            public long getTimeAtCpuSpeedStep(int speedStep, int which) {
3504                if (speedStep < mSpeedBins.length) {
3505                    SamplingCounter c = mSpeedBins[speedStep];
3506                    return c != null ? c.getCountLocked(which) : 0;
3507                } else {
3508                    return 0;
3509                }
3510            }
3511        }
3512
3513        /**
3514         * The statistics associated with a particular package.
3515         */
3516        public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
3517            /**
3518             * Number of times this package has done something that could wake up the
3519             * device from sleep.
3520             */
3521            int mWakeups;
3522
3523            /**
3524             * Number of things that could wake up the device loaded from a
3525             * previous save.
3526             */
3527            int mLoadedWakeups;
3528
3529            /**
3530             * Number of things that could wake up the device as of the
3531             * last run.
3532             */
3533            int mLastWakeups;
3534
3535            /**
3536             * Number of things that could wake up the device as of the
3537             * last run.
3538             */
3539            int mUnpluggedWakeups;
3540
3541            /**
3542             * The statics we have collected for this package's services.
3543             */
3544            final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
3545
3546            Pkg() {
3547                mUnpluggables.add(this);
3548            }
3549
3550            public void unplug(long batteryUptime, long batteryRealtime) {
3551                mUnpluggedWakeups = mWakeups;
3552            }
3553
3554            public void plug(long batteryUptime, long batteryRealtime) {
3555            }
3556
3557            void detach() {
3558                mUnpluggables.remove(this);
3559            }
3560
3561            void readFromParcelLocked(Parcel in) {
3562                mWakeups = in.readInt();
3563                mLoadedWakeups = in.readInt();
3564                mLastWakeups = 0;
3565                mUnpluggedWakeups = in.readInt();
3566
3567                int numServs = in.readInt();
3568                mServiceStats.clear();
3569                for (int m = 0; m < numServs; m++) {
3570                    String serviceName = in.readString();
3571                    Uid.Pkg.Serv serv = new Serv();
3572                    mServiceStats.put(serviceName, serv);
3573
3574                    serv.readFromParcelLocked(in);
3575                }
3576            }
3577
3578            void writeToParcelLocked(Parcel out) {
3579                out.writeInt(mWakeups);
3580                out.writeInt(mLoadedWakeups);
3581                out.writeInt(mUnpluggedWakeups);
3582
3583                out.writeInt(mServiceStats.size());
3584                for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
3585                    out.writeString(servEntry.getKey());
3586                    Uid.Pkg.Serv serv = servEntry.getValue();
3587
3588                    serv.writeToParcelLocked(out);
3589                }
3590            }
3591
3592            @Override
3593            public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
3594                return mServiceStats;
3595            }
3596
3597            @Override
3598            public int getWakeups(int which) {
3599                int val;
3600                if (which == STATS_LAST) {
3601                    val = mLastWakeups;
3602                } else {
3603                    val = mWakeups;
3604                    if (which == STATS_CURRENT) {
3605                        val -= mLoadedWakeups;
3606                    } else if (which == STATS_SINCE_UNPLUGGED) {
3607                        val -= mUnpluggedWakeups;
3608                    }
3609                }
3610
3611                return val;
3612            }
3613
3614            /**
3615             * The statistics associated with a particular service.
3616             */
3617            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
3618                /**
3619                 * Total time (ms in battery uptime) the service has been left started.
3620                 */
3621                long mStartTime;
3622
3623                /**
3624                 * If service has been started and not yet stopped, this is
3625                 * when it was started.
3626                 */
3627                long mRunningSince;
3628
3629                /**
3630                 * True if we are currently running.
3631                 */
3632                boolean mRunning;
3633
3634                /**
3635                 * Total number of times startService() has been called.
3636                 */
3637                int mStarts;
3638
3639                /**
3640                 * Total time (ms in battery uptime) the service has been left launched.
3641                 */
3642                long mLaunchedTime;
3643
3644                /**
3645                 * If service has been launched and not yet exited, this is
3646                 * when it was launched (ms in battery uptime).
3647                 */
3648                long mLaunchedSince;
3649
3650                /**
3651                 * True if we are currently launched.
3652                 */
3653                boolean mLaunched;
3654
3655                /**
3656                 * Total number times the service has been launched.
3657                 */
3658                int mLaunches;
3659
3660                /**
3661                 * The amount of time spent started loaded from a previous save
3662                 * (ms in battery uptime).
3663                 */
3664                long mLoadedStartTime;
3665
3666                /**
3667                 * The number of starts loaded from a previous save.
3668                 */
3669                int mLoadedStarts;
3670
3671                /**
3672                 * The number of launches loaded from a previous save.
3673                 */
3674                int mLoadedLaunches;
3675
3676                /**
3677                 * The amount of time spent started as of the last run (ms
3678                 * in battery uptime).
3679                 */
3680                long mLastStartTime;
3681
3682                /**
3683                 * The number of starts as of the last run.
3684                 */
3685                int mLastStarts;
3686
3687                /**
3688                 * The number of launches as of the last run.
3689                 */
3690                int mLastLaunches;
3691
3692                /**
3693                 * The amount of time spent started when last unplugged (ms
3694                 * in battery uptime).
3695                 */
3696                long mUnpluggedStartTime;
3697
3698                /**
3699                 * The number of starts when last unplugged.
3700                 */
3701                int mUnpluggedStarts;
3702
3703                /**
3704                 * The number of launches when last unplugged.
3705                 */
3706                int mUnpluggedLaunches;
3707
3708                Serv() {
3709                    mUnpluggables.add(this);
3710                }
3711
3712                public void unplug(long batteryUptime, long batteryRealtime) {
3713                    mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
3714                    mUnpluggedStarts = mStarts;
3715                    mUnpluggedLaunches = mLaunches;
3716                }
3717
3718                public void plug(long batteryUptime, long batteryRealtime) {
3719                }
3720
3721                void detach() {
3722                    mUnpluggables.remove(this);
3723                }
3724
3725                void readFromParcelLocked(Parcel in) {
3726                    mStartTime = in.readLong();
3727                    mRunningSince = in.readLong();
3728                    mRunning = in.readInt() != 0;
3729                    mStarts = in.readInt();
3730                    mLaunchedTime = in.readLong();
3731                    mLaunchedSince = in.readLong();
3732                    mLaunched = in.readInt() != 0;
3733                    mLaunches = in.readInt();
3734                    mLoadedStartTime = in.readLong();
3735                    mLoadedStarts = in.readInt();
3736                    mLoadedLaunches = in.readInt();
3737                    mLastStartTime = 0;
3738                    mLastStarts = 0;
3739                    mLastLaunches = 0;
3740                    mUnpluggedStartTime = in.readLong();
3741                    mUnpluggedStarts = in.readInt();
3742                    mUnpluggedLaunches = in.readInt();
3743                }
3744
3745                void writeToParcelLocked(Parcel out) {
3746                    out.writeLong(mStartTime);
3747                    out.writeLong(mRunningSince);
3748                    out.writeInt(mRunning ? 1 : 0);
3749                    out.writeInt(mStarts);
3750                    out.writeLong(mLaunchedTime);
3751                    out.writeLong(mLaunchedSince);
3752                    out.writeInt(mLaunched ? 1 : 0);
3753                    out.writeInt(mLaunches);
3754                    out.writeLong(mLoadedStartTime);
3755                    out.writeInt(mLoadedStarts);
3756                    out.writeInt(mLoadedLaunches);
3757                    out.writeLong(mUnpluggedStartTime);
3758                    out.writeInt(mUnpluggedStarts);
3759                    out.writeInt(mUnpluggedLaunches);
3760                }
3761
3762                long getLaunchTimeToNowLocked(long batteryUptime) {
3763                    if (!mLaunched) return mLaunchedTime;
3764                    return mLaunchedTime + batteryUptime - mLaunchedSince;
3765                }
3766
3767                long getStartTimeToNowLocked(long batteryUptime) {
3768                    if (!mRunning) return mStartTime;
3769                    return mStartTime + batteryUptime - mRunningSince;
3770                }
3771
3772                public void startLaunchedLocked() {
3773                    if (!mLaunched) {
3774                        mLaunches++;
3775                        mLaunchedSince = getBatteryUptimeLocked();
3776                        mLaunched = true;
3777                    }
3778                }
3779
3780                public void stopLaunchedLocked() {
3781                    if (mLaunched) {
3782                        long time = getBatteryUptimeLocked() - mLaunchedSince;
3783                        if (time > 0) {
3784                            mLaunchedTime += time;
3785                        } else {
3786                            mLaunches--;
3787                        }
3788                        mLaunched = false;
3789                    }
3790                }
3791
3792                public void startRunningLocked() {
3793                    if (!mRunning) {
3794                        mStarts++;
3795                        mRunningSince = getBatteryUptimeLocked();
3796                        mRunning = true;
3797                    }
3798                }
3799
3800                public void stopRunningLocked() {
3801                    if (mRunning) {
3802                        long time = getBatteryUptimeLocked() - mRunningSince;
3803                        if (time > 0) {
3804                            mStartTime += time;
3805                        } else {
3806                            mStarts--;
3807                        }
3808                        mRunning = false;
3809                    }
3810                }
3811
3812                public BatteryStatsImpl getBatteryStats() {
3813                    return BatteryStatsImpl.this;
3814                }
3815
3816                @Override
3817                public int getLaunches(int which) {
3818                    int val;
3819
3820                    if (which == STATS_LAST) {
3821                        val = mLastLaunches;
3822                    } else {
3823                        val = mLaunches;
3824                        if (which == STATS_CURRENT) {
3825                            val -= mLoadedLaunches;
3826                        } else if (which == STATS_SINCE_UNPLUGGED) {
3827                            val -= mUnpluggedLaunches;
3828                        }
3829                    }
3830
3831                    return val;
3832                }
3833
3834                @Override
3835                public long getStartTime(long now, int which) {
3836                    long val;
3837                    if (which == STATS_LAST) {
3838                        val = mLastStartTime;
3839                    } else {
3840                        val = getStartTimeToNowLocked(now);
3841                        if (which == STATS_CURRENT) {
3842                            val -= mLoadedStartTime;
3843                        } else if (which == STATS_SINCE_UNPLUGGED) {
3844                            val -= mUnpluggedStartTime;
3845                        }
3846                    }
3847
3848                    return val;
3849                }
3850
3851                @Override
3852                public int getStarts(int which) {
3853                    int val;
3854                    if (which == STATS_LAST) {
3855                        val = mLastStarts;
3856                    } else {
3857                        val = mStarts;
3858                        if (which == STATS_CURRENT) {
3859                            val -= mLoadedStarts;
3860                        } else if (which == STATS_SINCE_UNPLUGGED) {
3861                            val -= mUnpluggedStarts;
3862                        }
3863                    }
3864
3865                    return val;
3866                }
3867            }
3868
3869            public BatteryStatsImpl getBatteryStats() {
3870                return BatteryStatsImpl.this;
3871            }
3872
3873            public void incWakeupsLocked() {
3874                mWakeups++;
3875            }
3876
3877            final Serv newServiceStatsLocked() {
3878                return new Serv();
3879            }
3880        }
3881
3882        /**
3883         * Retrieve the statistics object for a particular process, creating
3884         * if needed.
3885         */
3886        public Proc getProcessStatsLocked(String name) {
3887            Proc ps = mProcessStats.get(name);
3888            if (ps == null) {
3889                ps = new Proc();
3890                mProcessStats.put(name, ps);
3891            }
3892
3893            return ps;
3894        }
3895
3896        public SparseArray<? extends Pid> getPidStats() {
3897            return mPids;
3898        }
3899
3900        public Pid getPidStatsLocked(int pid) {
3901            Pid p = mPids.get(pid);
3902            if (p == null) {
3903                p = new Pid();
3904                mPids.put(pid, p);
3905            }
3906            return p;
3907        }
3908
3909        /**
3910         * Retrieve the statistics object for a particular service, creating
3911         * if needed.
3912         */
3913        public Pkg getPackageStatsLocked(String name) {
3914            Pkg ps = mPackageStats.get(name);
3915            if (ps == null) {
3916                ps = new Pkg();
3917                mPackageStats.put(name, ps);
3918            }
3919
3920            return ps;
3921        }
3922
3923        /**
3924         * Retrieve the statistics object for a particular service, creating
3925         * if needed.
3926         */
3927        public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
3928            Pkg ps = getPackageStatsLocked(pkg);
3929            Pkg.Serv ss = ps.mServiceStats.get(serv);
3930            if (ss == null) {
3931                ss = ps.newServiceStatsLocked();
3932                ps.mServiceStats.put(serv, ss);
3933            }
3934
3935            return ss;
3936        }
3937
3938        public StopwatchTimer getWakeTimerLocked(String name, int type) {
3939            Wakelock wl = mWakelockStats.get(name);
3940            if (wl == null) {
3941                final int N = mWakelockStats.size();
3942                if (N > MAX_WAKELOCKS_PER_UID && (mUid != Process.SYSTEM_UID
3943                        || N > MAX_WAKELOCKS_PER_UID_IN_SYSTEM)) {
3944                    name = BATCHED_WAKELOCK_NAME;
3945                    wl = mWakelockStats.get(name);
3946                }
3947                if (wl == null) {
3948                    wl = new Wakelock();
3949                    mWakelockStats.put(name, wl);
3950                }
3951            }
3952            StopwatchTimer t = null;
3953            switch (type) {
3954                case WAKE_TYPE_PARTIAL:
3955                    t = wl.mTimerPartial;
3956                    if (t == null) {
3957                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
3958                                mPartialTimers, mUnpluggables);
3959                        wl.mTimerPartial = t;
3960                    }
3961                    return t;
3962                case WAKE_TYPE_FULL:
3963                    t = wl.mTimerFull;
3964                    if (t == null) {
3965                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
3966                                mFullTimers, mUnpluggables);
3967                        wl.mTimerFull = t;
3968                    }
3969                    return t;
3970                case WAKE_TYPE_WINDOW:
3971                    t = wl.mTimerWindow;
3972                    if (t == null) {
3973                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
3974                                mWindowTimers, mUnpluggables);
3975                        wl.mTimerWindow = t;
3976                    }
3977                    return t;
3978                default:
3979                    throw new IllegalArgumentException("type=" + type);
3980            }
3981        }
3982
3983        public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
3984            Sensor se = mSensorStats.get(sensor);
3985            if (se == null) {
3986                if (!create) {
3987                    return null;
3988                }
3989                se = new Sensor(sensor);
3990                mSensorStats.put(sensor, se);
3991            }
3992            StopwatchTimer t = se.mTimer;
3993            if (t != null) {
3994                return t;
3995            }
3996            ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
3997            if (timers == null) {
3998                timers = new ArrayList<StopwatchTimer>();
3999                mSensorTimers.put(sensor, timers);
4000            }
4001            t = new StopwatchTimer(Uid.this, BatteryStats.SENSOR, timers, mUnpluggables);
4002            se.mTimer = t;
4003            return t;
4004        }
4005
4006        public void noteStartWakeLocked(int pid, String name, int type) {
4007            StopwatchTimer t = getWakeTimerLocked(name, type);
4008            if (t != null) {
4009                t.startRunningLocked(BatteryStatsImpl.this);
4010            }
4011            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
4012                Pid p = getPidStatsLocked(pid);
4013                if (p.mWakeStart == 0) {
4014                    p.mWakeStart = SystemClock.elapsedRealtime();
4015                }
4016            }
4017        }
4018
4019        public void noteStopWakeLocked(int pid, String name, int type) {
4020            StopwatchTimer t = getWakeTimerLocked(name, type);
4021            if (t != null) {
4022                t.stopRunningLocked(BatteryStatsImpl.this);
4023            }
4024            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
4025                Pid p = mPids.get(pid);
4026                if (p != null && p.mWakeStart != 0) {
4027                    p.mWakeSum += SystemClock.elapsedRealtime() - p.mWakeStart;
4028                    p.mWakeStart = 0;
4029                }
4030            }
4031        }
4032
4033        public void reportExcessiveWakeLocked(String proc, long overTime, long usedTime) {
4034            Proc p = getProcessStatsLocked(proc);
4035            if (p != null) {
4036                p.addExcessiveWake(overTime, usedTime);
4037            }
4038        }
4039
4040        public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) {
4041            Proc p = getProcessStatsLocked(proc);
4042            if (p != null) {
4043                p.addExcessiveCpu(overTime, usedTime);
4044            }
4045        }
4046
4047        public void noteStartSensor(int sensor) {
4048            StopwatchTimer t = getSensorTimerLocked(sensor, true);
4049            if (t != null) {
4050                t.startRunningLocked(BatteryStatsImpl.this);
4051            }
4052        }
4053
4054        public void noteStopSensor(int sensor) {
4055            // Don't create a timer if one doesn't already exist
4056            StopwatchTimer t = getSensorTimerLocked(sensor, false);
4057            if (t != null) {
4058                t.stopRunningLocked(BatteryStatsImpl.this);
4059            }
4060        }
4061
4062        public void noteStartGps() {
4063            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
4064            if (t != null) {
4065                t.startRunningLocked(BatteryStatsImpl.this);
4066            }
4067        }
4068
4069        public void noteStopGps() {
4070            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
4071            if (t != null) {
4072                t.stopRunningLocked(BatteryStatsImpl.this);
4073            }
4074        }
4075
4076        public BatteryStatsImpl getBatteryStats() {
4077            return BatteryStatsImpl.this;
4078        }
4079    }
4080
4081    public BatteryStatsImpl(String filename) {
4082        mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
4083        mHandler = new MyHandler();
4084        mStartCount++;
4085        mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables);
4086        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4087            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mUnpluggables);
4088        }
4089        mInputEventCounter = new Counter(mUnpluggables);
4090        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables);
4091        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
4092            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null, mUnpluggables);
4093        }
4094        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables);
4095        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4096            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null, mUnpluggables);
4097        }
4098        mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables);
4099        mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
4100        mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables);
4101        mAudioOnTimer = new StopwatchTimer(null, -6, null, mUnpluggables);
4102        mVideoOnTimer = new StopwatchTimer(null, -7, null, mUnpluggables);
4103        mOnBattery = mOnBatteryInternal = false;
4104        initTimes();
4105        mTrackBatteryPastUptime = 0;
4106        mTrackBatteryPastRealtime = 0;
4107        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
4108        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
4109        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
4110        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
4111        mDischargeStartLevel = 0;
4112        mDischargeUnplugLevel = 0;
4113        mDischargeCurrentLevel = 0;
4114        initDischarge();
4115        clearHistoryLocked();
4116    }
4117
4118    public BatteryStatsImpl(Parcel p) {
4119        mFile = null;
4120        mHandler = null;
4121        clearHistoryLocked();
4122        readFromParcel(p);
4123    }
4124
4125    public void setCallback(BatteryCallback cb) {
4126        mCallback = cb;
4127    }
4128
4129    public void setNumSpeedSteps(int steps) {
4130        if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
4131    }
4132
4133    public void setRadioScanningTimeout(long timeout) {
4134        if (mPhoneSignalScanningTimer != null) {
4135            mPhoneSignalScanningTimer.setTimeout(timeout);
4136        }
4137    }
4138
4139    @Override
4140    public boolean startIteratingOldHistoryLocked() {
4141        if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
4142                + " pos=" + mHistoryBuffer.dataPosition());
4143        mHistoryBuffer.setDataPosition(0);
4144        mHistoryReadTmp.clear();
4145        mReadOverflow = false;
4146        mIteratingHistory = true;
4147        return (mHistoryIterator = mHistory) != null;
4148    }
4149
4150    @Override
4151    public boolean getNextOldHistoryLocked(HistoryItem out) {
4152        boolean end = mHistoryBuffer.dataPosition() >= mHistoryBuffer.dataSize();
4153        if (!end) {
4154            mHistoryReadTmp.readDelta(mHistoryBuffer);
4155            mReadOverflow |= mHistoryReadTmp.cmd == HistoryItem.CMD_OVERFLOW;
4156        }
4157        HistoryItem cur = mHistoryIterator;
4158        if (cur == null) {
4159            if (!mReadOverflow && !end) {
4160                Slog.w(TAG, "Old history ends before new history!");
4161            }
4162            return false;
4163        }
4164        out.setTo(cur);
4165        mHistoryIterator = cur.next;
4166        if (!mReadOverflow) {
4167            if (end) {
4168                Slog.w(TAG, "New history ends before old history!");
4169            } else if (!out.same(mHistoryReadTmp)) {
4170                long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
4171                PrintWriter pw = new PrintWriter(new LogWriter(android.util.Log.WARN, TAG));
4172                pw.println("Histories differ!");
4173                pw.println("Old history:");
4174                (new HistoryPrinter()).printNextItem(pw, out, now);
4175                pw.println("New history:");
4176                (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, now);
4177            }
4178        }
4179        return true;
4180    }
4181
4182    @Override
4183    public void finishIteratingOldHistoryLocked() {
4184        mIteratingHistory = false;
4185        mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
4186    }
4187
4188    @Override
4189    public boolean startIteratingHistoryLocked() {
4190        if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
4191                + " pos=" + mHistoryBuffer.dataPosition());
4192        mHistoryBuffer.setDataPosition(0);
4193        mReadOverflow = false;
4194        mIteratingHistory = true;
4195        return mHistoryBuffer.dataSize() > 0;
4196    }
4197
4198    @Override
4199    public boolean getNextHistoryLocked(HistoryItem out) {
4200        final int pos = mHistoryBuffer.dataPosition();
4201        if (pos == 0) {
4202            out.clear();
4203        }
4204        boolean end = pos >= mHistoryBuffer.dataSize();
4205        if (end) {
4206            return false;
4207        }
4208
4209        out.readDelta(mHistoryBuffer);
4210        return true;
4211    }
4212
4213    @Override
4214    public void finishIteratingHistoryLocked() {
4215        mIteratingHistory = false;
4216        mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
4217    }
4218
4219    @Override
4220    public long getHistoryBaseTime() {
4221        return mHistoryBaseTime;
4222    }
4223
4224    @Override
4225    public int getStartCount() {
4226        return mStartCount;
4227    }
4228
4229    public boolean isOnBattery() {
4230        return mOnBattery;
4231    }
4232
4233    public boolean isScreenOn() {
4234        return mScreenOn;
4235    }
4236
4237    void initTimes() {
4238        mBatteryRealtime = mTrackBatteryPastUptime = 0;
4239        mBatteryUptime = mTrackBatteryPastRealtime = 0;
4240        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
4241        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
4242        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
4243        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
4244    }
4245
4246    void initDischarge() {
4247        mLowDischargeAmountSinceCharge = 0;
4248        mHighDischargeAmountSinceCharge = 0;
4249        mDischargeAmountScreenOn = 0;
4250        mDischargeAmountScreenOnSinceCharge = 0;
4251        mDischargeAmountScreenOff = 0;
4252        mDischargeAmountScreenOffSinceCharge = 0;
4253    }
4254
4255    public void resetAllStatsLocked() {
4256        mStartCount = 0;
4257        initTimes();
4258        mScreenOnTimer.reset(this, false);
4259        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4260            mScreenBrightnessTimer[i].reset(this, false);
4261        }
4262        mInputEventCounter.reset(false);
4263        mPhoneOnTimer.reset(this, false);
4264        mAudioOnTimer.reset(this, false);
4265        mVideoOnTimer.reset(this, false);
4266        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
4267            mPhoneSignalStrengthsTimer[i].reset(this, false);
4268        }
4269        mPhoneSignalScanningTimer.reset(this, false);
4270        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4271            mPhoneDataConnectionsTimer[i].reset(this, false);
4272        }
4273        mWifiOnTimer.reset(this, false);
4274        mGlobalWifiRunningTimer.reset(this, false);
4275        mBluetoothOnTimer.reset(this, false);
4276
4277        for (int i=0; i<mUidStats.size(); i++) {
4278            if (mUidStats.valueAt(i).reset()) {
4279                mUidStats.remove(mUidStats.keyAt(i));
4280                i--;
4281            }
4282        }
4283
4284        if (mKernelWakelockStats.size() > 0) {
4285            for (SamplingTimer timer : mKernelWakelockStats.values()) {
4286                mUnpluggables.remove(timer);
4287            }
4288            mKernelWakelockStats.clear();
4289        }
4290
4291        initDischarge();
4292
4293        clearHistoryLocked();
4294    }
4295
4296    void updateDischargeScreenLevelsLocked(boolean oldScreenOn, boolean newScreenOn) {
4297        if (oldScreenOn) {
4298            int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
4299            if (diff > 0) {
4300                mDischargeAmountScreenOn += diff;
4301                mDischargeAmountScreenOnSinceCharge += diff;
4302            }
4303        } else {
4304            int diff = mDischargeScreenOffUnplugLevel - mDischargeCurrentLevel;
4305            if (diff > 0) {
4306                mDischargeAmountScreenOff += diff;
4307                mDischargeAmountScreenOffSinceCharge += diff;
4308            }
4309        }
4310        if (newScreenOn) {
4311            mDischargeScreenOnUnplugLevel = mDischargeCurrentLevel;
4312            mDischargeScreenOffUnplugLevel = 0;
4313        } else {
4314            mDischargeScreenOnUnplugLevel = 0;
4315            mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
4316        }
4317    }
4318
4319    void setOnBattery(boolean onBattery, int oldStatus, int level) {
4320        synchronized(this) {
4321            setOnBatteryLocked(onBattery, oldStatus, level);
4322        }
4323    }
4324
4325    void setOnBatteryLocked(boolean onBattery, int oldStatus, int level) {
4326        boolean doWrite = false;
4327        Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
4328        m.arg1 = onBattery ? 1 : 0;
4329        mHandler.sendMessage(m);
4330        mOnBattery = mOnBatteryInternal = onBattery;
4331
4332        long uptime = SystemClock.uptimeMillis() * 1000;
4333        long mSecRealtime = SystemClock.elapsedRealtime();
4334        long realtime = mSecRealtime * 1000;
4335        if (onBattery) {
4336            // We will reset our status if we are unplugging after the
4337            // battery was last full, or the level is at 100, or
4338            // we have gone through a significant charge (from a very low
4339            // level to a now very high level).
4340            if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
4341                    || level >= 90
4342                    || (mDischargeCurrentLevel < 20 && level >= 80)) {
4343                doWrite = true;
4344                resetAllStatsLocked();
4345                mDischargeStartLevel = level;
4346            }
4347            updateKernelWakelocksLocked();
4348            mHistoryCur.batteryLevel = (byte)level;
4349            mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4350            if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
4351                    + Integer.toHexString(mHistoryCur.states));
4352            addHistoryRecordLocked(mSecRealtime);
4353            mTrackBatteryUptimeStart = uptime;
4354            mTrackBatteryRealtimeStart = realtime;
4355            mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
4356            mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
4357            mDischargeCurrentLevel = mDischargeUnplugLevel = level;
4358            if (mScreenOn) {
4359                mDischargeScreenOnUnplugLevel = level;
4360                mDischargeScreenOffUnplugLevel = 0;
4361            } else {
4362                mDischargeScreenOnUnplugLevel = 0;
4363                mDischargeScreenOffUnplugLevel = level;
4364            }
4365            mDischargeAmountScreenOn = 0;
4366            mDischargeAmountScreenOff = 0;
4367            doUnplugLocked(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
4368        } else {
4369            updateKernelWakelocksLocked();
4370            mHistoryCur.batteryLevel = (byte)level;
4371            mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4372            if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
4373                    + Integer.toHexString(mHistoryCur.states));
4374            addHistoryRecordLocked(mSecRealtime);
4375            mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
4376            mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
4377            mDischargeCurrentLevel = level;
4378            if (level < mDischargeUnplugLevel) {
4379                mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
4380                mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
4381            }
4382            updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
4383            doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
4384        }
4385        if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
4386            if (mFile != null) {
4387                writeAsyncLocked();
4388            }
4389        }
4390    }
4391
4392    // This should probably be exposed in the API, though it's not critical
4393    private static final int BATTERY_PLUGGED_NONE = 0;
4394
4395    public void setBatteryState(int status, int health, int plugType, int level,
4396            int temp, int volt) {
4397        synchronized(this) {
4398            boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
4399            int oldStatus = mHistoryCur.batteryStatus;
4400            if (!mHaveBatteryLevel) {
4401                mHaveBatteryLevel = true;
4402                // We start out assuming that the device is plugged in (not
4403                // on battery).  If our first report is now that we are indeed
4404                // plugged in, then twiddle our state to correctly reflect that
4405                // since we won't be going through the full setOnBattery().
4406                if (onBattery == mOnBattery) {
4407                    if (onBattery) {
4408                        mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4409                    } else {
4410                        mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4411                    }
4412                }
4413                oldStatus = status;
4414            }
4415            if (onBattery) {
4416                mDischargeCurrentLevel = level;
4417                mRecordingHistory = true;
4418            }
4419            if (onBattery != mOnBattery) {
4420                mHistoryCur.batteryLevel = (byte)level;
4421                mHistoryCur.batteryStatus = (byte)status;
4422                mHistoryCur.batteryHealth = (byte)health;
4423                mHistoryCur.batteryPlugType = (byte)plugType;
4424                mHistoryCur.batteryTemperature = (char)temp;
4425                mHistoryCur.batteryVoltage = (char)volt;
4426                setOnBatteryLocked(onBattery, oldStatus, level);
4427            } else {
4428                boolean changed = false;
4429                if (mHistoryCur.batteryLevel != level) {
4430                    mHistoryCur.batteryLevel = (byte)level;
4431                    changed = true;
4432                }
4433                if (mHistoryCur.batteryStatus != status) {
4434                    mHistoryCur.batteryStatus = (byte)status;
4435                    changed = true;
4436                }
4437                if (mHistoryCur.batteryHealth != health) {
4438                    mHistoryCur.batteryHealth = (byte)health;
4439                    changed = true;
4440                }
4441                if (mHistoryCur.batteryPlugType != plugType) {
4442                    mHistoryCur.batteryPlugType = (byte)plugType;
4443                    changed = true;
4444                }
4445                if (temp >= (mHistoryCur.batteryTemperature+10)
4446                        || temp <= (mHistoryCur.batteryTemperature-10)) {
4447                    mHistoryCur.batteryTemperature = (char)temp;
4448                    changed = true;
4449                }
4450                if (volt > (mHistoryCur.batteryVoltage+20)
4451                        || volt < (mHistoryCur.batteryVoltage-20)) {
4452                    mHistoryCur.batteryVoltage = (char)volt;
4453                    changed = true;
4454                }
4455                if (changed) {
4456                    addHistoryRecordLocked(SystemClock.elapsedRealtime());
4457                }
4458            }
4459            if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
4460                // We don't record history while we are plugged in and fully charged.
4461                // The next time we are unplugged, history will be cleared.
4462                mRecordingHistory = false;
4463            }
4464        }
4465    }
4466
4467    public void updateKernelWakelocksLocked() {
4468        Map<String, KernelWakelockStats> m = readKernelWakelockStats();
4469
4470        if (m == null) {
4471            // Not crashing might make board bringup easier.
4472            Slog.w(TAG, "Couldn't get kernel wake lock stats");
4473            return;
4474        }
4475
4476        for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
4477            String name = ent.getKey();
4478            KernelWakelockStats kws = ent.getValue();
4479
4480            SamplingTimer kwlt = mKernelWakelockStats.get(name);
4481            if (kwlt == null) {
4482                kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
4483                        true /* track reported values */);
4484                mKernelWakelockStats.put(name, kwlt);
4485            }
4486            kwlt.updateCurrentReportedCount(kws.mCount);
4487            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
4488            kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
4489        }
4490
4491        if (m.size() != mKernelWakelockStats.size()) {
4492            // Set timers to stale if they didn't appear in /proc/wakelocks this time.
4493            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
4494                SamplingTimer st = ent.getValue();
4495                if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
4496                    st.setStale();
4497                }
4498            }
4499        }
4500    }
4501
4502    public long getAwakeTimeBattery() {
4503        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
4504    }
4505
4506    public long getAwakeTimePlugged() {
4507        return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
4508    }
4509
4510    @Override
4511    public long computeUptime(long curTime, int which) {
4512        switch (which) {
4513            case STATS_SINCE_CHARGED: return mUptime + (curTime-mUptimeStart);
4514            case STATS_LAST: return mLastUptime;
4515            case STATS_CURRENT: return (curTime-mUptimeStart);
4516            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
4517        }
4518        return 0;
4519    }
4520
4521    @Override
4522    public long computeRealtime(long curTime, int which) {
4523        switch (which) {
4524            case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
4525            case STATS_LAST: return mLastRealtime;
4526            case STATS_CURRENT: return (curTime-mRealtimeStart);
4527            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
4528        }
4529        return 0;
4530    }
4531
4532    @Override
4533    public long computeBatteryUptime(long curTime, int which) {
4534        switch (which) {
4535            case STATS_SINCE_CHARGED:
4536                return mBatteryUptime + getBatteryUptime(curTime);
4537            case STATS_LAST:
4538                return mBatteryLastUptime;
4539            case STATS_CURRENT:
4540                return getBatteryUptime(curTime);
4541            case STATS_SINCE_UNPLUGGED:
4542                return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
4543        }
4544        return 0;
4545    }
4546
4547    @Override
4548    public long computeBatteryRealtime(long curTime, int which) {
4549        switch (which) {
4550            case STATS_SINCE_CHARGED:
4551                return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
4552            case STATS_LAST:
4553                return mBatteryLastRealtime;
4554            case STATS_CURRENT:
4555                return getBatteryRealtimeLocked(curTime);
4556            case STATS_SINCE_UNPLUGGED:
4557                return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
4558        }
4559        return 0;
4560    }
4561
4562    long getBatteryUptimeLocked(long curTime) {
4563        long time = mTrackBatteryPastUptime;
4564        if (mOnBatteryInternal) {
4565            time += curTime - mTrackBatteryUptimeStart;
4566        }
4567        return time;
4568    }
4569
4570    long getBatteryUptimeLocked() {
4571        return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
4572    }
4573
4574    @Override
4575    public long getBatteryUptime(long curTime) {
4576        return getBatteryUptimeLocked(curTime);
4577    }
4578
4579    long getBatteryRealtimeLocked(long curTime) {
4580        long time = mTrackBatteryPastRealtime;
4581        if (mOnBatteryInternal) {
4582            time += curTime - mTrackBatteryRealtimeStart;
4583        }
4584        return time;
4585    }
4586
4587    @Override
4588    public long getBatteryRealtime(long curTime) {
4589        return getBatteryRealtimeLocked(curTime);
4590    }
4591
4592    private long getTcpBytes(long current, long[] dataBytes, int which) {
4593        if (which == STATS_LAST) {
4594            return dataBytes[STATS_LAST];
4595        } else {
4596            if (which == STATS_SINCE_UNPLUGGED) {
4597                if (dataBytes[STATS_SINCE_UNPLUGGED] < 0) {
4598                    return dataBytes[STATS_LAST];
4599                } else {
4600                    return current - dataBytes[STATS_SINCE_UNPLUGGED];
4601                }
4602            } else if (which == STATS_SINCE_CHARGED) {
4603                return (current - dataBytes[STATS_CURRENT]) + dataBytes[STATS_SINCE_CHARGED];
4604            }
4605            return current - dataBytes[STATS_CURRENT];
4606        }
4607    }
4608
4609    /** Only STATS_UNPLUGGED works properly */
4610    public long getMobileTcpBytesSent(int which) {
4611        final long mobileTxBytes = getNetworkStatsSummary().getTotal(null, mMobileIfaces).txBytes;
4612        return getTcpBytes(mobileTxBytes, mMobileDataTx, which);
4613    }
4614
4615    /** Only STATS_UNPLUGGED works properly */
4616    public long getMobileTcpBytesReceived(int which) {
4617        final long mobileRxBytes = getNetworkStatsSummary().getTotal(null, mMobileIfaces).rxBytes;
4618        return getTcpBytes(mobileRxBytes, mMobileDataRx, which);
4619    }
4620
4621    /** Only STATS_UNPLUGGED works properly */
4622    public long getTotalTcpBytesSent(int which) {
4623        final long totalTxBytes = getNetworkStatsSummary().getTotal(null).txBytes;
4624        return getTcpBytes(totalTxBytes, mTotalDataTx, which);
4625    }
4626
4627    /** Only STATS_UNPLUGGED works properly */
4628    public long getTotalTcpBytesReceived(int which) {
4629        final long totalRxBytes = getNetworkStatsSummary().getTotal(null).rxBytes;
4630        return getTcpBytes(totalRxBytes, mTotalDataRx, which);
4631    }
4632
4633    @Override
4634    public int getDischargeStartLevel() {
4635        synchronized(this) {
4636            return getDischargeStartLevelLocked();
4637        }
4638    }
4639
4640    public int getDischargeStartLevelLocked() {
4641            return mDischargeUnplugLevel;
4642    }
4643
4644    @Override
4645    public int getDischargeCurrentLevel() {
4646        synchronized(this) {
4647            return getDischargeCurrentLevelLocked();
4648        }
4649    }
4650
4651    public int getDischargeCurrentLevelLocked() {
4652        return mDischargeCurrentLevel;
4653    }
4654
4655    @Override
4656    public int getLowDischargeAmountSinceCharge() {
4657        synchronized(this) {
4658            int val = mLowDischargeAmountSinceCharge;
4659            if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
4660                val += mDischargeUnplugLevel-mDischargeCurrentLevel-1;
4661            }
4662            return val;
4663        }
4664    }
4665
4666    @Override
4667    public int getHighDischargeAmountSinceCharge() {
4668        synchronized(this) {
4669            int val = mHighDischargeAmountSinceCharge;
4670            if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
4671                val += mDischargeUnplugLevel-mDischargeCurrentLevel;
4672            }
4673            return val;
4674        }
4675    }
4676
4677    public int getDischargeAmountScreenOn() {
4678        synchronized(this) {
4679            int val = mDischargeAmountScreenOn;
4680            if (mOnBattery && mScreenOn
4681                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
4682                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
4683            }
4684            return val;
4685        }
4686    }
4687
4688    public int getDischargeAmountScreenOnSinceCharge() {
4689        synchronized(this) {
4690            int val = mDischargeAmountScreenOnSinceCharge;
4691            if (mOnBattery && mScreenOn
4692                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
4693                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
4694            }
4695            return val;
4696        }
4697    }
4698
4699    public int getDischargeAmountScreenOff() {
4700        synchronized(this) {
4701            int val = mDischargeAmountScreenOff;
4702            if (mOnBattery && !mScreenOn
4703                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
4704                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
4705            }
4706            return val;
4707        }
4708    }
4709
4710    public int getDischargeAmountScreenOffSinceCharge() {
4711        synchronized(this) {
4712            int val = mDischargeAmountScreenOffSinceCharge;
4713            if (mOnBattery && !mScreenOn
4714                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
4715                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
4716            }
4717            return val;
4718        }
4719    }
4720
4721    @Override
4722    public int getCpuSpeedSteps() {
4723        return sNumSpeedSteps;
4724    }
4725
4726    /**
4727     * Retrieve the statistics object for a particular uid, creating if needed.
4728     */
4729    public Uid getUidStatsLocked(int uid) {
4730        Uid u = mUidStats.get(uid);
4731        if (u == null) {
4732            u = new Uid(uid);
4733            mUidStats.put(uid, u);
4734        }
4735        return u;
4736    }
4737
4738    /**
4739     * Remove the statistics object for a particular uid.
4740     */
4741    public void removeUidStatsLocked(int uid) {
4742        mUidStats.remove(uid);
4743    }
4744
4745    /**
4746     * Retrieve the statistics object for a particular process, creating
4747     * if needed.
4748     */
4749    public Uid.Proc getProcessStatsLocked(int uid, String name) {
4750        Uid u = getUidStatsLocked(uid);
4751        return u.getProcessStatsLocked(name);
4752    }
4753
4754    /**
4755     * Retrieve the statistics object for a particular process, given
4756     * the name of the process.
4757     * @param name process name
4758     * @return the statistics object for the process
4759     */
4760    public Uid.Proc getProcessStatsLocked(String name, int pid) {
4761        int uid;
4762        if (mUidCache.containsKey(name)) {
4763            uid = mUidCache.get(name);
4764        } else {
4765            uid = Process.getUidForPid(pid);
4766            mUidCache.put(name, uid);
4767        }
4768        Uid u = getUidStatsLocked(uid);
4769        return u.getProcessStatsLocked(name);
4770    }
4771
4772    /**
4773     * Retrieve the statistics object for a particular process, creating
4774     * if needed.
4775     */
4776    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
4777        Uid u = getUidStatsLocked(uid);
4778        return u.getPackageStatsLocked(pkg);
4779    }
4780
4781    /**
4782     * Retrieve the statistics object for a particular service, creating
4783     * if needed.
4784     */
4785    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
4786        Uid u = getUidStatsLocked(uid);
4787        return u.getServiceStatsLocked(pkg, name);
4788    }
4789
4790    /**
4791     * Massage data to distribute any reasonable work down to more specific
4792     * owners.  Must only be called on a dead BatteryStats object!
4793     */
4794    public void distributeWorkLocked(int which) {
4795        // Aggregate all CPU time associated with WIFI.
4796        Uid wifiUid = mUidStats.get(Process.WIFI_UID);
4797        if (wifiUid != null) {
4798            long uSecTime = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
4799            for (Uid.Proc proc : wifiUid.mProcessStats.values()) {
4800                long totalRunningTime = getGlobalWifiRunningTime(uSecTime, which);
4801                for (int i=0; i<mUidStats.size(); i++) {
4802                    Uid uid = mUidStats.valueAt(i);
4803                    if (uid.mUid != Process.WIFI_UID) {
4804                        long uidRunningTime = uid.getWifiRunningTime(uSecTime, which);
4805                        if (uidRunningTime > 0) {
4806                            Uid.Proc uidProc = uid.getProcessStatsLocked("*wifi*");
4807                            long time = proc.getUserTime(which);
4808                            time = (time*uidRunningTime)/totalRunningTime;
4809                            uidProc.mUserTime += time;
4810                            proc.mUserTime -= time;
4811                            time = proc.getSystemTime(which);
4812                            time = (time*uidRunningTime)/totalRunningTime;
4813                            uidProc.mSystemTime += time;
4814                            proc.mSystemTime -= time;
4815                            time = proc.getForegroundTime(which);
4816                            time = (time*uidRunningTime)/totalRunningTime;
4817                            uidProc.mForegroundTime += time;
4818                            proc.mForegroundTime -= time;
4819                            for (int sb=0; sb<proc.mSpeedBins.length; sb++) {
4820                                SamplingCounter sc = proc.mSpeedBins[sb];
4821                                if (sc != null) {
4822                                    time = sc.getCountLocked(which);
4823                                    time = (time*uidRunningTime)/totalRunningTime;
4824                                    SamplingCounter uidSc = uidProc.mSpeedBins[sb];
4825                                    if (uidSc == null) {
4826                                        uidSc = new SamplingCounter(mUnpluggables);
4827                                        uidProc.mSpeedBins[sb] = uidSc;
4828                                    }
4829                                    uidSc.mCount.addAndGet((int)time);
4830                                    sc.mCount.addAndGet((int)-time);
4831                                }
4832                            }
4833                            totalRunningTime -= uidRunningTime;
4834                        }
4835                    }
4836                }
4837            }
4838        }
4839    }
4840
4841    public void shutdownLocked() {
4842        writeSyncLocked();
4843        mShuttingDown = true;
4844    }
4845
4846    Parcel mPendingWrite = null;
4847    final ReentrantLock mWriteLock = new ReentrantLock();
4848
4849    public void writeAsyncLocked() {
4850        writeLocked(false);
4851    }
4852
4853    public void writeSyncLocked() {
4854        writeLocked(true);
4855    }
4856
4857    void writeLocked(boolean sync) {
4858        if (mFile == null) {
4859            Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
4860            return;
4861        }
4862
4863        if (mShuttingDown) {
4864            return;
4865        }
4866
4867        Parcel out = Parcel.obtain();
4868        writeSummaryToParcel(out);
4869        mLastWriteTime = SystemClock.elapsedRealtime();
4870
4871        if (mPendingWrite != null) {
4872            mPendingWrite.recycle();
4873        }
4874        mPendingWrite = out;
4875
4876        if (sync) {
4877            commitPendingDataToDisk();
4878        } else {
4879            Thread thr = new Thread("BatteryStats-Write") {
4880                @Override
4881                public void run() {
4882                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
4883                    commitPendingDataToDisk();
4884                }
4885            };
4886            thr.start();
4887        }
4888    }
4889
4890    public void commitPendingDataToDisk() {
4891        final Parcel next;
4892        synchronized (this) {
4893            next = mPendingWrite;
4894            mPendingWrite = null;
4895            if (next == null) {
4896                return;
4897            }
4898
4899            mWriteLock.lock();
4900        }
4901
4902        try {
4903            FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
4904            stream.write(next.marshall());
4905            stream.flush();
4906            FileUtils.sync(stream);
4907            stream.close();
4908            mFile.commit();
4909        } catch (IOException e) {
4910            Slog.w("BatteryStats", "Error writing battery statistics", e);
4911            mFile.rollback();
4912        } finally {
4913            next.recycle();
4914            mWriteLock.unlock();
4915        }
4916    }
4917
4918    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
4919        int pos = 0;
4920        int avail = stream.available();
4921        byte[] data = new byte[avail];
4922        while (true) {
4923            int amt = stream.read(data, pos, data.length-pos);
4924            //Log.i("foo", "Read " + amt + " bytes at " + pos
4925            //        + " of avail " + data.length);
4926            if (amt <= 0) {
4927                //Log.i("foo", "**** FINISHED READING: pos=" + pos
4928                //        + " len=" + data.length);
4929                return data;
4930            }
4931            pos += amt;
4932            avail = stream.available();
4933            if (avail > data.length-pos) {
4934                byte[] newData = new byte[pos+avail];
4935                System.arraycopy(data, 0, newData, 0, pos);
4936                data = newData;
4937            }
4938        }
4939    }
4940
4941    public void readLocked() {
4942        if (mFile == null) {
4943            Slog.w("BatteryStats", "readLocked: no file associated with this instance");
4944            return;
4945        }
4946
4947        mUidStats.clear();
4948
4949        try {
4950            File file = mFile.chooseForRead();
4951            if (!file.exists()) {
4952                return;
4953            }
4954            FileInputStream stream = new FileInputStream(file);
4955
4956            byte[] raw = readFully(stream);
4957            Parcel in = Parcel.obtain();
4958            in.unmarshall(raw, 0, raw.length);
4959            in.setDataPosition(0);
4960            stream.close();
4961
4962            readSummaryFromParcel(in);
4963        } catch(java.io.IOException e) {
4964            Slog.e("BatteryStats", "Error reading battery statistics", e);
4965        }
4966
4967        long now = SystemClock.elapsedRealtime();
4968        if (USE_OLD_HISTORY) {
4969            addHistoryRecordLocked(now, HistoryItem.CMD_START);
4970        }
4971        addHistoryBufferLocked(now, HistoryItem.CMD_START);
4972    }
4973
4974    public int describeContents() {
4975        return 0;
4976    }
4977
4978    void readHistory(Parcel in, boolean andOldHistory) {
4979        final long historyBaseTime = in.readLong();
4980
4981        mHistoryBuffer.setDataSize(0);
4982        mHistoryBuffer.setDataPosition(0);
4983
4984        int bufSize = in.readInt();
4985        int curPos = in.dataPosition();
4986        if (bufSize >= (MAX_MAX_HISTORY_BUFFER*3)) {
4987            Slog.w(TAG, "File corrupt: history data buffer too large " + bufSize);
4988        } else if ((bufSize&~3) != bufSize) {
4989            Slog.w(TAG, "File corrupt: history data buffer not aligned " + bufSize);
4990        } else {
4991            if (DEBUG_HISTORY) Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
4992                    + " bytes at " + curPos);
4993            mHistoryBuffer.appendFrom(in, curPos, bufSize);
4994            in.setDataPosition(curPos + bufSize);
4995        }
4996
4997        if (andOldHistory) {
4998            readOldHistory(in);
4999        }
5000
5001        if (DEBUG_HISTORY) {
5002            StringBuilder sb = new StringBuilder(128);
5003            sb.append("****************** OLD mHistoryBaseTime: ");
5004            TimeUtils.formatDuration(mHistoryBaseTime, sb);
5005            Slog.i(TAG, sb.toString());
5006        }
5007        mHistoryBaseTime = historyBaseTime;
5008        if (DEBUG_HISTORY) {
5009            StringBuilder sb = new StringBuilder(128);
5010            sb.append("****************** NEW mHistoryBaseTime: ");
5011            TimeUtils.formatDuration(mHistoryBaseTime, sb);
5012            Slog.i(TAG, sb.toString());
5013        }
5014
5015        // We are just arbitrarily going to insert 1 minute from the sample of
5016        // the last run until samples in this run.
5017        if (mHistoryBaseTime > 0) {
5018            long oldnow = SystemClock.elapsedRealtime();
5019            mHistoryBaseTime = (mHistoryBaseTime - oldnow) + 60*1000;
5020            if (DEBUG_HISTORY) {
5021                StringBuilder sb = new StringBuilder(128);
5022                sb.append("****************** ADJUSTED mHistoryBaseTime: ");
5023                TimeUtils.formatDuration(mHistoryBaseTime, sb);
5024                Slog.i(TAG, sb.toString());
5025            }
5026        }
5027    }
5028
5029    void readOldHistory(Parcel in) {
5030        if (!USE_OLD_HISTORY) {
5031            return;
5032        }
5033        mHistory = mHistoryEnd = mHistoryCache = null;
5034        long time;
5035        while (in.dataAvail() > 0 && (time=in.readLong()) >= 0) {
5036            HistoryItem rec = new HistoryItem(time, in);
5037            addHistoryRecordLocked(rec);
5038        }
5039    }
5040
5041    void writeHistory(Parcel out, boolean andOldHistory) {
5042        if (DEBUG_HISTORY) {
5043            StringBuilder sb = new StringBuilder(128);
5044            sb.append("****************** WRITING mHistoryBaseTime: ");
5045            TimeUtils.formatDuration(mHistoryBaseTime, sb);
5046            sb.append(" mLastHistoryTime: ");
5047            TimeUtils.formatDuration(mLastHistoryTime, sb);
5048            Slog.i(TAG, sb.toString());
5049        }
5050        out.writeLong(mHistoryBaseTime + mLastHistoryTime);
5051        out.writeInt(mHistoryBuffer.dataSize());
5052        if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
5053                + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
5054        out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
5055
5056        if (andOldHistory) {
5057            writeOldHistory(out);
5058        }
5059    }
5060
5061    void writeOldHistory(Parcel out) {
5062        if (!USE_OLD_HISTORY) {
5063            return;
5064        }
5065        HistoryItem rec = mHistory;
5066        while (rec != null) {
5067            if (rec.time >= 0) rec.writeToParcel(out, 0);
5068            rec = rec.next;
5069        }
5070        out.writeLong(-1);
5071    }
5072
5073    private void readSummaryFromParcel(Parcel in) {
5074        final int version = in.readInt();
5075        if (version != VERSION) {
5076            Slog.w("BatteryStats", "readFromParcel: version got " + version
5077                + ", expected " + VERSION + "; erasing old stats");
5078            return;
5079        }
5080
5081        readHistory(in, true);
5082
5083        mStartCount = in.readInt();
5084        mBatteryUptime = in.readLong();
5085        mBatteryRealtime = in.readLong();
5086        mUptime = in.readLong();
5087        mRealtime = in.readLong();
5088        mDischargeUnplugLevel = in.readInt();
5089        mDischargeCurrentLevel = in.readInt();
5090        mLowDischargeAmountSinceCharge = in.readInt();
5091        mHighDischargeAmountSinceCharge = in.readInt();
5092        mDischargeAmountScreenOnSinceCharge = in.readInt();
5093        mDischargeAmountScreenOffSinceCharge = in.readInt();
5094
5095        mStartCount++;
5096
5097        mScreenOn = false;
5098        mScreenOnTimer.readSummaryFromParcelLocked(in);
5099        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5100            mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
5101        }
5102        mInputEventCounter.readSummaryFromParcelLocked(in);
5103        mPhoneOn = false;
5104        mPhoneOnTimer.readSummaryFromParcelLocked(in);
5105        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5106            mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
5107        }
5108        mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
5109        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5110            mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
5111        }
5112        mWifiOn = false;
5113        mWifiOnTimer.readSummaryFromParcelLocked(in);
5114        mGlobalWifiRunning = false;
5115        mGlobalWifiRunningTimer.readSummaryFromParcelLocked(in);
5116        mBluetoothOn = false;
5117        mBluetoothOnTimer.readSummaryFromParcelLocked(in);
5118
5119        int NKW = in.readInt();
5120        if (NKW > 10000) {
5121            Slog.w(TAG, "File corrupt: too many kernel wake locks " + NKW);
5122            return;
5123        }
5124        for (int ikw = 0; ikw < NKW; ikw++) {
5125            if (in.readInt() != 0) {
5126                String kwltName = in.readString();
5127                getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
5128            }
5129        }
5130
5131        sNumSpeedSteps = in.readInt();
5132
5133        final int NU = in.readInt();
5134        if (NU > 10000) {
5135            Slog.w(TAG, "File corrupt: too many uids " + NU);
5136            return;
5137        }
5138        for (int iu = 0; iu < NU; iu++) {
5139            int uid = in.readInt();
5140            Uid u = new Uid(uid);
5141            mUidStats.put(uid, u);
5142
5143            u.mWifiRunning = false;
5144            if (in.readInt() != 0) {
5145                u.mWifiRunningTimer.readSummaryFromParcelLocked(in);
5146            }
5147            u.mFullWifiLockOut = false;
5148            if (in.readInt() != 0) {
5149                u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
5150            }
5151            u.mWifiScanStarted = false;
5152            if (in.readInt() != 0) {
5153                u.mWifiScanTimer.readSummaryFromParcelLocked(in);
5154            }
5155            u.mWifiMulticastEnabled = false;
5156            if (in.readInt() != 0) {
5157                u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
5158            }
5159            u.mAudioTurnedOn = false;
5160            if (in.readInt() != 0) {
5161                u.mAudioTurnedOnTimer.readSummaryFromParcelLocked(in);
5162            }
5163            u.mVideoTurnedOn = false;
5164            if (in.readInt() != 0) {
5165                u.mVideoTurnedOnTimer.readSummaryFromParcelLocked(in);
5166            }
5167
5168            if (in.readInt() != 0) {
5169                if (u.mUserActivityCounters == null) {
5170                    u.initUserActivityLocked();
5171                }
5172                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
5173                    u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
5174                }
5175            }
5176
5177            int NW = in.readInt();
5178            if (NW > 100) {
5179                Slog.w(TAG, "File corrupt: too many wake locks " + NW);
5180                return;
5181            }
5182            for (int iw = 0; iw < NW; iw++) {
5183                String wlName = in.readString();
5184                if (in.readInt() != 0) {
5185                    u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
5186                }
5187                if (in.readInt() != 0) {
5188                    u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
5189                }
5190                if (in.readInt() != 0) {
5191                    u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
5192                }
5193            }
5194
5195            int NP = in.readInt();
5196            if (NP > 1000) {
5197                Slog.w(TAG, "File corrupt: too many sensors " + NP);
5198                return;
5199            }
5200            for (int is = 0; is < NP; is++) {
5201                int seNumber = in.readInt();
5202                if (in.readInt() != 0) {
5203                    u.getSensorTimerLocked(seNumber, true)
5204                            .readSummaryFromParcelLocked(in);
5205                }
5206            }
5207
5208            NP = in.readInt();
5209            if (NP > 1000) {
5210                Slog.w(TAG, "File corrupt: too many processes " + NP);
5211                return;
5212            }
5213            for (int ip = 0; ip < NP; ip++) {
5214                String procName = in.readString();
5215                Uid.Proc p = u.getProcessStatsLocked(procName);
5216                p.mUserTime = p.mLoadedUserTime = in.readLong();
5217                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
5218                p.mStarts = p.mLoadedStarts = in.readInt();
5219                int NSB = in.readInt();
5220                if (NSB > 100) {
5221                    Slog.w(TAG, "File corrupt: too many speed bins " + NSB);
5222                    return;
5223                }
5224                p.mSpeedBins = new SamplingCounter[NSB];
5225                for (int i=0; i<NSB; i++) {
5226                    if (in.readInt() != 0) {
5227                        p.mSpeedBins[i] = new SamplingCounter(mUnpluggables);
5228                        p.mSpeedBins[i].readSummaryFromParcelLocked(in);
5229                    }
5230                }
5231                if (!p.readExcessivePowerFromParcelLocked(in)) {
5232                    return;
5233                }
5234            }
5235
5236            NP = in.readInt();
5237            if (NP > 10000) {
5238                Slog.w(TAG, "File corrupt: too many packages " + NP);
5239                return;
5240            }
5241            for (int ip = 0; ip < NP; ip++) {
5242                String pkgName = in.readString();
5243                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
5244                p.mWakeups = p.mLoadedWakeups = in.readInt();
5245                final int NS = in.readInt();
5246                if (NS > 1000) {
5247                    Slog.w(TAG, "File corrupt: too many services " + NS);
5248                    return;
5249                }
5250                for (int is = 0; is < NS; is++) {
5251                    String servName = in.readString();
5252                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
5253                    s.mStartTime = s.mLoadedStartTime = in.readLong();
5254                    s.mStarts = s.mLoadedStarts = in.readInt();
5255                    s.mLaunches = s.mLoadedLaunches = in.readInt();
5256                }
5257            }
5258
5259            u.mLoadedTcpBytesReceived = in.readLong();
5260            u.mLoadedTcpBytesSent = in.readLong();
5261        }
5262    }
5263
5264    /**
5265     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
5266     * disk.  This format does not allow a lossless round-trip.
5267     *
5268     * @param out the Parcel to be written to.
5269     */
5270    public void writeSummaryToParcel(Parcel out) {
5271        // Need to update with current kernel wake lock counts.
5272        updateKernelWakelocksLocked();
5273
5274        final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
5275        final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
5276        final long NOW = getBatteryUptimeLocked(NOW_SYS);
5277        final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
5278
5279        out.writeInt(VERSION);
5280
5281        writeHistory(out, true);
5282
5283        out.writeInt(mStartCount);
5284        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_SINCE_CHARGED));
5285        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
5286        out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
5287        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
5288        out.writeInt(mDischargeUnplugLevel);
5289        out.writeInt(mDischargeCurrentLevel);
5290        out.writeInt(getLowDischargeAmountSinceCharge());
5291        out.writeInt(getHighDischargeAmountSinceCharge());
5292        out.writeInt(getDischargeAmountScreenOnSinceCharge());
5293        out.writeInt(getDischargeAmountScreenOffSinceCharge());
5294
5295        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5296        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5297            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
5298        }
5299        mInputEventCounter.writeSummaryFromParcelLocked(out);
5300        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5301        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5302            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
5303        }
5304        mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5305        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5306            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
5307        }
5308        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5309        mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5310        mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5311
5312        out.writeInt(mKernelWakelockStats.size());
5313        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
5314            Timer kwlt = ent.getValue();
5315            if (kwlt != null) {
5316                out.writeInt(1);
5317                out.writeString(ent.getKey());
5318                ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
5319            } else {
5320                out.writeInt(0);
5321            }
5322        }
5323
5324        out.writeInt(sNumSpeedSteps);
5325        final int NU = mUidStats.size();
5326        out.writeInt(NU);
5327        for (int iu = 0; iu < NU; iu++) {
5328            out.writeInt(mUidStats.keyAt(iu));
5329            Uid u = mUidStats.valueAt(iu);
5330
5331            if (u.mWifiRunningTimer != null) {
5332                out.writeInt(1);
5333                u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5334            } else {
5335                out.writeInt(0);
5336            }
5337            if (u.mFullWifiLockTimer != null) {
5338                out.writeInt(1);
5339                u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5340            } else {
5341                out.writeInt(0);
5342            }
5343            if (u.mWifiScanTimer != null) {
5344                out.writeInt(1);
5345                u.mWifiScanTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5346            } else {
5347                out.writeInt(0);
5348            }
5349            if (u.mWifiMulticastTimer != null) {
5350                out.writeInt(1);
5351                u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5352            } else {
5353                out.writeInt(0);
5354            }
5355            if (u.mAudioTurnedOnTimer != null) {
5356                out.writeInt(1);
5357                u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5358            } else {
5359                out.writeInt(0);
5360            }
5361            if (u.mVideoTurnedOnTimer != null) {
5362                out.writeInt(1);
5363                u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5364            } else {
5365                out.writeInt(0);
5366            }
5367
5368            if (u.mUserActivityCounters == null) {
5369                out.writeInt(0);
5370            } else {
5371                out.writeInt(1);
5372                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
5373                    u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
5374                }
5375            }
5376
5377            int NW = u.mWakelockStats.size();
5378            out.writeInt(NW);
5379            if (NW > 0) {
5380                for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
5381                        : u.mWakelockStats.entrySet()) {
5382                    out.writeString(ent.getKey());
5383                    Uid.Wakelock wl = ent.getValue();
5384                    if (wl.mTimerFull != null) {
5385                        out.writeInt(1);
5386                        wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
5387                    } else {
5388                        out.writeInt(0);
5389                    }
5390                    if (wl.mTimerPartial != null) {
5391                        out.writeInt(1);
5392                        wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
5393                    } else {
5394                        out.writeInt(0);
5395                    }
5396                    if (wl.mTimerWindow != null) {
5397                        out.writeInt(1);
5398                        wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
5399                    } else {
5400                        out.writeInt(0);
5401                    }
5402                }
5403            }
5404
5405            int NSE = u.mSensorStats.size();
5406            out.writeInt(NSE);
5407            if (NSE > 0) {
5408                for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
5409                        : u.mSensorStats.entrySet()) {
5410                    out.writeInt(ent.getKey());
5411                    Uid.Sensor se = ent.getValue();
5412                    if (se.mTimer != null) {
5413                        out.writeInt(1);
5414                        se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5415                    } else {
5416                        out.writeInt(0);
5417                    }
5418                }
5419            }
5420
5421            int NP = u.mProcessStats.size();
5422            out.writeInt(NP);
5423            if (NP > 0) {
5424                for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
5425                    : u.mProcessStats.entrySet()) {
5426                    out.writeString(ent.getKey());
5427                    Uid.Proc ps = ent.getValue();
5428                    out.writeLong(ps.mUserTime);
5429                    out.writeLong(ps.mSystemTime);
5430                    out.writeInt(ps.mStarts);
5431                    final int N = ps.mSpeedBins.length;
5432                    out.writeInt(N);
5433                    for (int i=0; i<N; i++) {
5434                        if (ps.mSpeedBins[i] != null) {
5435                            out.writeInt(1);
5436                            ps.mSpeedBins[i].writeSummaryFromParcelLocked(out);
5437                        } else {
5438                            out.writeInt(0);
5439                        }
5440                    }
5441                    ps.writeExcessivePowerToParcelLocked(out);
5442                }
5443            }
5444
5445            NP = u.mPackageStats.size();
5446            out.writeInt(NP);
5447            if (NP > 0) {
5448                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
5449                    : u.mPackageStats.entrySet()) {
5450                    out.writeString(ent.getKey());
5451                    Uid.Pkg ps = ent.getValue();
5452                    out.writeInt(ps.mWakeups);
5453                    final int NS = ps.mServiceStats.size();
5454                    out.writeInt(NS);
5455                    if (NS > 0) {
5456                        for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
5457                                : ps.mServiceStats.entrySet()) {
5458                            out.writeString(sent.getKey());
5459                            BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
5460                            long time = ss.getStartTimeToNowLocked(NOW);
5461                            out.writeLong(time);
5462                            out.writeInt(ss.mStarts);
5463                            out.writeInt(ss.mLaunches);
5464                        }
5465                    }
5466                }
5467            }
5468
5469            out.writeLong(u.getTcpBytesReceived(STATS_SINCE_CHARGED));
5470            out.writeLong(u.getTcpBytesSent(STATS_SINCE_CHARGED));
5471        }
5472    }
5473
5474    public void readFromParcel(Parcel in) {
5475        readFromParcelLocked(in);
5476    }
5477
5478    void readFromParcelLocked(Parcel in) {
5479        int magic = in.readInt();
5480        if (magic != MAGIC) {
5481            throw new ParcelFormatException("Bad magic number");
5482        }
5483
5484        readHistory(in, false);
5485
5486        mStartCount = in.readInt();
5487        mBatteryUptime = in.readLong();
5488        mBatteryLastUptime = 0;
5489        mBatteryRealtime = in.readLong();
5490        mBatteryLastRealtime = 0;
5491        mScreenOn = false;
5492        mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables, in);
5493        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5494            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i,
5495                    null, mUnpluggables, in);
5496        }
5497        mInputEventCounter = new Counter(mUnpluggables, in);
5498        mPhoneOn = false;
5499        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5500        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5501            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
5502                    null, mUnpluggables, in);
5503        }
5504        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables, in);
5505        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5506            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
5507                    null, mUnpluggables, in);
5508        }
5509        mWifiOn = false;
5510        mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5511        mGlobalWifiRunning = false;
5512        mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5513        mBluetoothOn = false;
5514        mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5515        mUptime = in.readLong();
5516        mUptimeStart = in.readLong();
5517        mLastUptime = 0;
5518        mRealtime = in.readLong();
5519        mRealtimeStart = in.readLong();
5520        mLastRealtime = 0;
5521        mOnBattery = in.readInt() != 0;
5522        mOnBatteryInternal = false; // we are no longer really running.
5523        mTrackBatteryPastUptime = in.readLong();
5524        mTrackBatteryUptimeStart = in.readLong();
5525        mTrackBatteryPastRealtime = in.readLong();
5526        mTrackBatteryRealtimeStart = in.readLong();
5527        mUnpluggedBatteryUptime = in.readLong();
5528        mUnpluggedBatteryRealtime = in.readLong();
5529        mDischargeUnplugLevel = in.readInt();
5530        mDischargeCurrentLevel = in.readInt();
5531        mLowDischargeAmountSinceCharge = in.readInt();
5532        mHighDischargeAmountSinceCharge = in.readInt();
5533        mDischargeAmountScreenOn = in.readInt();
5534        mDischargeAmountScreenOnSinceCharge = in.readInt();
5535        mDischargeAmountScreenOff = in.readInt();
5536        mDischargeAmountScreenOffSinceCharge = in.readInt();
5537        mLastWriteTime = in.readLong();
5538
5539        mMobileDataRx[STATS_LAST] = in.readLong();
5540        mMobileDataRx[STATS_SINCE_UNPLUGGED] = -1;
5541        mMobileDataTx[STATS_LAST] = in.readLong();
5542        mMobileDataTx[STATS_SINCE_UNPLUGGED] = -1;
5543        mTotalDataRx[STATS_LAST] = in.readLong();
5544        mTotalDataRx[STATS_SINCE_UNPLUGGED] = -1;
5545        mTotalDataTx[STATS_LAST] = in.readLong();
5546        mTotalDataTx[STATS_SINCE_UNPLUGGED] = -1;
5547
5548        mRadioDataUptime = in.readLong();
5549        mRadioDataStart = -1;
5550
5551        mBluetoothPingCount = in.readInt();
5552        mBluetoothPingStart = -1;
5553
5554        mKernelWakelockStats.clear();
5555        int NKW = in.readInt();
5556        for (int ikw = 0; ikw < NKW; ikw++) {
5557            if (in.readInt() != 0) {
5558                String wakelockName = in.readString();
5559                in.readInt(); // Extra 0/1 written by Timer.writeTimerToParcel
5560                SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
5561                mKernelWakelockStats.put(wakelockName, kwlt);
5562            }
5563        }
5564
5565        mPartialTimers.clear();
5566        mFullTimers.clear();
5567        mWindowTimers.clear();
5568        mWifiRunningTimers.clear();
5569        mFullWifiLockTimers.clear();
5570        mWifiScanTimers.clear();
5571        mWifiMulticastTimers.clear();
5572
5573        sNumSpeedSteps = in.readInt();
5574
5575        int numUids = in.readInt();
5576        mUidStats.clear();
5577        for (int i = 0; i < numUids; i++) {
5578            int uid = in.readInt();
5579            Uid u = new Uid(uid);
5580            u.readFromParcelLocked(mUnpluggables, in);
5581            mUidStats.append(uid, u);
5582        }
5583    }
5584
5585    public void writeToParcel(Parcel out, int flags) {
5586        writeToParcelLocked(out, true, flags);
5587    }
5588
5589    public void writeToParcelWithoutUids(Parcel out, int flags) {
5590        writeToParcelLocked(out, false, flags);
5591    }
5592
5593    @SuppressWarnings("unused")
5594    void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
5595        // Need to update with current kernel wake lock counts.
5596        updateKernelWakelocksLocked();
5597
5598        final long uSecUptime = SystemClock.uptimeMillis() * 1000;
5599        final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
5600        final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
5601        final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
5602
5603        out.writeInt(MAGIC);
5604
5605        writeHistory(out, false);
5606
5607        out.writeInt(mStartCount);
5608        out.writeLong(mBatteryUptime);
5609        out.writeLong(mBatteryRealtime);
5610        mScreenOnTimer.writeToParcel(out, batteryRealtime);
5611        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5612            mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
5613        }
5614        mInputEventCounter.writeToParcel(out);
5615        mPhoneOnTimer.writeToParcel(out, batteryRealtime);
5616        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5617            mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
5618        }
5619        mPhoneSignalScanningTimer.writeToParcel(out, batteryRealtime);
5620        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5621            mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
5622        }
5623        mWifiOnTimer.writeToParcel(out, batteryRealtime);
5624        mGlobalWifiRunningTimer.writeToParcel(out, batteryRealtime);
5625        mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
5626        out.writeLong(mUptime);
5627        out.writeLong(mUptimeStart);
5628        out.writeLong(mRealtime);
5629        out.writeLong(mRealtimeStart);
5630        out.writeInt(mOnBattery ? 1 : 0);
5631        out.writeLong(batteryUptime);
5632        out.writeLong(mTrackBatteryUptimeStart);
5633        out.writeLong(batteryRealtime);
5634        out.writeLong(mTrackBatteryRealtimeStart);
5635        out.writeLong(mUnpluggedBatteryUptime);
5636        out.writeLong(mUnpluggedBatteryRealtime);
5637        out.writeInt(mDischargeUnplugLevel);
5638        out.writeInt(mDischargeCurrentLevel);
5639        out.writeInt(mLowDischargeAmountSinceCharge);
5640        out.writeInt(mHighDischargeAmountSinceCharge);
5641        out.writeInt(mDischargeAmountScreenOn);
5642        out.writeInt(mDischargeAmountScreenOnSinceCharge);
5643        out.writeInt(mDischargeAmountScreenOff);
5644        out.writeInt(mDischargeAmountScreenOffSinceCharge);
5645        out.writeLong(mLastWriteTime);
5646
5647        out.writeLong(getMobileTcpBytesReceived(STATS_SINCE_UNPLUGGED));
5648        out.writeLong(getMobileTcpBytesSent(STATS_SINCE_UNPLUGGED));
5649        out.writeLong(getTotalTcpBytesReceived(STATS_SINCE_UNPLUGGED));
5650        out.writeLong(getTotalTcpBytesSent(STATS_SINCE_UNPLUGGED));
5651
5652        // Write radio uptime for data
5653        out.writeLong(getRadioDataUptime());
5654
5655        out.writeInt(getBluetoothPingCount());
5656
5657        if (inclUids) {
5658            out.writeInt(mKernelWakelockStats.size());
5659            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
5660                SamplingTimer kwlt = ent.getValue();
5661                if (kwlt != null) {
5662                    out.writeInt(1);
5663                    out.writeString(ent.getKey());
5664                    Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
5665                } else {
5666                    out.writeInt(0);
5667                }
5668            }
5669        } else {
5670            out.writeInt(0);
5671        }
5672
5673        out.writeInt(sNumSpeedSteps);
5674
5675        if (inclUids) {
5676            int size = mUidStats.size();
5677            out.writeInt(size);
5678            for (int i = 0; i < size; i++) {
5679                out.writeInt(mUidStats.keyAt(i));
5680                Uid uid = mUidStats.valueAt(i);
5681
5682                uid.writeToParcelLocked(out, batteryRealtime);
5683            }
5684        } else {
5685            out.writeInt(0);
5686        }
5687    }
5688
5689    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
5690        new Parcelable.Creator<BatteryStatsImpl>() {
5691        public BatteryStatsImpl createFromParcel(Parcel in) {
5692            return new BatteryStatsImpl(in);
5693        }
5694
5695        public BatteryStatsImpl[] newArray(int size) {
5696            return new BatteryStatsImpl[size];
5697        }
5698    };
5699
5700    public void prepareForDumpLocked() {
5701        // Need to retrieve current kernel wake lock stats before printing.
5702        updateKernelWakelocksLocked();
5703    }
5704
5705    public void dumpLocked(PrintWriter pw) {
5706        if (DEBUG) {
5707            Printer pr = new PrintWriterPrinter(pw);
5708            pr.println("*** Screen timer:");
5709            mScreenOnTimer.logState(pr, "  ");
5710            for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5711                pr.println("*** Screen brightness #" + i + ":");
5712                mScreenBrightnessTimer[i].logState(pr, "  ");
5713            }
5714            pr.println("*** Input event counter:");
5715            mInputEventCounter.logState(pr, "  ");
5716            pr.println("*** Phone timer:");
5717            mPhoneOnTimer.logState(pr, "  ");
5718            for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5719                pr.println("*** Signal strength #" + i + ":");
5720                mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
5721            }
5722            pr.println("*** Signal scanning :");
5723            mPhoneSignalScanningTimer.logState(pr, "  ");
5724            for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5725                pr.println("*** Data connection type #" + i + ":");
5726                mPhoneDataConnectionsTimer[i].logState(pr, "  ");
5727            }
5728            pr.println("*** Wifi timer:");
5729            mWifiOnTimer.logState(pr, "  ");
5730            pr.println("*** WifiRunning timer:");
5731            mGlobalWifiRunningTimer.logState(pr, "  ");
5732            pr.println("*** Bluetooth timer:");
5733            mBluetoothOnTimer.logState(pr, "  ");
5734            pr.println("*** Mobile ifaces:");
5735            pr.println(mMobileIfaces.toString());
5736        }
5737        super.dumpLocked(pw);
5738    }
5739
5740    private NetworkStats mNetworkSummaryCache;
5741    private NetworkStats mNetworkDetailCache;
5742
5743    private NetworkStats getNetworkStatsSummary() {
5744        // NOTE: calls from BatteryStatsService already hold this lock
5745        synchronized (this) {
5746            if (mNetworkSummaryCache == null
5747                    || mNetworkSummaryCache.getElapsedRealtimeAge() > SECOND_IN_MILLIS) {
5748                mNetworkSummaryCache = null;
5749
5750                if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
5751                    try {
5752                        mNetworkSummaryCache = mNetworkStatsFactory.readNetworkStatsSummaryDev();
5753                    } catch (IllegalStateException e) {
5754                        Log.wtf(TAG, "problem reading network stats", e);
5755                    }
5756                }
5757
5758                if (mNetworkSummaryCache == null) {
5759                    mNetworkSummaryCache = new NetworkStats(SystemClock.elapsedRealtime(), 0);
5760                }
5761            }
5762            return mNetworkSummaryCache;
5763        }
5764    }
5765
5766    private NetworkStats getNetworkStatsDetailGroupedByUid() {
5767        // NOTE: calls from BatteryStatsService already hold this lock
5768        synchronized (this) {
5769            if (mNetworkDetailCache == null
5770                    || mNetworkDetailCache.getElapsedRealtimeAge() > SECOND_IN_MILLIS) {
5771                mNetworkDetailCache = null;
5772
5773                if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
5774                    try {
5775                        mNetworkDetailCache = mNetworkStatsFactory
5776                                .readNetworkStatsDetail().groupedByUid();
5777                    } catch (IllegalStateException e) {
5778                        Log.wtf(TAG, "problem reading network stats", e);
5779                    }
5780                }
5781
5782                if (mNetworkDetailCache == null) {
5783                    mNetworkDetailCache = new NetworkStats(SystemClock.elapsedRealtime(), 0);
5784                }
5785            }
5786            return mNetworkDetailCache;
5787        }
5788    }
5789}
5790