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