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