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