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