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