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