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