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