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