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