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