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