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