BatteryStatsImpl.java revision 904a857d5a319e32d1df065b38e3191324b35b0f
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                default:
2176                    bin = DATA_CONNECTION_OTHER;
2177                    break;
2178            }
2179        }
2180        if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
2181        if (mPhoneDataConnectionType != bin) {
2182            mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
2183                    | (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
2184            if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
2185                    + Integer.toHexString(mHistoryCur.states));
2186            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2187            if (mPhoneDataConnectionType >= 0) {
2188                mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this);
2189            }
2190            mPhoneDataConnectionType = bin;
2191            mPhoneDataConnectionsTimer[bin].startRunningLocked(this);
2192        }
2193    }
2194
2195    public void noteWifiOnLocked() {
2196        if (!mWifiOn) {
2197            mHistoryCur.states |= HistoryItem.STATE_WIFI_ON_FLAG;
2198            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
2199                    + Integer.toHexString(mHistoryCur.states));
2200            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2201            mWifiOn = true;
2202            mWifiOnTimer.startRunningLocked(this);
2203        }
2204    }
2205
2206    public void noteWifiOffLocked() {
2207        if (mWifiOn) {
2208            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_ON_FLAG;
2209            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
2210                    + Integer.toHexString(mHistoryCur.states));
2211            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2212            mWifiOn = false;
2213            mWifiOnTimer.stopRunningLocked(this);
2214        }
2215        if (mWifiOnUid >= 0) {
2216            getUidStatsLocked(mWifiOnUid).noteWifiStoppedLocked();
2217            mWifiOnUid = -1;
2218        }
2219    }
2220
2221    public void noteAudioOnLocked(int uid) {
2222        if (!mAudioOn) {
2223            mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
2224            if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
2225                    + Integer.toHexString(mHistoryCur.states));
2226            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2227            mAudioOn = true;
2228            mAudioOnTimer.startRunningLocked(this);
2229        }
2230        getUidStatsLocked(uid).noteAudioTurnedOnLocked();
2231    }
2232
2233    public void noteAudioOffLocked(int uid) {
2234        if (mAudioOn) {
2235            mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
2236            if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
2237                    + Integer.toHexString(mHistoryCur.states));
2238            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2239            mAudioOn = false;
2240            mAudioOnTimer.stopRunningLocked(this);
2241        }
2242        getUidStatsLocked(uid).noteAudioTurnedOffLocked();
2243    }
2244
2245    public void noteVideoOnLocked(int uid) {
2246        if (!mVideoOn) {
2247            mHistoryCur.states |= HistoryItem.STATE_VIDEO_ON_FLAG;
2248            if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
2249                    + Integer.toHexString(mHistoryCur.states));
2250            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2251            mVideoOn = true;
2252            mVideoOnTimer.startRunningLocked(this);
2253        }
2254        getUidStatsLocked(uid).noteVideoTurnedOnLocked();
2255    }
2256
2257    public void noteVideoOffLocked(int uid) {
2258        if (mVideoOn) {
2259            mHistoryCur.states &= ~HistoryItem.STATE_VIDEO_ON_FLAG;
2260            if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
2261                    + Integer.toHexString(mHistoryCur.states));
2262            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2263            mVideoOn = false;
2264            mVideoOnTimer.stopRunningLocked(this);
2265        }
2266        getUidStatsLocked(uid).noteVideoTurnedOffLocked();
2267    }
2268
2269    public void noteActivityResumedLocked(int uid) {
2270        getUidStatsLocked(uid).noteActivityResumedLocked();
2271    }
2272
2273    public void noteActivityPausedLocked(int uid) {
2274        getUidStatsLocked(uid).noteActivityPausedLocked();
2275    }
2276
2277    public void noteVibratorOnLocked(int uid, long durationMillis) {
2278        getUidStatsLocked(uid).noteVibratorOnLocked(durationMillis);
2279    }
2280
2281    public void noteVibratorOffLocked(int uid) {
2282        getUidStatsLocked(uid).noteVibratorOffLocked();
2283    }
2284
2285    public void noteWifiRunningLocked(WorkSource ws) {
2286        if (!mGlobalWifiRunning) {
2287            mHistoryCur.states |= HistoryItem.STATE_WIFI_RUNNING_FLAG;
2288            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
2289                    + Integer.toHexString(mHistoryCur.states));
2290            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2291            mGlobalWifiRunning = true;
2292            mGlobalWifiRunningTimer.startRunningLocked(this);
2293            int N = ws.size();
2294            for (int i=0; i<N; i++) {
2295                getUidStatsLocked(ws.get(i)).noteWifiRunningLocked();
2296            }
2297        } else {
2298            Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
2299        }
2300    }
2301
2302    public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
2303        if (mGlobalWifiRunning) {
2304            int N = oldWs.size();
2305            for (int i=0; i<N; i++) {
2306                getUidStatsLocked(oldWs.get(i)).noteWifiStoppedLocked();
2307            }
2308            N = newWs.size();
2309            for (int i=0; i<N; i++) {
2310                getUidStatsLocked(newWs.get(i)).noteWifiRunningLocked();
2311            }
2312        } else {
2313            Log.w(TAG, "noteWifiRunningChangedLocked -- called while WIFI not running");
2314        }
2315    }
2316
2317    public void noteWifiStoppedLocked(WorkSource ws) {
2318        if (mGlobalWifiRunning) {
2319            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RUNNING_FLAG;
2320            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
2321                    + Integer.toHexString(mHistoryCur.states));
2322            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2323            mGlobalWifiRunning = false;
2324            mGlobalWifiRunningTimer.stopRunningLocked(this);
2325            int N = ws.size();
2326            for (int i=0; i<N; i++) {
2327                getUidStatsLocked(ws.get(i)).noteWifiStoppedLocked();
2328            }
2329        } else {
2330            Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
2331        }
2332    }
2333
2334    public void noteBluetoothOnLocked() {
2335        if (!mBluetoothOn) {
2336            mHistoryCur.states |= HistoryItem.STATE_BLUETOOTH_ON_FLAG;
2337            if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth on to: "
2338                    + Integer.toHexString(mHistoryCur.states));
2339            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2340            mBluetoothOn = true;
2341            mBluetoothOnTimer.startRunningLocked(this);
2342        }
2343    }
2344
2345    public void noteBluetoothOffLocked() {
2346        if (mBluetoothOn) {
2347            mHistoryCur.states &= ~HistoryItem.STATE_BLUETOOTH_ON_FLAG;
2348            if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth off to: "
2349                    + Integer.toHexString(mHistoryCur.states));
2350            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2351            mBluetoothOn = false;
2352            mBluetoothOnTimer.stopRunningLocked(this);
2353        }
2354    }
2355
2356    int mWifiFullLockNesting = 0;
2357
2358    public void noteFullWifiLockAcquiredLocked(int uid) {
2359        if (mWifiFullLockNesting == 0) {
2360            mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
2361            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
2362                    + Integer.toHexString(mHistoryCur.states));
2363            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2364        }
2365        mWifiFullLockNesting++;
2366        getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
2367    }
2368
2369    public void noteFullWifiLockReleasedLocked(int uid) {
2370        mWifiFullLockNesting--;
2371        if (mWifiFullLockNesting == 0) {
2372            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
2373            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
2374                    + Integer.toHexString(mHistoryCur.states));
2375            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2376        }
2377        getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
2378    }
2379
2380    int mWifiScanNesting = 0;
2381
2382    public void noteWifiScanStartedLocked(int uid) {
2383        if (mWifiScanNesting == 0) {
2384            mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG;
2385            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: "
2386                    + Integer.toHexString(mHistoryCur.states));
2387            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2388        }
2389        mWifiScanNesting++;
2390        getUidStatsLocked(uid).noteWifiScanStartedLocked();
2391    }
2392
2393    public void noteWifiScanStoppedLocked(int uid) {
2394        mWifiScanNesting--;
2395        if (mWifiScanNesting == 0) {
2396            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG;
2397            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan stopped for: "
2398                    + Integer.toHexString(mHistoryCur.states));
2399            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2400        }
2401        getUidStatsLocked(uid).noteWifiScanStoppedLocked();
2402    }
2403
2404    int mWifiMulticastNesting = 0;
2405
2406    public void noteWifiMulticastEnabledLocked(int uid) {
2407        if (mWifiMulticastNesting == 0) {
2408            mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
2409            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
2410                    + Integer.toHexString(mHistoryCur.states));
2411            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2412        }
2413        mWifiMulticastNesting++;
2414        getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
2415    }
2416
2417    public void noteWifiMulticastDisabledLocked(int uid) {
2418        mWifiMulticastNesting--;
2419        if (mWifiMulticastNesting == 0) {
2420            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
2421            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
2422                    + Integer.toHexString(mHistoryCur.states));
2423            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2424        }
2425        getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
2426    }
2427
2428    public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
2429        int N = ws.size();
2430        for (int i=0; i<N; i++) {
2431            noteFullWifiLockAcquiredLocked(ws.get(i));
2432        }
2433    }
2434
2435    public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
2436        int N = ws.size();
2437        for (int i=0; i<N; i++) {
2438            noteFullWifiLockReleasedLocked(ws.get(i));
2439        }
2440    }
2441
2442    public void noteWifiScanStartedFromSourceLocked(WorkSource ws) {
2443        int N = ws.size();
2444        for (int i=0; i<N; i++) {
2445            noteWifiScanStartedLocked(ws.get(i));
2446        }
2447    }
2448
2449    public void noteWifiScanStoppedFromSourceLocked(WorkSource ws) {
2450        int N = ws.size();
2451        for (int i=0; i<N; i++) {
2452            noteWifiScanStoppedLocked(ws.get(i));
2453        }
2454    }
2455
2456    public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
2457        int N = ws.size();
2458        for (int i=0; i<N; i++) {
2459            noteWifiMulticastEnabledLocked(ws.get(i));
2460        }
2461    }
2462
2463    public void noteWifiMulticastDisabledFromSourceLocked(WorkSource ws) {
2464        int N = ws.size();
2465        for (int i=0; i<N; i++) {
2466            noteWifiMulticastDisabledLocked(ws.get(i));
2467        }
2468    }
2469
2470    public void noteNetworkInterfaceTypeLocked(String iface, int networkType) {
2471        if (ConnectivityManager.isNetworkTypeMobile(networkType)) {
2472            mMobileIfaces.add(iface);
2473        } else {
2474            mMobileIfaces.remove(iface);
2475        }
2476        if (ConnectivityManager.isNetworkTypeWifi(networkType)) {
2477            mWifiIfaces.add(iface);
2478        } else {
2479            mWifiIfaces.remove(iface);
2480        }
2481    }
2482
2483    public void noteNetworkStatsEnabledLocked() {
2484        // During device boot, qtaguid isn't enabled until after the inital
2485        // loading of battery stats. Now that they're enabled, take our initial
2486        // snapshot for future delta calculation.
2487        updateNetworkActivityLocked();
2488    }
2489
2490    @Override public long getScreenOnTime(long batteryRealtime, int which) {
2491        return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
2492    }
2493
2494    @Override public long getScreenBrightnessTime(int brightnessBin,
2495            long batteryRealtime, int which) {
2496        return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
2497                batteryRealtime, which);
2498    }
2499
2500    @Override public int getInputEventCount(int which) {
2501        return mInputEventCounter.getCountLocked(which);
2502    }
2503
2504    @Override public long getPhoneOnTime(long batteryRealtime, int which) {
2505        return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
2506    }
2507
2508    @Override public long getPhoneSignalStrengthTime(int strengthBin,
2509            long batteryRealtime, int which) {
2510        return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
2511                batteryRealtime, which);
2512    }
2513
2514    @Override public long getPhoneSignalScanningTime(
2515            long batteryRealtime, int which) {
2516        return mPhoneSignalScanningTimer.getTotalTimeLocked(
2517                batteryRealtime, which);
2518    }
2519
2520    @Override public int getPhoneSignalStrengthCount(int strengthBin, int which) {
2521        return mPhoneSignalStrengthsTimer[strengthBin].getCountLocked(which);
2522    }
2523
2524    @Override public long getPhoneDataConnectionTime(int dataType,
2525            long batteryRealtime, int which) {
2526        return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
2527                batteryRealtime, which);
2528    }
2529
2530    @Override public int getPhoneDataConnectionCount(int dataType, int which) {
2531        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
2532    }
2533
2534    @Override public long getWifiOnTime(long batteryRealtime, int which) {
2535        return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
2536    }
2537
2538    @Override public long getGlobalWifiRunningTime(long batteryRealtime, int which) {
2539        return mGlobalWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
2540    }
2541
2542    @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
2543        return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
2544    }
2545
2546    @Override
2547    public long getNetworkActivityCount(int type, int which) {
2548        if (type >= 0 && type < mNetworkActivityCounters.length) {
2549            return mNetworkActivityCounters[type].getCountLocked(which);
2550        } else {
2551            return 0;
2552        }
2553    }
2554
2555    @Override public boolean getIsOnBattery() {
2556        return mOnBattery;
2557    }
2558
2559    @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
2560        return mUidStats;
2561    }
2562
2563    /**
2564     * The statistics associated with a particular uid.
2565     */
2566    public final class Uid extends BatteryStats.Uid {
2567
2568        final int mUid;
2569
2570        boolean mWifiRunning;
2571        StopwatchTimer mWifiRunningTimer;
2572
2573        boolean mFullWifiLockOut;
2574        StopwatchTimer mFullWifiLockTimer;
2575
2576        boolean mWifiScanStarted;
2577        StopwatchTimer mWifiScanTimer;
2578
2579        boolean mWifiMulticastEnabled;
2580        StopwatchTimer mWifiMulticastTimer;
2581
2582        boolean mAudioTurnedOn;
2583        StopwatchTimer mAudioTurnedOnTimer;
2584
2585        boolean mVideoTurnedOn;
2586        StopwatchTimer mVideoTurnedOnTimer;
2587
2588        StopwatchTimer mForegroundActivityTimer;
2589
2590        BatchTimer mVibratorOnTimer;
2591
2592        Counter[] mUserActivityCounters;
2593
2594        LongSamplingCounter[] mNetworkActivityCounters;
2595
2596        /**
2597         * The statistics we have collected for this uid's wake locks.
2598         */
2599        final HashMap<String, Wakelock> mWakelockStats = new HashMap<String, Wakelock>();
2600
2601        /**
2602         * The statistics we have collected for this uid's sensor activations.
2603         */
2604        final HashMap<Integer, Sensor> mSensorStats = new HashMap<Integer, Sensor>();
2605
2606        /**
2607         * The statistics we have collected for this uid's processes.
2608         */
2609        final HashMap<String, Proc> mProcessStats = new HashMap<String, Proc>();
2610
2611        /**
2612         * The statistics we have collected for this uid's processes.
2613         */
2614        final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
2615
2616        /**
2617         * The transient wake stats we have collected for this uid's pids.
2618         */
2619        final SparseArray<Pid> mPids = new SparseArray<Pid>();
2620
2621        public Uid(int uid) {
2622            mUid = uid;
2623            mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
2624                    mWifiRunningTimers, mUnpluggables);
2625            mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
2626                    mFullWifiLockTimers, mUnpluggables);
2627            mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
2628                    mWifiScanTimers, mUnpluggables);
2629            mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
2630                    mWifiMulticastTimers, mUnpluggables);
2631        }
2632
2633        @Override
2634        public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
2635            return mWakelockStats;
2636        }
2637
2638        @Override
2639        public Map<Integer, ? extends BatteryStats.Uid.Sensor> getSensorStats() {
2640            return mSensorStats;
2641        }
2642
2643        @Override
2644        public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
2645            return mProcessStats;
2646        }
2647
2648        @Override
2649        public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
2650            return mPackageStats;
2651        }
2652
2653        @Override
2654        public int getUid() {
2655            return mUid;
2656        }
2657
2658        @Override
2659        public void noteWifiRunningLocked() {
2660            if (!mWifiRunning) {
2661                mWifiRunning = true;
2662                if (mWifiRunningTimer == null) {
2663                    mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
2664                            mWifiRunningTimers, mUnpluggables);
2665                }
2666                mWifiRunningTimer.startRunningLocked(BatteryStatsImpl.this);
2667            }
2668        }
2669
2670        @Override
2671        public void noteWifiStoppedLocked() {
2672            if (mWifiRunning) {
2673                mWifiRunning = false;
2674                mWifiRunningTimer.stopRunningLocked(BatteryStatsImpl.this);
2675            }
2676        }
2677
2678        @Override
2679        public void noteFullWifiLockAcquiredLocked() {
2680            if (!mFullWifiLockOut) {
2681                mFullWifiLockOut = true;
2682                if (mFullWifiLockTimer == null) {
2683                    mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
2684                            mFullWifiLockTimers, mUnpluggables);
2685                }
2686                mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
2687            }
2688        }
2689
2690        @Override
2691        public void noteFullWifiLockReleasedLocked() {
2692            if (mFullWifiLockOut) {
2693                mFullWifiLockOut = false;
2694                mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
2695            }
2696        }
2697
2698        @Override
2699        public void noteWifiScanStartedLocked() {
2700            if (!mWifiScanStarted) {
2701                mWifiScanStarted = true;
2702                if (mWifiScanTimer == null) {
2703                    mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
2704                            mWifiScanTimers, mUnpluggables);
2705                }
2706                mWifiScanTimer.startRunningLocked(BatteryStatsImpl.this);
2707            }
2708        }
2709
2710        @Override
2711        public void noteWifiScanStoppedLocked() {
2712            if (mWifiScanStarted) {
2713                mWifiScanStarted = false;
2714                mWifiScanTimer.stopRunningLocked(BatteryStatsImpl.this);
2715            }
2716        }
2717
2718        @Override
2719        public void noteWifiMulticastEnabledLocked() {
2720            if (!mWifiMulticastEnabled) {
2721                mWifiMulticastEnabled = true;
2722                if (mWifiMulticastTimer == null) {
2723                    mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
2724                            mWifiMulticastTimers, mUnpluggables);
2725                }
2726                mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
2727            }
2728        }
2729
2730        @Override
2731        public void noteWifiMulticastDisabledLocked() {
2732            if (mWifiMulticastEnabled) {
2733                mWifiMulticastEnabled = false;
2734                mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
2735            }
2736        }
2737
2738        public StopwatchTimer createAudioTurnedOnTimerLocked() {
2739            if (mAudioTurnedOnTimer == null) {
2740                mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
2741                        null, mUnpluggables);
2742            }
2743            return mAudioTurnedOnTimer;
2744        }
2745
2746        @Override
2747        public void noteAudioTurnedOnLocked() {
2748            if (!mAudioTurnedOn) {
2749                mAudioTurnedOn = true;
2750                createAudioTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this);
2751            }
2752        }
2753
2754        @Override
2755        public void noteAudioTurnedOffLocked() {
2756            if (mAudioTurnedOn) {
2757                mAudioTurnedOn = false;
2758                if (mAudioTurnedOnTimer != null) {
2759                    mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
2760                }
2761            }
2762        }
2763
2764        public StopwatchTimer createVideoTurnedOnTimerLocked() {
2765            if (mVideoTurnedOnTimer == null) {
2766                mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
2767                        null, mUnpluggables);
2768            }
2769            return mVideoTurnedOnTimer;
2770        }
2771
2772        @Override
2773        public void noteVideoTurnedOnLocked() {
2774            if (!mVideoTurnedOn) {
2775                mVideoTurnedOn = true;
2776                createVideoTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this);
2777            }
2778        }
2779
2780        @Override
2781        public void noteVideoTurnedOffLocked() {
2782            if (mVideoTurnedOn) {
2783                mVideoTurnedOn = false;
2784                if (mVideoTurnedOnTimer != null) {
2785                    mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
2786                }
2787            }
2788        }
2789
2790        public StopwatchTimer createForegroundActivityTimerLocked() {
2791            if (mForegroundActivityTimer == null) {
2792                mForegroundActivityTimer = new StopwatchTimer(
2793                        Uid.this, FOREGROUND_ACTIVITY, null, mUnpluggables);
2794            }
2795            return mForegroundActivityTimer;
2796        }
2797
2798        @Override
2799        public void noteActivityResumedLocked() {
2800            // We always start, since we want multiple foreground PIDs to nest
2801            createForegroundActivityTimerLocked().startRunningLocked(BatteryStatsImpl.this);
2802        }
2803
2804        @Override
2805        public void noteActivityPausedLocked() {
2806            if (mForegroundActivityTimer != null) {
2807                mForegroundActivityTimer.stopRunningLocked(BatteryStatsImpl.this);
2808            }
2809        }
2810
2811        public BatchTimer createVibratorOnTimerLocked() {
2812            if (mVibratorOnTimer == null) {
2813                mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON,
2814                        mUnpluggables, BatteryStatsImpl.this.mOnBatteryInternal);
2815            }
2816            return mVibratorOnTimer;
2817        }
2818
2819        public void noteVibratorOnLocked(long durationMillis) {
2820            createVibratorOnTimerLocked().addDuration(BatteryStatsImpl.this, durationMillis);
2821        }
2822
2823        public void noteVibratorOffLocked() {
2824            if (mVibratorOnTimer != null) {
2825                mVibratorOnTimer.abortLastDuration(BatteryStatsImpl.this);
2826            }
2827        }
2828
2829        @Override
2830        public long getWifiRunningTime(long batteryRealtime, int which) {
2831            if (mWifiRunningTimer == null) {
2832                return 0;
2833            }
2834            return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
2835        }
2836
2837        @Override
2838        public long getFullWifiLockTime(long batteryRealtime, int which) {
2839            if (mFullWifiLockTimer == null) {
2840                return 0;
2841            }
2842            return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
2843        }
2844
2845        @Override
2846        public long getWifiScanTime(long batteryRealtime, int which) {
2847            if (mWifiScanTimer == null) {
2848                return 0;
2849            }
2850            return mWifiScanTimer.getTotalTimeLocked(batteryRealtime, which);
2851        }
2852
2853        @Override
2854        public long getWifiMulticastTime(long batteryRealtime, int which) {
2855            if (mWifiMulticastTimer == null) {
2856                return 0;
2857            }
2858            return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime,
2859                                                          which);
2860        }
2861
2862        @Override
2863        public long getAudioTurnedOnTime(long batteryRealtime, int which) {
2864            if (mAudioTurnedOnTimer == null) {
2865                return 0;
2866            }
2867            return mAudioTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
2868        }
2869
2870        @Override
2871        public long getVideoTurnedOnTime(long batteryRealtime, int which) {
2872            if (mVideoTurnedOnTimer == null) {
2873                return 0;
2874            }
2875            return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
2876        }
2877
2878        @Override
2879        public Timer getForegroundActivityTimer() {
2880            return mForegroundActivityTimer;
2881        }
2882
2883        @Override
2884        public Timer getVibratorOnTimer() {
2885            return mVibratorOnTimer;
2886        }
2887
2888        @Override
2889        public void noteUserActivityLocked(int type) {
2890            if (mUserActivityCounters == null) {
2891                initUserActivityLocked();
2892            }
2893            if (type >= 0 && type < NUM_USER_ACTIVITY_TYPES) {
2894                mUserActivityCounters[type].stepAtomic();
2895            } else {
2896                Slog.w(TAG, "Unknown user activity type " + type + " was specified.",
2897                        new Throwable());
2898            }
2899        }
2900
2901        @Override
2902        public boolean hasUserActivity() {
2903            return mUserActivityCounters != null;
2904        }
2905
2906        @Override
2907        public int getUserActivityCount(int type, int which) {
2908            if (mUserActivityCounters == null) {
2909                return 0;
2910            }
2911            return mUserActivityCounters[type].getCountLocked(which);
2912        }
2913
2914        void initUserActivityLocked() {
2915            mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
2916            for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2917                mUserActivityCounters[i] = new Counter(mUnpluggables);
2918            }
2919        }
2920
2921        void noteNetworkActivityLocked(int type, long delta) {
2922            if (mNetworkActivityCounters == null) {
2923                initNetworkActivityLocked();
2924            }
2925            if (type >= 0 && type < NUM_NETWORK_ACTIVITY_TYPES) {
2926                mNetworkActivityCounters[type].addCountLocked(delta);
2927            } else {
2928                Slog.w(TAG, "Unknown network activity type " + type + " was specified.",
2929                        new Throwable());
2930            }
2931        }
2932
2933        @Override
2934        public boolean hasNetworkActivity() {
2935            return mNetworkActivityCounters != null;
2936        }
2937
2938        @Override
2939        public long getNetworkActivityCount(int type, int which) {
2940            if (mNetworkActivityCounters != null && type >= 0
2941                    && type < mNetworkActivityCounters.length) {
2942                return mNetworkActivityCounters[type].getCountLocked(which);
2943            } else {
2944                return 0;
2945            }
2946        }
2947
2948        void initNetworkActivityLocked() {
2949            mNetworkActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
2950            for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
2951                mNetworkActivityCounters[i] = new LongSamplingCounter(mUnpluggables);
2952            }
2953        }
2954
2955        /**
2956         * Clear all stats for this uid.  Returns true if the uid is completely
2957         * inactive so can be dropped.
2958         */
2959        boolean reset() {
2960            boolean active = false;
2961
2962            if (mWifiRunningTimer != null) {
2963                active |= !mWifiRunningTimer.reset(BatteryStatsImpl.this, false);
2964                active |= mWifiRunning;
2965            }
2966            if (mFullWifiLockTimer != null) {
2967                active |= !mFullWifiLockTimer.reset(BatteryStatsImpl.this, false);
2968                active |= mFullWifiLockOut;
2969            }
2970            if (mWifiScanTimer != null) {
2971                active |= !mWifiScanTimer.reset(BatteryStatsImpl.this, false);
2972                active |= mWifiScanStarted;
2973            }
2974            if (mWifiMulticastTimer != null) {
2975                active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
2976                active |= mWifiMulticastEnabled;
2977            }
2978            if (mAudioTurnedOnTimer != null) {
2979                active |= !mAudioTurnedOnTimer.reset(BatteryStatsImpl.this, false);
2980                active |= mAudioTurnedOn;
2981            }
2982            if (mVideoTurnedOnTimer != null) {
2983                active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
2984                active |= mVideoTurnedOn;
2985            }
2986            if (mForegroundActivityTimer != null) {
2987                active |= !mForegroundActivityTimer.reset(BatteryStatsImpl.this, false);
2988            }
2989            if (mVibratorOnTimer != null) {
2990                if (mVibratorOnTimer.reset(BatteryStatsImpl.this, false)) {
2991                    mVibratorOnTimer.detach();
2992                    mVibratorOnTimer = null;
2993                } else {
2994                    active = true;
2995                }
2996            }
2997
2998            if (mUserActivityCounters != null) {
2999                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
3000                    mUserActivityCounters[i].reset(false);
3001                }
3002            }
3003
3004            if (mNetworkActivityCounters != null) {
3005                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
3006                    mNetworkActivityCounters[i].reset(false);
3007                }
3008            }
3009
3010            if (mWakelockStats.size() > 0) {
3011                Iterator<Map.Entry<String, Wakelock>> it = mWakelockStats.entrySet().iterator();
3012                while (it.hasNext()) {
3013                    Map.Entry<String, Wakelock> wakelockEntry = it.next();
3014                    Wakelock wl = wakelockEntry.getValue();
3015                    if (wl.reset()) {
3016                        it.remove();
3017                    } else {
3018                        active = true;
3019                    }
3020                }
3021            }
3022            if (mSensorStats.size() > 0) {
3023                Iterator<Map.Entry<Integer, Sensor>> it = mSensorStats.entrySet().iterator();
3024                while (it.hasNext()) {
3025                    Map.Entry<Integer, Sensor> sensorEntry = it.next();
3026                    Sensor s = sensorEntry.getValue();
3027                    if (s.reset()) {
3028                        it.remove();
3029                    } else {
3030                        active = true;
3031                    }
3032                }
3033            }
3034            if (mProcessStats.size() > 0) {
3035                Iterator<Map.Entry<String, Proc>> it = mProcessStats.entrySet().iterator();
3036                while (it.hasNext()) {
3037                    Map.Entry<String, Proc> procEntry = it.next();
3038                    procEntry.getValue().detach();
3039                }
3040                mProcessStats.clear();
3041            }
3042            if (mPids.size() > 0) {
3043                for (int i=0; !active && i<mPids.size(); i++) {
3044                    Pid pid = mPids.valueAt(i);
3045                    if (pid.mWakeStart != 0) {
3046                        active = true;
3047                    }
3048                }
3049            }
3050            if (mPackageStats.size() > 0) {
3051                Iterator<Map.Entry<String, Pkg>> it = mPackageStats.entrySet().iterator();
3052                while (it.hasNext()) {
3053                    Map.Entry<String, Pkg> pkgEntry = it.next();
3054                    Pkg p = pkgEntry.getValue();
3055                    p.detach();
3056                    if (p.mServiceStats.size() > 0) {
3057                        Iterator<Map.Entry<String, Pkg.Serv>> it2
3058                                = p.mServiceStats.entrySet().iterator();
3059                        while (it2.hasNext()) {
3060                            Map.Entry<String, Pkg.Serv> servEntry = it2.next();
3061                            servEntry.getValue().detach();
3062                        }
3063                    }
3064                }
3065                mPackageStats.clear();
3066            }
3067
3068            mPids.clear();
3069
3070            if (!active) {
3071                if (mWifiRunningTimer != null) {
3072                    mWifiRunningTimer.detach();
3073                }
3074                if (mFullWifiLockTimer != null) {
3075                    mFullWifiLockTimer.detach();
3076                }
3077                if (mWifiScanTimer != null) {
3078                    mWifiScanTimer.detach();
3079                }
3080                if (mWifiMulticastTimer != null) {
3081                    mWifiMulticastTimer.detach();
3082                }
3083                if (mAudioTurnedOnTimer != null) {
3084                    mAudioTurnedOnTimer.detach();
3085                    mAudioTurnedOnTimer = null;
3086                }
3087                if (mVideoTurnedOnTimer != null) {
3088                    mVideoTurnedOnTimer.detach();
3089                    mVideoTurnedOnTimer = null;
3090                }
3091                if (mForegroundActivityTimer != null) {
3092                    mForegroundActivityTimer.detach();
3093                    mForegroundActivityTimer = null;
3094                }
3095                if (mUserActivityCounters != null) {
3096                    for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
3097                        mUserActivityCounters[i].detach();
3098                    }
3099                }
3100                if (mNetworkActivityCounters != null) {
3101                    for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
3102                        mNetworkActivityCounters[i].detach();
3103                    }
3104                }
3105            }
3106
3107            return !active;
3108        }
3109
3110        void writeToParcelLocked(Parcel out, long batteryRealtime) {
3111            out.writeInt(mWakelockStats.size());
3112            for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
3113                out.writeString(wakelockEntry.getKey());
3114                Uid.Wakelock wakelock = wakelockEntry.getValue();
3115                wakelock.writeToParcelLocked(out, batteryRealtime);
3116            }
3117
3118            out.writeInt(mSensorStats.size());
3119            for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
3120                out.writeInt(sensorEntry.getKey());
3121                Uid.Sensor sensor = sensorEntry.getValue();
3122                sensor.writeToParcelLocked(out, batteryRealtime);
3123            }
3124
3125            out.writeInt(mProcessStats.size());
3126            for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
3127                out.writeString(procEntry.getKey());
3128                Uid.Proc proc = procEntry.getValue();
3129                proc.writeToParcelLocked(out);
3130            }
3131
3132            out.writeInt(mPackageStats.size());
3133            for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
3134                out.writeString(pkgEntry.getKey());
3135                Uid.Pkg pkg = pkgEntry.getValue();
3136                pkg.writeToParcelLocked(out);
3137            }
3138
3139            if (mWifiRunningTimer != null) {
3140                out.writeInt(1);
3141                mWifiRunningTimer.writeToParcel(out, batteryRealtime);
3142            } else {
3143                out.writeInt(0);
3144            }
3145            if (mFullWifiLockTimer != null) {
3146                out.writeInt(1);
3147                mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
3148            } else {
3149                out.writeInt(0);
3150            }
3151            if (mWifiScanTimer != null) {
3152                out.writeInt(1);
3153                mWifiScanTimer.writeToParcel(out, batteryRealtime);
3154            } else {
3155                out.writeInt(0);
3156            }
3157            if (mWifiMulticastTimer != null) {
3158                out.writeInt(1);
3159                mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
3160            } else {
3161                out.writeInt(0);
3162            }
3163            if (mAudioTurnedOnTimer != null) {
3164                out.writeInt(1);
3165                mAudioTurnedOnTimer.writeToParcel(out, batteryRealtime);
3166            } else {
3167                out.writeInt(0);
3168            }
3169            if (mVideoTurnedOnTimer != null) {
3170                out.writeInt(1);
3171                mVideoTurnedOnTimer.writeToParcel(out, batteryRealtime);
3172            } else {
3173                out.writeInt(0);
3174            }
3175            if (mForegroundActivityTimer != null) {
3176                out.writeInt(1);
3177                mForegroundActivityTimer.writeToParcel(out, batteryRealtime);
3178            } else {
3179                out.writeInt(0);
3180            }
3181            if (mVibratorOnTimer != null) {
3182                out.writeInt(1);
3183                mVibratorOnTimer.writeToParcel(out, batteryRealtime);
3184            } else {
3185                out.writeInt(0);
3186            }
3187            if (mUserActivityCounters != null) {
3188                out.writeInt(1);
3189                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
3190                    mUserActivityCounters[i].writeToParcel(out);
3191                }
3192            } else {
3193                out.writeInt(0);
3194            }
3195            if (mNetworkActivityCounters != null) {
3196                out.writeInt(1);
3197                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
3198                    mNetworkActivityCounters[i].writeToParcel(out);
3199                }
3200            } else {
3201                out.writeInt(0);
3202            }
3203        }
3204
3205        void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
3206            int numWakelocks = in.readInt();
3207            mWakelockStats.clear();
3208            for (int j = 0; j < numWakelocks; j++) {
3209                String wakelockName = in.readString();
3210                Uid.Wakelock wakelock = new Wakelock();
3211                wakelock.readFromParcelLocked(unpluggables, in);
3212                // We will just drop some random set of wakelocks if
3213                // the previous run of the system was an older version
3214                // that didn't impose a limit.
3215                mWakelockStats.put(wakelockName, wakelock);
3216            }
3217
3218            int numSensors = in.readInt();
3219            mSensorStats.clear();
3220            for (int k = 0; k < numSensors; k++) {
3221                int sensorNumber = in.readInt();
3222                Uid.Sensor sensor = new Sensor(sensorNumber);
3223                sensor.readFromParcelLocked(mUnpluggables, in);
3224                mSensorStats.put(sensorNumber, sensor);
3225            }
3226
3227            int numProcs = in.readInt();
3228            mProcessStats.clear();
3229            for (int k = 0; k < numProcs; k++) {
3230                String processName = in.readString();
3231                Uid.Proc proc = new Proc();
3232                proc.readFromParcelLocked(in);
3233                mProcessStats.put(processName, proc);
3234            }
3235
3236            int numPkgs = in.readInt();
3237            mPackageStats.clear();
3238            for (int l = 0; l < numPkgs; l++) {
3239                String packageName = in.readString();
3240                Uid.Pkg pkg = new Pkg();
3241                pkg.readFromParcelLocked(in);
3242                mPackageStats.put(packageName, pkg);
3243            }
3244
3245            mWifiRunning = false;
3246            if (in.readInt() != 0) {
3247                mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
3248                        mWifiRunningTimers, mUnpluggables, in);
3249            } else {
3250                mWifiRunningTimer = null;
3251            }
3252            mFullWifiLockOut = false;
3253            if (in.readInt() != 0) {
3254                mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
3255                        mFullWifiLockTimers, mUnpluggables, in);
3256            } else {
3257                mFullWifiLockTimer = null;
3258            }
3259            mWifiScanStarted = false;
3260            if (in.readInt() != 0) {
3261                mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
3262                        mWifiScanTimers, mUnpluggables, in);
3263            } else {
3264                mWifiScanTimer = null;
3265            }
3266            mWifiMulticastEnabled = false;
3267            if (in.readInt() != 0) {
3268                mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
3269                        mWifiMulticastTimers, mUnpluggables, in);
3270            } else {
3271                mWifiMulticastTimer = null;
3272            }
3273            mAudioTurnedOn = false;
3274            if (in.readInt() != 0) {
3275                mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
3276                        null, mUnpluggables, in);
3277            } else {
3278                mAudioTurnedOnTimer = null;
3279            }
3280            mVideoTurnedOn = false;
3281            if (in.readInt() != 0) {
3282                mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
3283                        null, mUnpluggables, in);
3284            } else {
3285                mVideoTurnedOnTimer = null;
3286            }
3287            if (in.readInt() != 0) {
3288                mForegroundActivityTimer = new StopwatchTimer(
3289                        Uid.this, FOREGROUND_ACTIVITY, null, mUnpluggables, in);
3290            } else {
3291                mForegroundActivityTimer = null;
3292            }
3293            if (in.readInt() != 0) {
3294                mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON,
3295                        mUnpluggables, BatteryStatsImpl.this.mOnBatteryInternal, in);
3296            } else {
3297                mVibratorOnTimer = null;
3298            }
3299            if (in.readInt() != 0) {
3300                mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
3301                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
3302                    mUserActivityCounters[i] = new Counter(mUnpluggables, in);
3303                }
3304            } else {
3305                mUserActivityCounters = null;
3306            }
3307            if (in.readInt() != 0) {
3308                mNetworkActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
3309                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
3310                    mNetworkActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in);
3311                }
3312            } else {
3313                mNetworkActivityCounters = null;
3314            }
3315        }
3316
3317        /**
3318         * The statistics associated with a particular wake lock.
3319         */
3320        public final class Wakelock extends BatteryStats.Uid.Wakelock {
3321            /**
3322             * How long (in ms) this uid has been keeping the device partially awake.
3323             */
3324            StopwatchTimer mTimerPartial;
3325
3326            /**
3327             * How long (in ms) this uid has been keeping the device fully awake.
3328             */
3329            StopwatchTimer mTimerFull;
3330
3331            /**
3332             * How long (in ms) this uid has had a window keeping the device awake.
3333             */
3334            StopwatchTimer mTimerWindow;
3335
3336            /**
3337             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
3338             * proper timer pool from the given BatteryStatsImpl object.
3339             *
3340             * @param in the Parcel to be read from.
3341             * return a new Timer, or null.
3342             */
3343            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
3344                    ArrayList<Unpluggable> unpluggables, Parcel in) {
3345                if (in.readInt() == 0) {
3346                    return null;
3347                }
3348
3349                return new StopwatchTimer(Uid.this, type, pool, unpluggables, in);
3350            }
3351
3352            boolean reset() {
3353                boolean wlactive = false;
3354                if (mTimerFull != null) {
3355                    wlactive |= !mTimerFull.reset(BatteryStatsImpl.this, false);
3356                }
3357                if (mTimerPartial != null) {
3358                    wlactive |= !mTimerPartial.reset(BatteryStatsImpl.this, false);
3359                }
3360                if (mTimerWindow != null) {
3361                    wlactive |= !mTimerWindow.reset(BatteryStatsImpl.this, false);
3362                }
3363                if (!wlactive) {
3364                    if (mTimerFull != null) {
3365                        mTimerFull.detach();
3366                        mTimerFull = null;
3367                    }
3368                    if (mTimerPartial != null) {
3369                        mTimerPartial.detach();
3370                        mTimerPartial = null;
3371                    }
3372                    if (mTimerWindow != null) {
3373                        mTimerWindow.detach();
3374                        mTimerWindow = null;
3375                    }
3376                }
3377                return !wlactive;
3378            }
3379
3380            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
3381                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
3382                        mPartialTimers, unpluggables, in);
3383                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
3384                        mFullTimers, unpluggables, in);
3385                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
3386                        mWindowTimers, unpluggables, in);
3387            }
3388
3389            void writeToParcelLocked(Parcel out, long batteryRealtime) {
3390                Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
3391                Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
3392                Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
3393            }
3394
3395            @Override
3396            public Timer getWakeTime(int type) {
3397                switch (type) {
3398                case WAKE_TYPE_FULL: return mTimerFull;
3399                case WAKE_TYPE_PARTIAL: return mTimerPartial;
3400                case WAKE_TYPE_WINDOW: return mTimerWindow;
3401                default: throw new IllegalArgumentException("type = " + type);
3402                }
3403            }
3404        }
3405
3406        public final class Sensor extends BatteryStats.Uid.Sensor {
3407            final int mHandle;
3408            StopwatchTimer mTimer;
3409
3410            public Sensor(int handle) {
3411                mHandle = handle;
3412            }
3413
3414            private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
3415                    Parcel in) {
3416                if (in.readInt() == 0) {
3417                    return null;
3418                }
3419
3420                ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
3421                if (pool == null) {
3422                    pool = new ArrayList<StopwatchTimer>();
3423                    mSensorTimers.put(mHandle, pool);
3424                }
3425                return new StopwatchTimer(Uid.this, 0, pool, unpluggables, in);
3426            }
3427
3428            boolean reset() {
3429                if (mTimer.reset(BatteryStatsImpl.this, true)) {
3430                    mTimer = null;
3431                    return true;
3432                }
3433                return false;
3434            }
3435
3436            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
3437                mTimer = readTimerFromParcel(unpluggables, in);
3438            }
3439
3440            void writeToParcelLocked(Parcel out, long batteryRealtime) {
3441                Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
3442            }
3443
3444            @Override
3445            public Timer getSensorTime() {
3446                return mTimer;
3447            }
3448
3449            @Override
3450            public int getHandle() {
3451                return mHandle;
3452            }
3453        }
3454
3455        /**
3456         * The statistics associated with a particular process.
3457         */
3458        public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
3459            /**
3460             * Total time (in 1/100 sec) spent executing in user code.
3461             */
3462            long mUserTime;
3463
3464            /**
3465             * Total time (in 1/100 sec) spent executing in kernel code.
3466             */
3467            long mSystemTime;
3468
3469            /**
3470             * Amount of time the process was running in the foreground.
3471             */
3472            long mForegroundTime;
3473
3474            /**
3475             * Number of times the process has been started.
3476             */
3477            int mStarts;
3478
3479            /**
3480             * The amount of user time loaded from a previous save.
3481             */
3482            long mLoadedUserTime;
3483
3484            /**
3485             * The amount of system time loaded from a previous save.
3486             */
3487            long mLoadedSystemTime;
3488
3489            /**
3490             * The amount of foreground time loaded from a previous save.
3491             */
3492            long mLoadedForegroundTime;
3493
3494            /**
3495             * The number of times the process has started from a previous save.
3496             */
3497            int mLoadedStarts;
3498
3499            /**
3500             * The amount of user time loaded from the previous run.
3501             */
3502            long mLastUserTime;
3503
3504            /**
3505             * The amount of system time loaded from the previous run.
3506             */
3507            long mLastSystemTime;
3508
3509            /**
3510             * The amount of foreground time loaded from the previous run
3511             */
3512            long mLastForegroundTime;
3513
3514            /**
3515             * The number of times the process has started from the previous run.
3516             */
3517            int mLastStarts;
3518
3519            /**
3520             * The amount of user time when last unplugged.
3521             */
3522            long mUnpluggedUserTime;
3523
3524            /**
3525             * The amount of system time when last unplugged.
3526             */
3527            long mUnpluggedSystemTime;
3528
3529            /**
3530             * The amount of foreground time since unplugged.
3531             */
3532            long mUnpluggedForegroundTime;
3533
3534            /**
3535             * The number of times the process has started before unplugged.
3536             */
3537            int mUnpluggedStarts;
3538
3539            SamplingCounter[] mSpeedBins;
3540
3541            ArrayList<ExcessivePower> mExcessivePower;
3542
3543            Proc() {
3544                mUnpluggables.add(this);
3545                mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
3546            }
3547
3548            public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
3549                mUnpluggedUserTime = mUserTime;
3550                mUnpluggedSystemTime = mSystemTime;
3551                mUnpluggedForegroundTime = mForegroundTime;
3552                mUnpluggedStarts = mStarts;
3553            }
3554
3555            public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
3556            }
3557
3558            void detach() {
3559                mUnpluggables.remove(this);
3560                for (int i = 0; i < mSpeedBins.length; i++) {
3561                    SamplingCounter c = mSpeedBins[i];
3562                    if (c != null) {
3563                        mUnpluggables.remove(c);
3564                        mSpeedBins[i] = null;
3565                    }
3566                }
3567            }
3568
3569            public int countExcessivePowers() {
3570                return mExcessivePower != null ? mExcessivePower.size() : 0;
3571            }
3572
3573            public ExcessivePower getExcessivePower(int i) {
3574                if (mExcessivePower != null) {
3575                    return mExcessivePower.get(i);
3576                }
3577                return null;
3578            }
3579
3580            public void addExcessiveWake(long overTime, long usedTime) {
3581                if (mExcessivePower == null) {
3582                    mExcessivePower = new ArrayList<ExcessivePower>();
3583                }
3584                ExcessivePower ew = new ExcessivePower();
3585                ew.type = ExcessivePower.TYPE_WAKE;
3586                ew.overTime = overTime;
3587                ew.usedTime = usedTime;
3588                mExcessivePower.add(ew);
3589            }
3590
3591            public void addExcessiveCpu(long overTime, long usedTime) {
3592                if (mExcessivePower == null) {
3593                    mExcessivePower = new ArrayList<ExcessivePower>();
3594                }
3595                ExcessivePower ew = new ExcessivePower();
3596                ew.type = ExcessivePower.TYPE_CPU;
3597                ew.overTime = overTime;
3598                ew.usedTime = usedTime;
3599                mExcessivePower.add(ew);
3600            }
3601
3602            void writeExcessivePowerToParcelLocked(Parcel out) {
3603                if (mExcessivePower == null) {
3604                    out.writeInt(0);
3605                    return;
3606                }
3607
3608                final int N = mExcessivePower.size();
3609                out.writeInt(N);
3610                for (int i=0; i<N; i++) {
3611                    ExcessivePower ew = mExcessivePower.get(i);
3612                    out.writeInt(ew.type);
3613                    out.writeLong(ew.overTime);
3614                    out.writeLong(ew.usedTime);
3615                }
3616            }
3617
3618            boolean readExcessivePowerFromParcelLocked(Parcel in) {
3619                final int N = in.readInt();
3620                if (N == 0) {
3621                    mExcessivePower = null;
3622                    return true;
3623                }
3624
3625                if (N > 10000) {
3626                    Slog.w(TAG, "File corrupt: too many excessive power entries " + N);
3627                    return false;
3628                }
3629
3630                mExcessivePower = new ArrayList<ExcessivePower>();
3631                for (int i=0; i<N; i++) {
3632                    ExcessivePower ew = new ExcessivePower();
3633                    ew.type = in.readInt();
3634                    ew.overTime = in.readLong();
3635                    ew.usedTime = in.readLong();
3636                    mExcessivePower.add(ew);
3637                }
3638                return true;
3639            }
3640
3641            void writeToParcelLocked(Parcel out) {
3642                out.writeLong(mUserTime);
3643                out.writeLong(mSystemTime);
3644                out.writeLong(mForegroundTime);
3645                out.writeInt(mStarts);
3646                out.writeLong(mLoadedUserTime);
3647                out.writeLong(mLoadedSystemTime);
3648                out.writeLong(mLoadedForegroundTime);
3649                out.writeInt(mLoadedStarts);
3650                out.writeLong(mUnpluggedUserTime);
3651                out.writeLong(mUnpluggedSystemTime);
3652                out.writeLong(mUnpluggedForegroundTime);
3653                out.writeInt(mUnpluggedStarts);
3654
3655                out.writeInt(mSpeedBins.length);
3656                for (int i = 0; i < mSpeedBins.length; i++) {
3657                    SamplingCounter c = mSpeedBins[i];
3658                    if (c != null) {
3659                        out.writeInt(1);
3660                        c.writeToParcel(out);
3661                    } else {
3662                        out.writeInt(0);
3663                    }
3664                }
3665
3666                writeExcessivePowerToParcelLocked(out);
3667            }
3668
3669            void readFromParcelLocked(Parcel in) {
3670                mUserTime = in.readLong();
3671                mSystemTime = in.readLong();
3672                mForegroundTime = in.readLong();
3673                mStarts = in.readInt();
3674                mLoadedUserTime = in.readLong();
3675                mLoadedSystemTime = in.readLong();
3676                mLoadedForegroundTime = in.readLong();
3677                mLoadedStarts = in.readInt();
3678                mLastUserTime = 0;
3679                mLastSystemTime = 0;
3680                mLastForegroundTime = 0;
3681                mLastStarts = 0;
3682                mUnpluggedUserTime = in.readLong();
3683                mUnpluggedSystemTime = in.readLong();
3684                mUnpluggedForegroundTime = in.readLong();
3685                mUnpluggedStarts = in.readInt();
3686
3687                int bins = in.readInt();
3688                int steps = getCpuSpeedSteps();
3689                mSpeedBins = new SamplingCounter[bins >= steps ? bins : steps];
3690                for (int i = 0; i < bins; i++) {
3691                    if (in.readInt() != 0) {
3692                        mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
3693                    }
3694                }
3695
3696                readExcessivePowerFromParcelLocked(in);
3697            }
3698
3699            public BatteryStatsImpl getBatteryStats() {
3700                return BatteryStatsImpl.this;
3701            }
3702
3703            public void addCpuTimeLocked(int utime, int stime) {
3704                mUserTime += utime;
3705                mSystemTime += stime;
3706            }
3707
3708            public void addForegroundTimeLocked(long ttime) {
3709                mForegroundTime += ttime;
3710            }
3711
3712            public void incStartsLocked() {
3713                mStarts++;
3714            }
3715
3716            @Override
3717            public long getUserTime(int which) {
3718                long val;
3719                if (which == STATS_LAST) {
3720                    val = mLastUserTime;
3721                } else {
3722                    val = mUserTime;
3723                    if (which == STATS_CURRENT) {
3724                        val -= mLoadedUserTime;
3725                    } else if (which == STATS_SINCE_UNPLUGGED) {
3726                        val -= mUnpluggedUserTime;
3727                    }
3728                }
3729                return val;
3730            }
3731
3732            @Override
3733            public long getSystemTime(int which) {
3734                long val;
3735                if (which == STATS_LAST) {
3736                    val = mLastSystemTime;
3737                } else {
3738                    val = mSystemTime;
3739                    if (which == STATS_CURRENT) {
3740                        val -= mLoadedSystemTime;
3741                    } else if (which == STATS_SINCE_UNPLUGGED) {
3742                        val -= mUnpluggedSystemTime;
3743                    }
3744                }
3745                return val;
3746            }
3747
3748            @Override
3749            public long getForegroundTime(int which) {
3750                long val;
3751                if (which == STATS_LAST) {
3752                    val = mLastForegroundTime;
3753                } else {
3754                    val = mForegroundTime;
3755                    if (which == STATS_CURRENT) {
3756                        val -= mLoadedForegroundTime;
3757                    } else if (which == STATS_SINCE_UNPLUGGED) {
3758                        val -= mUnpluggedForegroundTime;
3759                    }
3760                }
3761                return val;
3762            }
3763
3764            @Override
3765            public int getStarts(int which) {
3766                int val;
3767                if (which == STATS_LAST) {
3768                    val = mLastStarts;
3769                } else {
3770                    val = mStarts;
3771                    if (which == STATS_CURRENT) {
3772                        val -= mLoadedStarts;
3773                    } else if (which == STATS_SINCE_UNPLUGGED) {
3774                        val -= mUnpluggedStarts;
3775                    }
3776                }
3777                return val;
3778            }
3779
3780            /* Called by ActivityManagerService when CPU times are updated. */
3781            public void addSpeedStepTimes(long[] values) {
3782                for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
3783                    long amt = values[i];
3784                    if (amt != 0) {
3785                        SamplingCounter c = mSpeedBins[i];
3786                        if (c == null) {
3787                            mSpeedBins[i] = c = new SamplingCounter(mUnpluggables);
3788                        }
3789                        c.addCountAtomic(values[i]);
3790                    }
3791                }
3792            }
3793
3794            @Override
3795            public long getTimeAtCpuSpeedStep(int speedStep, int which) {
3796                if (speedStep < mSpeedBins.length) {
3797                    SamplingCounter c = mSpeedBins[speedStep];
3798                    return c != null ? c.getCountLocked(which) : 0;
3799                } else {
3800                    return 0;
3801                }
3802            }
3803        }
3804
3805        /**
3806         * The statistics associated with a particular package.
3807         */
3808        public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
3809            /**
3810             * Number of times this package has done something that could wake up the
3811             * device from sleep.
3812             */
3813            int mWakeups;
3814
3815            /**
3816             * Number of things that could wake up the device loaded from a
3817             * previous save.
3818             */
3819            int mLoadedWakeups;
3820
3821            /**
3822             * Number of things that could wake up the device as of the
3823             * last run.
3824             */
3825            int mLastWakeups;
3826
3827            /**
3828             * Number of things that could wake up the device as of the
3829             * last run.
3830             */
3831            int mUnpluggedWakeups;
3832
3833            /**
3834             * The statics we have collected for this package's services.
3835             */
3836            final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
3837
3838            Pkg() {
3839                mUnpluggables.add(this);
3840            }
3841
3842            public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
3843                mUnpluggedWakeups = mWakeups;
3844            }
3845
3846            public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
3847            }
3848
3849            void detach() {
3850                mUnpluggables.remove(this);
3851            }
3852
3853            void readFromParcelLocked(Parcel in) {
3854                mWakeups = in.readInt();
3855                mLoadedWakeups = in.readInt();
3856                mLastWakeups = 0;
3857                mUnpluggedWakeups = in.readInt();
3858
3859                int numServs = in.readInt();
3860                mServiceStats.clear();
3861                for (int m = 0; m < numServs; m++) {
3862                    String serviceName = in.readString();
3863                    Uid.Pkg.Serv serv = new Serv();
3864                    mServiceStats.put(serviceName, serv);
3865
3866                    serv.readFromParcelLocked(in);
3867                }
3868            }
3869
3870            void writeToParcelLocked(Parcel out) {
3871                out.writeInt(mWakeups);
3872                out.writeInt(mLoadedWakeups);
3873                out.writeInt(mUnpluggedWakeups);
3874
3875                out.writeInt(mServiceStats.size());
3876                for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
3877                    out.writeString(servEntry.getKey());
3878                    Uid.Pkg.Serv serv = servEntry.getValue();
3879
3880                    serv.writeToParcelLocked(out);
3881                }
3882            }
3883
3884            @Override
3885            public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
3886                return mServiceStats;
3887            }
3888
3889            @Override
3890            public int getWakeups(int which) {
3891                int val;
3892                if (which == STATS_LAST) {
3893                    val = mLastWakeups;
3894                } else {
3895                    val = mWakeups;
3896                    if (which == STATS_CURRENT) {
3897                        val -= mLoadedWakeups;
3898                    } else if (which == STATS_SINCE_UNPLUGGED) {
3899                        val -= mUnpluggedWakeups;
3900                    }
3901                }
3902
3903                return val;
3904            }
3905
3906            /**
3907             * The statistics associated with a particular service.
3908             */
3909            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
3910                /**
3911                 * Total time (ms in battery uptime) the service has been left started.
3912                 */
3913                long mStartTime;
3914
3915                /**
3916                 * If service has been started and not yet stopped, this is
3917                 * when it was started.
3918                 */
3919                long mRunningSince;
3920
3921                /**
3922                 * True if we are currently running.
3923                 */
3924                boolean mRunning;
3925
3926                /**
3927                 * Total number of times startService() has been called.
3928                 */
3929                int mStarts;
3930
3931                /**
3932                 * Total time (ms in battery uptime) the service has been left launched.
3933                 */
3934                long mLaunchedTime;
3935
3936                /**
3937                 * If service has been launched and not yet exited, this is
3938                 * when it was launched (ms in battery uptime).
3939                 */
3940                long mLaunchedSince;
3941
3942                /**
3943                 * True if we are currently launched.
3944                 */
3945                boolean mLaunched;
3946
3947                /**
3948                 * Total number times the service has been launched.
3949                 */
3950                int mLaunches;
3951
3952                /**
3953                 * The amount of time spent started loaded from a previous save
3954                 * (ms in battery uptime).
3955                 */
3956                long mLoadedStartTime;
3957
3958                /**
3959                 * The number of starts loaded from a previous save.
3960                 */
3961                int mLoadedStarts;
3962
3963                /**
3964                 * The number of launches loaded from a previous save.
3965                 */
3966                int mLoadedLaunches;
3967
3968                /**
3969                 * The amount of time spent started as of the last run (ms
3970                 * in battery uptime).
3971                 */
3972                long mLastStartTime;
3973
3974                /**
3975                 * The number of starts as of the last run.
3976                 */
3977                int mLastStarts;
3978
3979                /**
3980                 * The number of launches as of the last run.
3981                 */
3982                int mLastLaunches;
3983
3984                /**
3985                 * The amount of time spent started when last unplugged (ms
3986                 * in battery uptime).
3987                 */
3988                long mUnpluggedStartTime;
3989
3990                /**
3991                 * The number of starts when last unplugged.
3992                 */
3993                int mUnpluggedStarts;
3994
3995                /**
3996                 * The number of launches when last unplugged.
3997                 */
3998                int mUnpluggedLaunches;
3999
4000                Serv() {
4001                    mUnpluggables.add(this);
4002                }
4003
4004                public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
4005                    mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
4006                    mUnpluggedStarts = mStarts;
4007                    mUnpluggedLaunches = mLaunches;
4008                }
4009
4010                public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
4011                }
4012
4013                void detach() {
4014                    mUnpluggables.remove(this);
4015                }
4016
4017                void readFromParcelLocked(Parcel in) {
4018                    mStartTime = in.readLong();
4019                    mRunningSince = in.readLong();
4020                    mRunning = in.readInt() != 0;
4021                    mStarts = in.readInt();
4022                    mLaunchedTime = in.readLong();
4023                    mLaunchedSince = in.readLong();
4024                    mLaunched = in.readInt() != 0;
4025                    mLaunches = in.readInt();
4026                    mLoadedStartTime = in.readLong();
4027                    mLoadedStarts = in.readInt();
4028                    mLoadedLaunches = in.readInt();
4029                    mLastStartTime = 0;
4030                    mLastStarts = 0;
4031                    mLastLaunches = 0;
4032                    mUnpluggedStartTime = in.readLong();
4033                    mUnpluggedStarts = in.readInt();
4034                    mUnpluggedLaunches = in.readInt();
4035                }
4036
4037                void writeToParcelLocked(Parcel out) {
4038                    out.writeLong(mStartTime);
4039                    out.writeLong(mRunningSince);
4040                    out.writeInt(mRunning ? 1 : 0);
4041                    out.writeInt(mStarts);
4042                    out.writeLong(mLaunchedTime);
4043                    out.writeLong(mLaunchedSince);
4044                    out.writeInt(mLaunched ? 1 : 0);
4045                    out.writeInt(mLaunches);
4046                    out.writeLong(mLoadedStartTime);
4047                    out.writeInt(mLoadedStarts);
4048                    out.writeInt(mLoadedLaunches);
4049                    out.writeLong(mUnpluggedStartTime);
4050                    out.writeInt(mUnpluggedStarts);
4051                    out.writeInt(mUnpluggedLaunches);
4052                }
4053
4054                long getLaunchTimeToNowLocked(long batteryUptime) {
4055                    if (!mLaunched) return mLaunchedTime;
4056                    return mLaunchedTime + batteryUptime - mLaunchedSince;
4057                }
4058
4059                long getStartTimeToNowLocked(long batteryUptime) {
4060                    if (!mRunning) return mStartTime;
4061                    return mStartTime + batteryUptime - mRunningSince;
4062                }
4063
4064                public void startLaunchedLocked() {
4065                    if (!mLaunched) {
4066                        mLaunches++;
4067                        mLaunchedSince = getBatteryUptimeLocked();
4068                        mLaunched = true;
4069                    }
4070                }
4071
4072                public void stopLaunchedLocked() {
4073                    if (mLaunched) {
4074                        long time = getBatteryUptimeLocked() - mLaunchedSince;
4075                        if (time > 0) {
4076                            mLaunchedTime += time;
4077                        } else {
4078                            mLaunches--;
4079                        }
4080                        mLaunched = false;
4081                    }
4082                }
4083
4084                public void startRunningLocked() {
4085                    if (!mRunning) {
4086                        mStarts++;
4087                        mRunningSince = getBatteryUptimeLocked();
4088                        mRunning = true;
4089                    }
4090                }
4091
4092                public void stopRunningLocked() {
4093                    if (mRunning) {
4094                        long time = getBatteryUptimeLocked() - mRunningSince;
4095                        if (time > 0) {
4096                            mStartTime += time;
4097                        } else {
4098                            mStarts--;
4099                        }
4100                        mRunning = false;
4101                    }
4102                }
4103
4104                public BatteryStatsImpl getBatteryStats() {
4105                    return BatteryStatsImpl.this;
4106                }
4107
4108                @Override
4109                public int getLaunches(int which) {
4110                    int val;
4111
4112                    if (which == STATS_LAST) {
4113                        val = mLastLaunches;
4114                    } else {
4115                        val = mLaunches;
4116                        if (which == STATS_CURRENT) {
4117                            val -= mLoadedLaunches;
4118                        } else if (which == STATS_SINCE_UNPLUGGED) {
4119                            val -= mUnpluggedLaunches;
4120                        }
4121                    }
4122
4123                    return val;
4124                }
4125
4126                @Override
4127                public long getStartTime(long now, int which) {
4128                    long val;
4129                    if (which == STATS_LAST) {
4130                        val = mLastStartTime;
4131                    } else {
4132                        val = getStartTimeToNowLocked(now);
4133                        if (which == STATS_CURRENT) {
4134                            val -= mLoadedStartTime;
4135                        } else if (which == STATS_SINCE_UNPLUGGED) {
4136                            val -= mUnpluggedStartTime;
4137                        }
4138                    }
4139
4140                    return val;
4141                }
4142
4143                @Override
4144                public int getStarts(int which) {
4145                    int val;
4146                    if (which == STATS_LAST) {
4147                        val = mLastStarts;
4148                    } else {
4149                        val = mStarts;
4150                        if (which == STATS_CURRENT) {
4151                            val -= mLoadedStarts;
4152                        } else if (which == STATS_SINCE_UNPLUGGED) {
4153                            val -= mUnpluggedStarts;
4154                        }
4155                    }
4156
4157                    return val;
4158                }
4159            }
4160
4161            public BatteryStatsImpl getBatteryStats() {
4162                return BatteryStatsImpl.this;
4163            }
4164
4165            public void incWakeupsLocked() {
4166                mWakeups++;
4167            }
4168
4169            final Serv newServiceStatsLocked() {
4170                return new Serv();
4171            }
4172        }
4173
4174        /**
4175         * Retrieve the statistics object for a particular process, creating
4176         * if needed.
4177         */
4178        public Proc getProcessStatsLocked(String name) {
4179            Proc ps = mProcessStats.get(name);
4180            if (ps == null) {
4181                ps = new Proc();
4182                mProcessStats.put(name, ps);
4183            }
4184
4185            return ps;
4186        }
4187
4188        public SparseArray<? extends Pid> getPidStats() {
4189            return mPids;
4190        }
4191
4192        public Pid getPidStatsLocked(int pid) {
4193            Pid p = mPids.get(pid);
4194            if (p == null) {
4195                p = new Pid();
4196                mPids.put(pid, p);
4197            }
4198            return p;
4199        }
4200
4201        /**
4202         * Retrieve the statistics object for a particular service, creating
4203         * if needed.
4204         */
4205        public Pkg getPackageStatsLocked(String name) {
4206            Pkg ps = mPackageStats.get(name);
4207            if (ps == null) {
4208                ps = new Pkg();
4209                mPackageStats.put(name, ps);
4210            }
4211
4212            return ps;
4213        }
4214
4215        /**
4216         * Retrieve the statistics object for a particular service, creating
4217         * if needed.
4218         */
4219        public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
4220            Pkg ps = getPackageStatsLocked(pkg);
4221            Pkg.Serv ss = ps.mServiceStats.get(serv);
4222            if (ss == null) {
4223                ss = ps.newServiceStatsLocked();
4224                ps.mServiceStats.put(serv, ss);
4225            }
4226
4227            return ss;
4228        }
4229
4230        public StopwatchTimer getWakeTimerLocked(String name, int type) {
4231            Wakelock wl = mWakelockStats.get(name);
4232            if (wl == null) {
4233                final int N = mWakelockStats.size();
4234                if (N > MAX_WAKELOCKS_PER_UID) {
4235                    name = BATCHED_WAKELOCK_NAME;
4236                    wl = mWakelockStats.get(name);
4237                }
4238                if (wl == null) {
4239                    wl = new Wakelock();
4240                    mWakelockStats.put(name, wl);
4241                }
4242            }
4243            StopwatchTimer t = null;
4244            switch (type) {
4245                case WAKE_TYPE_PARTIAL:
4246                    t = wl.mTimerPartial;
4247                    if (t == null) {
4248                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
4249                                mPartialTimers, mUnpluggables);
4250                        wl.mTimerPartial = t;
4251                    }
4252                    return t;
4253                case WAKE_TYPE_FULL:
4254                    t = wl.mTimerFull;
4255                    if (t == null) {
4256                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
4257                                mFullTimers, mUnpluggables);
4258                        wl.mTimerFull = t;
4259                    }
4260                    return t;
4261                case WAKE_TYPE_WINDOW:
4262                    t = wl.mTimerWindow;
4263                    if (t == null) {
4264                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
4265                                mWindowTimers, mUnpluggables);
4266                        wl.mTimerWindow = t;
4267                    }
4268                    return t;
4269                default:
4270                    throw new IllegalArgumentException("type=" + type);
4271            }
4272        }
4273
4274        public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
4275            Sensor se = mSensorStats.get(sensor);
4276            if (se == null) {
4277                if (!create) {
4278                    return null;
4279                }
4280                se = new Sensor(sensor);
4281                mSensorStats.put(sensor, se);
4282            }
4283            StopwatchTimer t = se.mTimer;
4284            if (t != null) {
4285                return t;
4286            }
4287            ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
4288            if (timers == null) {
4289                timers = new ArrayList<StopwatchTimer>();
4290                mSensorTimers.put(sensor, timers);
4291            }
4292            t = new StopwatchTimer(Uid.this, BatteryStats.SENSOR, timers, mUnpluggables);
4293            se.mTimer = t;
4294            return t;
4295        }
4296
4297        public void noteStartWakeLocked(int pid, String name, int type) {
4298            StopwatchTimer t = getWakeTimerLocked(name, type);
4299            if (t != null) {
4300                t.startRunningLocked(BatteryStatsImpl.this);
4301            }
4302            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
4303                Pid p = getPidStatsLocked(pid);
4304                if (p.mWakeStart == 0) {
4305                    p.mWakeStart = SystemClock.elapsedRealtime();
4306                }
4307            }
4308        }
4309
4310        public void noteStopWakeLocked(int pid, String name, int type) {
4311            StopwatchTimer t = getWakeTimerLocked(name, type);
4312            if (t != null) {
4313                t.stopRunningLocked(BatteryStatsImpl.this);
4314            }
4315            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
4316                Pid p = mPids.get(pid);
4317                if (p != null && p.mWakeStart != 0) {
4318                    p.mWakeSum += SystemClock.elapsedRealtime() - p.mWakeStart;
4319                    p.mWakeStart = 0;
4320                }
4321            }
4322        }
4323
4324        public void reportExcessiveWakeLocked(String proc, long overTime, long usedTime) {
4325            Proc p = getProcessStatsLocked(proc);
4326            if (p != null) {
4327                p.addExcessiveWake(overTime, usedTime);
4328            }
4329        }
4330
4331        public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) {
4332            Proc p = getProcessStatsLocked(proc);
4333            if (p != null) {
4334                p.addExcessiveCpu(overTime, usedTime);
4335            }
4336        }
4337
4338        public void noteStartSensor(int sensor) {
4339            StopwatchTimer t = getSensorTimerLocked(sensor, true);
4340            if (t != null) {
4341                t.startRunningLocked(BatteryStatsImpl.this);
4342            }
4343        }
4344
4345        public void noteStopSensor(int sensor) {
4346            // Don't create a timer if one doesn't already exist
4347            StopwatchTimer t = getSensorTimerLocked(sensor, false);
4348            if (t != null) {
4349                t.stopRunningLocked(BatteryStatsImpl.this);
4350            }
4351        }
4352
4353        public void noteStartGps() {
4354            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
4355            if (t != null) {
4356                t.startRunningLocked(BatteryStatsImpl.this);
4357            }
4358        }
4359
4360        public void noteStopGps() {
4361            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
4362            if (t != null) {
4363                t.stopRunningLocked(BatteryStatsImpl.this);
4364            }
4365        }
4366
4367        public BatteryStatsImpl getBatteryStats() {
4368            return BatteryStatsImpl.this;
4369        }
4370    }
4371
4372    public BatteryStatsImpl(String filename) {
4373        mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
4374        mHandler = new MyHandler();
4375        mStartCount++;
4376        mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables);
4377        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4378            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mUnpluggables);
4379        }
4380        mInputEventCounter = new Counter(mUnpluggables);
4381        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables);
4382        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
4383            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null, mUnpluggables);
4384        }
4385        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables);
4386        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4387            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null, mUnpluggables);
4388        }
4389        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
4390            mNetworkActivityCounters[i] = new LongSamplingCounter(mUnpluggables);
4391        }
4392        mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables);
4393        mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
4394        mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables);
4395        mAudioOnTimer = new StopwatchTimer(null, -6, null, mUnpluggables);
4396        mVideoOnTimer = new StopwatchTimer(null, -7, null, mUnpluggables);
4397        mOnBattery = mOnBatteryInternal = false;
4398        initTimes();
4399        mTrackBatteryPastUptime = 0;
4400        mTrackBatteryPastRealtime = 0;
4401        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
4402        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
4403        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
4404        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
4405        mDischargeStartLevel = 0;
4406        mDischargeUnplugLevel = 0;
4407        mDischargeCurrentLevel = 0;
4408        initDischarge();
4409        clearHistoryLocked();
4410    }
4411
4412    public BatteryStatsImpl(Parcel p) {
4413        mFile = null;
4414        mHandler = null;
4415        clearHistoryLocked();
4416        readFromParcel(p);
4417    }
4418
4419    public void setCallback(BatteryCallback cb) {
4420        mCallback = cb;
4421    }
4422
4423    public void setNumSpeedSteps(int steps) {
4424        if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
4425    }
4426
4427    public void setRadioScanningTimeout(long timeout) {
4428        if (mPhoneSignalScanningTimer != null) {
4429            mPhoneSignalScanningTimer.setTimeout(timeout);
4430        }
4431    }
4432
4433    @Override
4434    public boolean startIteratingOldHistoryLocked() {
4435        if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
4436                + " pos=" + mHistoryBuffer.dataPosition());
4437        mHistoryBuffer.setDataPosition(0);
4438        mHistoryReadTmp.clear();
4439        mReadOverflow = false;
4440        mIteratingHistory = true;
4441        return (mHistoryIterator = mHistory) != null;
4442    }
4443
4444    @Override
4445    public boolean getNextOldHistoryLocked(HistoryItem out) {
4446        boolean end = mHistoryBuffer.dataPosition() >= mHistoryBuffer.dataSize();
4447        if (!end) {
4448            mHistoryReadTmp.readDelta(mHistoryBuffer);
4449            mReadOverflow |= mHistoryReadTmp.cmd == HistoryItem.CMD_OVERFLOW;
4450        }
4451        HistoryItem cur = mHistoryIterator;
4452        if (cur == null) {
4453            if (!mReadOverflow && !end) {
4454                Slog.w(TAG, "Old history ends before new history!");
4455            }
4456            return false;
4457        }
4458        out.setTo(cur);
4459        mHistoryIterator = cur.next;
4460        if (!mReadOverflow) {
4461            if (end) {
4462                Slog.w(TAG, "New history ends before old history!");
4463            } else if (!out.same(mHistoryReadTmp)) {
4464                long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
4465                PrintWriter pw = new FastPrintWriter(new LogWriter(android.util.Log.WARN, TAG));
4466                pw.println("Histories differ!");
4467                pw.println("Old history:");
4468                (new HistoryPrinter()).printNextItem(pw, out, now);
4469                pw.println("New history:");
4470                (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, now);
4471                pw.flush();
4472            }
4473        }
4474        return true;
4475    }
4476
4477    @Override
4478    public void finishIteratingOldHistoryLocked() {
4479        mIteratingHistory = false;
4480        mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
4481    }
4482
4483    @Override
4484    public boolean startIteratingHistoryLocked() {
4485        if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
4486                + " pos=" + mHistoryBuffer.dataPosition());
4487        mHistoryBuffer.setDataPosition(0);
4488        mReadOverflow = false;
4489        mIteratingHistory = true;
4490        return mHistoryBuffer.dataSize() > 0;
4491    }
4492
4493    @Override
4494    public boolean getNextHistoryLocked(HistoryItem out) {
4495        final int pos = mHistoryBuffer.dataPosition();
4496        if (pos == 0) {
4497            out.clear();
4498        }
4499        boolean end = pos >= mHistoryBuffer.dataSize();
4500        if (end) {
4501            return false;
4502        }
4503
4504        out.readDelta(mHistoryBuffer);
4505        return true;
4506    }
4507
4508    @Override
4509    public void finishIteratingHistoryLocked() {
4510        mIteratingHistory = false;
4511        mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
4512    }
4513
4514    @Override
4515    public long getHistoryBaseTime() {
4516        return mHistoryBaseTime;
4517    }
4518
4519    @Override
4520    public int getStartCount() {
4521        return mStartCount;
4522    }
4523
4524    public boolean isOnBattery() {
4525        return mOnBattery;
4526    }
4527
4528    public boolean isScreenOn() {
4529        return mScreenOn;
4530    }
4531
4532    void initTimes() {
4533        mBatteryRealtime = mTrackBatteryPastUptime = 0;
4534        mBatteryUptime = mTrackBatteryPastRealtime = 0;
4535        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
4536        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
4537        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
4538        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
4539    }
4540
4541    void initDischarge() {
4542        mLowDischargeAmountSinceCharge = 0;
4543        mHighDischargeAmountSinceCharge = 0;
4544        mDischargeAmountScreenOn = 0;
4545        mDischargeAmountScreenOnSinceCharge = 0;
4546        mDischargeAmountScreenOff = 0;
4547        mDischargeAmountScreenOffSinceCharge = 0;
4548    }
4549
4550    public void resetAllStatsLocked() {
4551        mStartCount = 0;
4552        initTimes();
4553        mScreenOnTimer.reset(this, false);
4554        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4555            mScreenBrightnessTimer[i].reset(this, false);
4556        }
4557        mInputEventCounter.reset(false);
4558        mPhoneOnTimer.reset(this, false);
4559        mAudioOnTimer.reset(this, false);
4560        mVideoOnTimer.reset(this, false);
4561        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
4562            mPhoneSignalStrengthsTimer[i].reset(this, false);
4563        }
4564        mPhoneSignalScanningTimer.reset(this, false);
4565        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4566            mPhoneDataConnectionsTimer[i].reset(this, false);
4567        }
4568        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
4569            mNetworkActivityCounters[i].reset(false);
4570        }
4571        mWifiOnTimer.reset(this, false);
4572        mGlobalWifiRunningTimer.reset(this, false);
4573        mBluetoothOnTimer.reset(this, false);
4574
4575        for (int i=0; i<mUidStats.size(); i++) {
4576            if (mUidStats.valueAt(i).reset()) {
4577                mUidStats.remove(mUidStats.keyAt(i));
4578                i--;
4579            }
4580        }
4581
4582        if (mKernelWakelockStats.size() > 0) {
4583            for (SamplingTimer timer : mKernelWakelockStats.values()) {
4584                mUnpluggables.remove(timer);
4585            }
4586            mKernelWakelockStats.clear();
4587        }
4588
4589        initDischarge();
4590
4591        clearHistoryLocked();
4592    }
4593
4594    void updateDischargeScreenLevelsLocked(boolean oldScreenOn, boolean newScreenOn) {
4595        if (oldScreenOn) {
4596            int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
4597            if (diff > 0) {
4598                mDischargeAmountScreenOn += diff;
4599                mDischargeAmountScreenOnSinceCharge += diff;
4600            }
4601        } else {
4602            int diff = mDischargeScreenOffUnplugLevel - mDischargeCurrentLevel;
4603            if (diff > 0) {
4604                mDischargeAmountScreenOff += diff;
4605                mDischargeAmountScreenOffSinceCharge += diff;
4606            }
4607        }
4608        if (newScreenOn) {
4609            mDischargeScreenOnUnplugLevel = mDischargeCurrentLevel;
4610            mDischargeScreenOffUnplugLevel = 0;
4611        } else {
4612            mDischargeScreenOnUnplugLevel = 0;
4613            mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
4614        }
4615    }
4616
4617    void setOnBattery(boolean onBattery, int oldStatus, int level) {
4618        synchronized(this) {
4619            setOnBatteryLocked(onBattery, oldStatus, level);
4620        }
4621    }
4622
4623    void setOnBatteryLocked(boolean onBattery, int oldStatus, int level) {
4624        boolean doWrite = false;
4625        Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
4626        m.arg1 = onBattery ? 1 : 0;
4627        mHandler.sendMessage(m);
4628        mOnBattery = mOnBatteryInternal = onBattery;
4629
4630        long uptime = SystemClock.uptimeMillis() * 1000;
4631        long mSecRealtime = SystemClock.elapsedRealtime();
4632        long realtime = mSecRealtime * 1000;
4633        if (onBattery) {
4634            // We will reset our status if we are unplugging after the
4635            // battery was last full, or the level is at 100, or
4636            // we have gone through a significant charge (from a very low
4637            // level to a now very high level).
4638            if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
4639                    || level >= 90
4640                    || (mDischargeCurrentLevel < 20 && level >= 80)) {
4641                doWrite = true;
4642                resetAllStatsLocked();
4643                mDischargeStartLevel = level;
4644            }
4645            updateKernelWakelocksLocked();
4646            updateNetworkActivityLocked();
4647            mHistoryCur.batteryLevel = (byte)level;
4648            mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4649            if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
4650                    + Integer.toHexString(mHistoryCur.states));
4651            addHistoryRecordLocked(mSecRealtime);
4652            mTrackBatteryUptimeStart = uptime;
4653            mTrackBatteryRealtimeStart = realtime;
4654            mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
4655            mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
4656            mDischargeCurrentLevel = mDischargeUnplugLevel = level;
4657            if (mScreenOn) {
4658                mDischargeScreenOnUnplugLevel = level;
4659                mDischargeScreenOffUnplugLevel = 0;
4660            } else {
4661                mDischargeScreenOnUnplugLevel = 0;
4662                mDischargeScreenOffUnplugLevel = level;
4663            }
4664            mDischargeAmountScreenOn = 0;
4665            mDischargeAmountScreenOff = 0;
4666            doUnplugLocked(realtime, mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
4667        } else {
4668            updateKernelWakelocksLocked();
4669            updateNetworkActivityLocked();
4670            mHistoryCur.batteryLevel = (byte)level;
4671            mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4672            if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
4673                    + Integer.toHexString(mHistoryCur.states));
4674            addHistoryRecordLocked(mSecRealtime);
4675            mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
4676            mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
4677            mDischargeCurrentLevel = level;
4678            if (level < mDischargeUnplugLevel) {
4679                mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
4680                mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
4681            }
4682            updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
4683            doPlugLocked(realtime, getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
4684        }
4685        if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
4686            if (mFile != null) {
4687                writeAsyncLocked();
4688            }
4689        }
4690    }
4691
4692    // This should probably be exposed in the API, though it's not critical
4693    private static final int BATTERY_PLUGGED_NONE = 0;
4694
4695    public void setBatteryState(int status, int health, int plugType, int level,
4696            int temp, int volt) {
4697        synchronized(this) {
4698            boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
4699            int oldStatus = mHistoryCur.batteryStatus;
4700            if (!mHaveBatteryLevel) {
4701                mHaveBatteryLevel = true;
4702                // We start out assuming that the device is plugged in (not
4703                // on battery).  If our first report is now that we are indeed
4704                // plugged in, then twiddle our state to correctly reflect that
4705                // since we won't be going through the full setOnBattery().
4706                if (onBattery == mOnBattery) {
4707                    if (onBattery) {
4708                        mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4709                    } else {
4710                        mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4711                    }
4712                }
4713                oldStatus = status;
4714            }
4715            if (onBattery) {
4716                mDischargeCurrentLevel = level;
4717                mRecordingHistory = true;
4718            }
4719            if (onBattery != mOnBattery) {
4720                mHistoryCur.batteryLevel = (byte)level;
4721                mHistoryCur.batteryStatus = (byte)status;
4722                mHistoryCur.batteryHealth = (byte)health;
4723                mHistoryCur.batteryPlugType = (byte)plugType;
4724                mHistoryCur.batteryTemperature = (char)temp;
4725                mHistoryCur.batteryVoltage = (char)volt;
4726                setOnBatteryLocked(onBattery, oldStatus, level);
4727            } else {
4728                boolean changed = false;
4729                if (mHistoryCur.batteryLevel != level) {
4730                    mHistoryCur.batteryLevel = (byte)level;
4731                    changed = true;
4732                }
4733                if (mHistoryCur.batteryStatus != status) {
4734                    mHistoryCur.batteryStatus = (byte)status;
4735                    changed = true;
4736                }
4737                if (mHistoryCur.batteryHealth != health) {
4738                    mHistoryCur.batteryHealth = (byte)health;
4739                    changed = true;
4740                }
4741                if (mHistoryCur.batteryPlugType != plugType) {
4742                    mHistoryCur.batteryPlugType = (byte)plugType;
4743                    changed = true;
4744                }
4745                if (temp >= (mHistoryCur.batteryTemperature+10)
4746                        || temp <= (mHistoryCur.batteryTemperature-10)) {
4747                    mHistoryCur.batteryTemperature = (char)temp;
4748                    changed = true;
4749                }
4750                if (volt > (mHistoryCur.batteryVoltage+20)
4751                        || volt < (mHistoryCur.batteryVoltage-20)) {
4752                    mHistoryCur.batteryVoltage = (char)volt;
4753                    changed = true;
4754                }
4755                if (changed) {
4756                    addHistoryRecordLocked(SystemClock.elapsedRealtime());
4757                }
4758            }
4759            if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
4760                // We don't record history while we are plugged in and fully charged.
4761                // The next time we are unplugged, history will be cleared.
4762                mRecordingHistory = false;
4763            }
4764        }
4765    }
4766
4767    public void updateKernelWakelocksLocked() {
4768        Map<String, KernelWakelockStats> m = readKernelWakelockStats();
4769
4770        if (m == null) {
4771            // Not crashing might make board bringup easier.
4772            Slog.w(TAG, "Couldn't get kernel wake lock stats");
4773            return;
4774        }
4775
4776        for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
4777            String name = ent.getKey();
4778            KernelWakelockStats kws = ent.getValue();
4779
4780            SamplingTimer kwlt = mKernelWakelockStats.get(name);
4781            if (kwlt == null) {
4782                kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
4783                        true /* track reported values */);
4784                mKernelWakelockStats.put(name, kwlt);
4785            }
4786            kwlt.updateCurrentReportedCount(kws.mCount);
4787            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
4788            kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
4789        }
4790
4791        if (m.size() != mKernelWakelockStats.size()) {
4792            // Set timers to stale if they didn't appear in /proc/wakelocks this time.
4793            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
4794                SamplingTimer st = ent.getValue();
4795                if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
4796                    st.setStale();
4797                }
4798            }
4799        }
4800    }
4801
4802    private void updateNetworkActivityLocked() {
4803        if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return;
4804
4805        final NetworkStats snapshot;
4806        try {
4807            snapshot = mNetworkStatsFactory.readNetworkStatsDetail();
4808        } catch (IOException e) {
4809            Log.wtf(TAG, "Failed to read network stats", e);
4810            return;
4811        }
4812
4813        if (mLastSnapshot == null) {
4814            mLastSnapshot = snapshot;
4815            return;
4816        }
4817
4818        final NetworkStats delta = snapshot.subtract(mLastSnapshot);
4819        mLastSnapshot = snapshot;
4820
4821        NetworkStats.Entry entry = null;
4822        final int size = delta.size();
4823        for (int i = 0; i < size; i++) {
4824            entry = delta.getValues(i, entry);
4825
4826            if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
4827            if (entry.tag != NetworkStats.TAG_NONE) continue;
4828
4829            final Uid u = getUidStatsLocked(entry.uid);
4830
4831            if (mMobileIfaces.contains(entry.iface)) {
4832                u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_BYTES, entry.rxBytes);
4833                u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_BYTES, entry.txBytes);
4834
4835                mNetworkActivityCounters[NETWORK_MOBILE_RX_BYTES].addCountLocked(entry.rxBytes);
4836                mNetworkActivityCounters[NETWORK_MOBILE_TX_BYTES].addCountLocked(entry.txBytes);
4837
4838            } else if (mWifiIfaces.contains(entry.iface)) {
4839                u.noteNetworkActivityLocked(NETWORK_WIFI_RX_BYTES, entry.rxBytes);
4840                u.noteNetworkActivityLocked(NETWORK_WIFI_TX_BYTES, entry.txBytes);
4841
4842                mNetworkActivityCounters[NETWORK_WIFI_RX_BYTES].addCountLocked(entry.rxBytes);
4843                mNetworkActivityCounters[NETWORK_WIFI_TX_BYTES].addCountLocked(entry.txBytes);
4844            }
4845        }
4846    }
4847
4848    public long getAwakeTimeBattery() {
4849        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
4850    }
4851
4852    public long getAwakeTimePlugged() {
4853        return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
4854    }
4855
4856    @Override
4857    public long computeUptime(long curTime, int which) {
4858        switch (which) {
4859            case STATS_SINCE_CHARGED: return mUptime + (curTime-mUptimeStart);
4860            case STATS_LAST: return mLastUptime;
4861            case STATS_CURRENT: return (curTime-mUptimeStart);
4862            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
4863        }
4864        return 0;
4865    }
4866
4867    @Override
4868    public long computeRealtime(long curTime, int which) {
4869        switch (which) {
4870            case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
4871            case STATS_LAST: return mLastRealtime;
4872            case STATS_CURRENT: return (curTime-mRealtimeStart);
4873            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
4874        }
4875        return 0;
4876    }
4877
4878    @Override
4879    public long computeBatteryUptime(long curTime, int which) {
4880        switch (which) {
4881            case STATS_SINCE_CHARGED:
4882                return mBatteryUptime + getBatteryUptime(curTime);
4883            case STATS_LAST:
4884                return mBatteryLastUptime;
4885            case STATS_CURRENT:
4886                return getBatteryUptime(curTime);
4887            case STATS_SINCE_UNPLUGGED:
4888                return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
4889        }
4890        return 0;
4891    }
4892
4893    @Override
4894    public long computeBatteryRealtime(long curTime, int which) {
4895        switch (which) {
4896            case STATS_SINCE_CHARGED:
4897                return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
4898            case STATS_LAST:
4899                return mBatteryLastRealtime;
4900            case STATS_CURRENT:
4901                return getBatteryRealtimeLocked(curTime);
4902            case STATS_SINCE_UNPLUGGED:
4903                return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
4904        }
4905        return 0;
4906    }
4907
4908    long getBatteryUptimeLocked(long curTime) {
4909        long time = mTrackBatteryPastUptime;
4910        if (mOnBatteryInternal) {
4911            time += curTime - mTrackBatteryUptimeStart;
4912        }
4913        return time;
4914    }
4915
4916    long getBatteryUptimeLocked() {
4917        return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
4918    }
4919
4920    @Override
4921    public long getBatteryUptime(long curTime) {
4922        return getBatteryUptimeLocked(curTime);
4923    }
4924
4925    long getBatteryRealtimeLocked(long curTime) {
4926        long time = mTrackBatteryPastRealtime;
4927        if (mOnBatteryInternal) {
4928            time += curTime - mTrackBatteryRealtimeStart;
4929        }
4930        return time;
4931    }
4932
4933    @Override
4934    public long getBatteryRealtime(long curTime) {
4935        return getBatteryRealtimeLocked(curTime);
4936    }
4937
4938    @Override
4939    public int getDischargeStartLevel() {
4940        synchronized(this) {
4941            return getDischargeStartLevelLocked();
4942        }
4943    }
4944
4945    public int getDischargeStartLevelLocked() {
4946            return mDischargeUnplugLevel;
4947    }
4948
4949    @Override
4950    public int getDischargeCurrentLevel() {
4951        synchronized(this) {
4952            return getDischargeCurrentLevelLocked();
4953        }
4954    }
4955
4956    public int getDischargeCurrentLevelLocked() {
4957        return mDischargeCurrentLevel;
4958    }
4959
4960    @Override
4961    public int getLowDischargeAmountSinceCharge() {
4962        synchronized(this) {
4963            int val = mLowDischargeAmountSinceCharge;
4964            if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
4965                val += mDischargeUnplugLevel-mDischargeCurrentLevel-1;
4966            }
4967            return val;
4968        }
4969    }
4970
4971    @Override
4972    public int getHighDischargeAmountSinceCharge() {
4973        synchronized(this) {
4974            int val = mHighDischargeAmountSinceCharge;
4975            if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
4976                val += mDischargeUnplugLevel-mDischargeCurrentLevel;
4977            }
4978            return val;
4979        }
4980    }
4981
4982    public int getDischargeAmountScreenOn() {
4983        synchronized(this) {
4984            int val = mDischargeAmountScreenOn;
4985            if (mOnBattery && mScreenOn
4986                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
4987                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
4988            }
4989            return val;
4990        }
4991    }
4992
4993    public int getDischargeAmountScreenOnSinceCharge() {
4994        synchronized(this) {
4995            int val = mDischargeAmountScreenOnSinceCharge;
4996            if (mOnBattery && mScreenOn
4997                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
4998                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
4999            }
5000            return val;
5001        }
5002    }
5003
5004    public int getDischargeAmountScreenOff() {
5005        synchronized(this) {
5006            int val = mDischargeAmountScreenOff;
5007            if (mOnBattery && !mScreenOn
5008                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
5009                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
5010            }
5011            return val;
5012        }
5013    }
5014
5015    public int getDischargeAmountScreenOffSinceCharge() {
5016        synchronized(this) {
5017            int val = mDischargeAmountScreenOffSinceCharge;
5018            if (mOnBattery && !mScreenOn
5019                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
5020                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
5021            }
5022            return val;
5023        }
5024    }
5025
5026    @Override
5027    public int getCpuSpeedSteps() {
5028        return sNumSpeedSteps;
5029    }
5030
5031    /**
5032     * Retrieve the statistics object for a particular uid, creating if needed.
5033     */
5034    public Uid getUidStatsLocked(int uid) {
5035        Uid u = mUidStats.get(uid);
5036        if (u == null) {
5037            u = new Uid(uid);
5038            mUidStats.put(uid, u);
5039        }
5040        return u;
5041    }
5042
5043    /**
5044     * Remove the statistics object for a particular uid.
5045     */
5046    public void removeUidStatsLocked(int uid) {
5047        mUidStats.remove(uid);
5048    }
5049
5050    /**
5051     * Retrieve the statistics object for a particular process, creating
5052     * if needed.
5053     */
5054    public Uid.Proc getProcessStatsLocked(int uid, String name) {
5055        Uid u = getUidStatsLocked(uid);
5056        return u.getProcessStatsLocked(name);
5057    }
5058
5059    /**
5060     * Retrieve the statistics object for a particular process, given
5061     * the name of the process.
5062     * @param name process name
5063     * @return the statistics object for the process
5064     */
5065    public Uid.Proc getProcessStatsLocked(String name, int pid) {
5066        int uid;
5067        if (mUidCache.containsKey(name)) {
5068            uid = mUidCache.get(name);
5069        } else {
5070            uid = Process.getUidForPid(pid);
5071            mUidCache.put(name, uid);
5072        }
5073        Uid u = getUidStatsLocked(uid);
5074        return u.getProcessStatsLocked(name);
5075    }
5076
5077    /**
5078     * Retrieve the statistics object for a particular process, creating
5079     * if needed.
5080     */
5081    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
5082        Uid u = getUidStatsLocked(uid);
5083        return u.getPackageStatsLocked(pkg);
5084    }
5085
5086    /**
5087     * Retrieve the statistics object for a particular service, creating
5088     * if needed.
5089     */
5090    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
5091        Uid u = getUidStatsLocked(uid);
5092        return u.getServiceStatsLocked(pkg, name);
5093    }
5094
5095    /**
5096     * Massage data to distribute any reasonable work down to more specific
5097     * owners.  Must only be called on a dead BatteryStats object!
5098     */
5099    public void distributeWorkLocked(int which) {
5100        // Aggregate all CPU time associated with WIFI.
5101        Uid wifiUid = mUidStats.get(Process.WIFI_UID);
5102        if (wifiUid != null) {
5103            long uSecTime = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
5104            for (Uid.Proc proc : wifiUid.mProcessStats.values()) {
5105                long totalRunningTime = getGlobalWifiRunningTime(uSecTime, which);
5106                for (int i=0; i<mUidStats.size(); i++) {
5107                    Uid uid = mUidStats.valueAt(i);
5108                    if (uid.mUid != Process.WIFI_UID) {
5109                        long uidRunningTime = uid.getWifiRunningTime(uSecTime, which);
5110                        if (uidRunningTime > 0) {
5111                            Uid.Proc uidProc = uid.getProcessStatsLocked("*wifi*");
5112                            long time = proc.getUserTime(which);
5113                            time = (time*uidRunningTime)/totalRunningTime;
5114                            uidProc.mUserTime += time;
5115                            proc.mUserTime -= time;
5116                            time = proc.getSystemTime(which);
5117                            time = (time*uidRunningTime)/totalRunningTime;
5118                            uidProc.mSystemTime += time;
5119                            proc.mSystemTime -= time;
5120                            time = proc.getForegroundTime(which);
5121                            time = (time*uidRunningTime)/totalRunningTime;
5122                            uidProc.mForegroundTime += time;
5123                            proc.mForegroundTime -= time;
5124                            for (int sb=0; sb<proc.mSpeedBins.length; sb++) {
5125                                SamplingCounter sc = proc.mSpeedBins[sb];
5126                                if (sc != null) {
5127                                    time = sc.getCountLocked(which);
5128                                    time = (time*uidRunningTime)/totalRunningTime;
5129                                    SamplingCounter uidSc = uidProc.mSpeedBins[sb];
5130                                    if (uidSc == null) {
5131                                        uidSc = new SamplingCounter(mUnpluggables);
5132                                        uidProc.mSpeedBins[sb] = uidSc;
5133                                    }
5134                                    uidSc.mCount.addAndGet((int)time);
5135                                    sc.mCount.addAndGet((int)-time);
5136                                }
5137                            }
5138                            totalRunningTime -= uidRunningTime;
5139                        }
5140                    }
5141                }
5142            }
5143        }
5144    }
5145
5146    public void shutdownLocked() {
5147        writeSyncLocked();
5148        mShuttingDown = true;
5149    }
5150
5151    Parcel mPendingWrite = null;
5152    final ReentrantLock mWriteLock = new ReentrantLock();
5153
5154    public void writeAsyncLocked() {
5155        writeLocked(false);
5156    }
5157
5158    public void writeSyncLocked() {
5159        writeLocked(true);
5160    }
5161
5162    void writeLocked(boolean sync) {
5163        if (mFile == null) {
5164            Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
5165            return;
5166        }
5167
5168        if (mShuttingDown) {
5169            return;
5170        }
5171
5172        Parcel out = Parcel.obtain();
5173        writeSummaryToParcel(out);
5174        mLastWriteTime = SystemClock.elapsedRealtime();
5175
5176        if (mPendingWrite != null) {
5177            mPendingWrite.recycle();
5178        }
5179        mPendingWrite = out;
5180
5181        if (sync) {
5182            commitPendingDataToDisk();
5183        } else {
5184            Thread thr = new Thread("BatteryStats-Write") {
5185                @Override
5186                public void run() {
5187                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
5188                    commitPendingDataToDisk();
5189                }
5190            };
5191            thr.start();
5192        }
5193    }
5194
5195    public void commitPendingDataToDisk() {
5196        final Parcel next;
5197        synchronized (this) {
5198            next = mPendingWrite;
5199            mPendingWrite = null;
5200            if (next == null) {
5201                return;
5202            }
5203
5204            mWriteLock.lock();
5205        }
5206
5207        try {
5208            FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
5209            stream.write(next.marshall());
5210            stream.flush();
5211            FileUtils.sync(stream);
5212            stream.close();
5213            mFile.commit();
5214        } catch (IOException e) {
5215            Slog.w("BatteryStats", "Error writing battery statistics", e);
5216            mFile.rollback();
5217        } finally {
5218            next.recycle();
5219            mWriteLock.unlock();
5220        }
5221    }
5222
5223    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
5224        int pos = 0;
5225        int avail = stream.available();
5226        byte[] data = new byte[avail];
5227        while (true) {
5228            int amt = stream.read(data, pos, data.length-pos);
5229            //Log.i("foo", "Read " + amt + " bytes at " + pos
5230            //        + " of avail " + data.length);
5231            if (amt <= 0) {
5232                //Log.i("foo", "**** FINISHED READING: pos=" + pos
5233                //        + " len=" + data.length);
5234                return data;
5235            }
5236            pos += amt;
5237            avail = stream.available();
5238            if (avail > data.length-pos) {
5239                byte[] newData = new byte[pos+avail];
5240                System.arraycopy(data, 0, newData, 0, pos);
5241                data = newData;
5242            }
5243        }
5244    }
5245
5246    public void readLocked() {
5247        if (mFile == null) {
5248            Slog.w("BatteryStats", "readLocked: no file associated with this instance");
5249            return;
5250        }
5251
5252        mUidStats.clear();
5253
5254        try {
5255            File file = mFile.chooseForRead();
5256            if (!file.exists()) {
5257                return;
5258            }
5259            FileInputStream stream = new FileInputStream(file);
5260
5261            byte[] raw = readFully(stream);
5262            Parcel in = Parcel.obtain();
5263            in.unmarshall(raw, 0, raw.length);
5264            in.setDataPosition(0);
5265            stream.close();
5266
5267            readSummaryFromParcel(in);
5268        } catch(java.io.IOException e) {
5269            Slog.e("BatteryStats", "Error reading battery statistics", e);
5270        }
5271
5272        long now = SystemClock.elapsedRealtime();
5273        if (USE_OLD_HISTORY) {
5274            addHistoryRecordLocked(now, HistoryItem.CMD_START);
5275        }
5276        addHistoryBufferLocked(now, HistoryItem.CMD_START);
5277    }
5278
5279    public int describeContents() {
5280        return 0;
5281    }
5282
5283    void readHistory(Parcel in, boolean andOldHistory) {
5284        final long historyBaseTime = in.readLong();
5285
5286        mHistoryBuffer.setDataSize(0);
5287        mHistoryBuffer.setDataPosition(0);
5288
5289        int bufSize = in.readInt();
5290        int curPos = in.dataPosition();
5291        if (bufSize >= (MAX_MAX_HISTORY_BUFFER*3)) {
5292            Slog.w(TAG, "File corrupt: history data buffer too large " + bufSize);
5293        } else if ((bufSize&~3) != bufSize) {
5294            Slog.w(TAG, "File corrupt: history data buffer not aligned " + bufSize);
5295        } else {
5296            if (DEBUG_HISTORY) Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
5297                    + " bytes at " + curPos);
5298            mHistoryBuffer.appendFrom(in, curPos, bufSize);
5299            in.setDataPosition(curPos + bufSize);
5300        }
5301
5302        if (andOldHistory) {
5303            readOldHistory(in);
5304        }
5305
5306        if (DEBUG_HISTORY) {
5307            StringBuilder sb = new StringBuilder(128);
5308            sb.append("****************** OLD mHistoryBaseTime: ");
5309            TimeUtils.formatDuration(mHistoryBaseTime, sb);
5310            Slog.i(TAG, sb.toString());
5311        }
5312        mHistoryBaseTime = historyBaseTime;
5313        if (DEBUG_HISTORY) {
5314            StringBuilder sb = new StringBuilder(128);
5315            sb.append("****************** NEW mHistoryBaseTime: ");
5316            TimeUtils.formatDuration(mHistoryBaseTime, sb);
5317            Slog.i(TAG, sb.toString());
5318        }
5319
5320        // We are just arbitrarily going to insert 1 minute from the sample of
5321        // the last run until samples in this run.
5322        if (mHistoryBaseTime > 0) {
5323            long oldnow = SystemClock.elapsedRealtime();
5324            mHistoryBaseTime = (mHistoryBaseTime - oldnow) + 60*1000;
5325            if (DEBUG_HISTORY) {
5326                StringBuilder sb = new StringBuilder(128);
5327                sb.append("****************** ADJUSTED mHistoryBaseTime: ");
5328                TimeUtils.formatDuration(mHistoryBaseTime, sb);
5329                Slog.i(TAG, sb.toString());
5330            }
5331        }
5332    }
5333
5334    void readOldHistory(Parcel in) {
5335        if (!USE_OLD_HISTORY) {
5336            return;
5337        }
5338        mHistory = mHistoryEnd = mHistoryCache = null;
5339        long time;
5340        while (in.dataAvail() > 0 && (time=in.readLong()) >= 0) {
5341            HistoryItem rec = new HistoryItem(time, in);
5342            addHistoryRecordLocked(rec);
5343        }
5344    }
5345
5346    void writeHistory(Parcel out, boolean andOldHistory) {
5347        if (DEBUG_HISTORY) {
5348            StringBuilder sb = new StringBuilder(128);
5349            sb.append("****************** WRITING mHistoryBaseTime: ");
5350            TimeUtils.formatDuration(mHistoryBaseTime, sb);
5351            sb.append(" mLastHistoryTime: ");
5352            TimeUtils.formatDuration(mLastHistoryTime, sb);
5353            Slog.i(TAG, sb.toString());
5354        }
5355        out.writeLong(mHistoryBaseTime + mLastHistoryTime);
5356        out.writeInt(mHistoryBuffer.dataSize());
5357        if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
5358                + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
5359        out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
5360
5361        if (andOldHistory) {
5362            writeOldHistory(out);
5363        }
5364    }
5365
5366    void writeOldHistory(Parcel out) {
5367        if (!USE_OLD_HISTORY) {
5368            return;
5369        }
5370        HistoryItem rec = mHistory;
5371        while (rec != null) {
5372            if (rec.time >= 0) rec.writeToParcel(out, 0);
5373            rec = rec.next;
5374        }
5375        out.writeLong(-1);
5376    }
5377
5378    private void readSummaryFromParcel(Parcel in) {
5379        final int version = in.readInt();
5380        if (version != VERSION) {
5381            Slog.w("BatteryStats", "readFromParcel: version got " + version
5382                + ", expected " + VERSION + "; erasing old stats");
5383            return;
5384        }
5385
5386        readHistory(in, true);
5387
5388        mStartCount = in.readInt();
5389        mBatteryUptime = in.readLong();
5390        mBatteryRealtime = in.readLong();
5391        mUptime = in.readLong();
5392        mRealtime = in.readLong();
5393        mDischargeUnplugLevel = in.readInt();
5394        mDischargeCurrentLevel = in.readInt();
5395        mLowDischargeAmountSinceCharge = in.readInt();
5396        mHighDischargeAmountSinceCharge = in.readInt();
5397        mDischargeAmountScreenOnSinceCharge = in.readInt();
5398        mDischargeAmountScreenOffSinceCharge = in.readInt();
5399
5400        mStartCount++;
5401
5402        mScreenOn = false;
5403        mScreenOnTimer.readSummaryFromParcelLocked(in);
5404        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5405            mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
5406        }
5407        mInputEventCounter.readSummaryFromParcelLocked(in);
5408        mPhoneOn = false;
5409        mPhoneOnTimer.readSummaryFromParcelLocked(in);
5410        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5411            mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
5412        }
5413        mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
5414        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5415            mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
5416        }
5417        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
5418            mNetworkActivityCounters[i].readSummaryFromParcelLocked(in);
5419        }
5420        mWifiOn = false;
5421        mWifiOnTimer.readSummaryFromParcelLocked(in);
5422        mGlobalWifiRunning = false;
5423        mGlobalWifiRunningTimer.readSummaryFromParcelLocked(in);
5424        mBluetoothOn = false;
5425        mBluetoothOnTimer.readSummaryFromParcelLocked(in);
5426
5427        int NKW = in.readInt();
5428        if (NKW > 10000) {
5429            Slog.w(TAG, "File corrupt: too many kernel wake locks " + NKW);
5430            return;
5431        }
5432        for (int ikw = 0; ikw < NKW; ikw++) {
5433            if (in.readInt() != 0) {
5434                String kwltName = in.readString();
5435                getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
5436            }
5437        }
5438
5439        sNumSpeedSteps = in.readInt();
5440
5441        final int NU = in.readInt();
5442        if (NU > 10000) {
5443            Slog.w(TAG, "File corrupt: too many uids " + NU);
5444            return;
5445        }
5446        for (int iu = 0; iu < NU; iu++) {
5447            int uid = in.readInt();
5448            Uid u = new Uid(uid);
5449            mUidStats.put(uid, u);
5450
5451            u.mWifiRunning = false;
5452            if (in.readInt() != 0) {
5453                u.mWifiRunningTimer.readSummaryFromParcelLocked(in);
5454            }
5455            u.mFullWifiLockOut = false;
5456            if (in.readInt() != 0) {
5457                u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
5458            }
5459            u.mWifiScanStarted = false;
5460            if (in.readInt() != 0) {
5461                u.mWifiScanTimer.readSummaryFromParcelLocked(in);
5462            }
5463            u.mWifiMulticastEnabled = false;
5464            if (in.readInt() != 0) {
5465                u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
5466            }
5467            u.mAudioTurnedOn = false;
5468            if (in.readInt() != 0) {
5469                u.createAudioTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
5470            }
5471            u.mVideoTurnedOn = false;
5472            if (in.readInt() != 0) {
5473                u.createVideoTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
5474            }
5475            if (in.readInt() != 0) {
5476                u.createForegroundActivityTimerLocked().readSummaryFromParcelLocked(in);
5477            }
5478            if (in.readInt() != 0) {
5479                u.createVibratorOnTimerLocked().readSummaryFromParcelLocked(in);
5480            }
5481
5482            if (in.readInt() != 0) {
5483                if (u.mUserActivityCounters == null) {
5484                    u.initUserActivityLocked();
5485                }
5486                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
5487                    u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
5488                }
5489            }
5490
5491            if (in.readInt() != 0) {
5492                if (u.mNetworkActivityCounters == null) {
5493                    u.initNetworkActivityLocked();
5494                }
5495                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
5496                    u.mNetworkActivityCounters[i].readSummaryFromParcelLocked(in);
5497                }
5498            }
5499
5500            int NW = in.readInt();
5501            if (NW > 100) {
5502                Slog.w(TAG, "File corrupt: too many wake locks " + NW);
5503                return;
5504            }
5505            for (int iw = 0; iw < NW; iw++) {
5506                String wlName = in.readString();
5507                if (in.readInt() != 0) {
5508                    u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
5509                }
5510                if (in.readInt() != 0) {
5511                    u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
5512                }
5513                if (in.readInt() != 0) {
5514                    u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
5515                }
5516            }
5517
5518            int NP = in.readInt();
5519            if (NP > 1000) {
5520                Slog.w(TAG, "File corrupt: too many sensors " + NP);
5521                return;
5522            }
5523            for (int is = 0; is < NP; is++) {
5524                int seNumber = in.readInt();
5525                if (in.readInt() != 0) {
5526                    u.getSensorTimerLocked(seNumber, true)
5527                            .readSummaryFromParcelLocked(in);
5528                }
5529            }
5530
5531            NP = in.readInt();
5532            if (NP > 1000) {
5533                Slog.w(TAG, "File corrupt: too many processes " + NP);
5534                return;
5535            }
5536            for (int ip = 0; ip < NP; ip++) {
5537                String procName = in.readString();
5538                Uid.Proc p = u.getProcessStatsLocked(procName);
5539                p.mUserTime = p.mLoadedUserTime = in.readLong();
5540                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
5541                p.mForegroundTime = p.mLoadedForegroundTime = in.readLong();
5542                p.mStarts = p.mLoadedStarts = in.readInt();
5543                int NSB = in.readInt();
5544                if (NSB > 100) {
5545                    Slog.w(TAG, "File corrupt: too many speed bins " + NSB);
5546                    return;
5547                }
5548                p.mSpeedBins = new SamplingCounter[NSB];
5549                for (int i=0; i<NSB; i++) {
5550                    if (in.readInt() != 0) {
5551                        p.mSpeedBins[i] = new SamplingCounter(mUnpluggables);
5552                        p.mSpeedBins[i].readSummaryFromParcelLocked(in);
5553                    }
5554                }
5555                if (!p.readExcessivePowerFromParcelLocked(in)) {
5556                    return;
5557                }
5558            }
5559
5560            NP = in.readInt();
5561            if (NP > 10000) {
5562                Slog.w(TAG, "File corrupt: too many packages " + NP);
5563                return;
5564            }
5565            for (int ip = 0; ip < NP; ip++) {
5566                String pkgName = in.readString();
5567                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
5568                p.mWakeups = p.mLoadedWakeups = in.readInt();
5569                final int NS = in.readInt();
5570                if (NS > 1000) {
5571                    Slog.w(TAG, "File corrupt: too many services " + NS);
5572                    return;
5573                }
5574                for (int is = 0; is < NS; is++) {
5575                    String servName = in.readString();
5576                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
5577                    s.mStartTime = s.mLoadedStartTime = in.readLong();
5578                    s.mStarts = s.mLoadedStarts = in.readInt();
5579                    s.mLaunches = s.mLoadedLaunches = in.readInt();
5580                }
5581            }
5582        }
5583    }
5584
5585    /**
5586     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
5587     * disk.  This format does not allow a lossless round-trip.
5588     *
5589     * @param out the Parcel to be written to.
5590     */
5591    public void writeSummaryToParcel(Parcel out) {
5592        // Need to update with current kernel wake lock counts.
5593        updateKernelWakelocksLocked();
5594        updateNetworkActivityLocked();
5595
5596        final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
5597        final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
5598        final long NOW = getBatteryUptimeLocked(NOW_SYS);
5599        final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
5600
5601        out.writeInt(VERSION);
5602
5603        writeHistory(out, true);
5604
5605        out.writeInt(mStartCount);
5606        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_SINCE_CHARGED));
5607        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
5608        out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
5609        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
5610        out.writeInt(mDischargeUnplugLevel);
5611        out.writeInt(mDischargeCurrentLevel);
5612        out.writeInt(getLowDischargeAmountSinceCharge());
5613        out.writeInt(getHighDischargeAmountSinceCharge());
5614        out.writeInt(getDischargeAmountScreenOnSinceCharge());
5615        out.writeInt(getDischargeAmountScreenOffSinceCharge());
5616
5617        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5618        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5619            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
5620        }
5621        mInputEventCounter.writeSummaryFromParcelLocked(out);
5622        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5623        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5624            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
5625        }
5626        mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5627        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5628            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
5629        }
5630        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
5631            mNetworkActivityCounters[i].writeSummaryFromParcelLocked(out);
5632        }
5633        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5634        mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5635        mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5636
5637        out.writeInt(mKernelWakelockStats.size());
5638        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
5639            Timer kwlt = ent.getValue();
5640            if (kwlt != null) {
5641                out.writeInt(1);
5642                out.writeString(ent.getKey());
5643                ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
5644            } else {
5645                out.writeInt(0);
5646            }
5647        }
5648
5649        out.writeInt(sNumSpeedSteps);
5650        final int NU = mUidStats.size();
5651        out.writeInt(NU);
5652        for (int iu = 0; iu < NU; iu++) {
5653            out.writeInt(mUidStats.keyAt(iu));
5654            Uid u = mUidStats.valueAt(iu);
5655
5656            if (u.mWifiRunningTimer != null) {
5657                out.writeInt(1);
5658                u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5659            } else {
5660                out.writeInt(0);
5661            }
5662            if (u.mFullWifiLockTimer != null) {
5663                out.writeInt(1);
5664                u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5665            } else {
5666                out.writeInt(0);
5667            }
5668            if (u.mWifiScanTimer != null) {
5669                out.writeInt(1);
5670                u.mWifiScanTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5671            } else {
5672                out.writeInt(0);
5673            }
5674            if (u.mWifiMulticastTimer != null) {
5675                out.writeInt(1);
5676                u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5677            } else {
5678                out.writeInt(0);
5679            }
5680            if (u.mAudioTurnedOnTimer != null) {
5681                out.writeInt(1);
5682                u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5683            } else {
5684                out.writeInt(0);
5685            }
5686            if (u.mVideoTurnedOnTimer != null) {
5687                out.writeInt(1);
5688                u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5689            } else {
5690                out.writeInt(0);
5691            }
5692            if (u.mForegroundActivityTimer != null) {
5693                out.writeInt(1);
5694                u.mForegroundActivityTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5695            } else {
5696                out.writeInt(0);
5697            }
5698            if (u.mVibratorOnTimer != null) {
5699                out.writeInt(1);
5700                u.mVibratorOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5701            } else {
5702                out.writeInt(0);
5703            }
5704
5705            if (u.mUserActivityCounters == null) {
5706                out.writeInt(0);
5707            } else {
5708                out.writeInt(1);
5709                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
5710                    u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
5711                }
5712            }
5713
5714            if (u.mNetworkActivityCounters == null) {
5715                out.writeInt(0);
5716            } else {
5717                out.writeInt(1);
5718                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
5719                    u.mNetworkActivityCounters[i].writeSummaryFromParcelLocked(out);
5720                }
5721            }
5722
5723            int NW = u.mWakelockStats.size();
5724            out.writeInt(NW);
5725            if (NW > 0) {
5726                for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
5727                        : u.mWakelockStats.entrySet()) {
5728                    out.writeString(ent.getKey());
5729                    Uid.Wakelock wl = ent.getValue();
5730                    if (wl.mTimerFull != null) {
5731                        out.writeInt(1);
5732                        wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
5733                    } else {
5734                        out.writeInt(0);
5735                    }
5736                    if (wl.mTimerPartial != null) {
5737                        out.writeInt(1);
5738                        wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
5739                    } else {
5740                        out.writeInt(0);
5741                    }
5742                    if (wl.mTimerWindow != null) {
5743                        out.writeInt(1);
5744                        wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
5745                    } else {
5746                        out.writeInt(0);
5747                    }
5748                }
5749            }
5750
5751            int NSE = u.mSensorStats.size();
5752            out.writeInt(NSE);
5753            if (NSE > 0) {
5754                for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
5755                        : u.mSensorStats.entrySet()) {
5756                    out.writeInt(ent.getKey());
5757                    Uid.Sensor se = ent.getValue();
5758                    if (se.mTimer != null) {
5759                        out.writeInt(1);
5760                        se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
5761                    } else {
5762                        out.writeInt(0);
5763                    }
5764                }
5765            }
5766
5767            int NP = u.mProcessStats.size();
5768            out.writeInt(NP);
5769            if (NP > 0) {
5770                for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
5771                    : u.mProcessStats.entrySet()) {
5772                    out.writeString(ent.getKey());
5773                    Uid.Proc ps = ent.getValue();
5774                    out.writeLong(ps.mUserTime);
5775                    out.writeLong(ps.mSystemTime);
5776                    out.writeLong(ps.mForegroundTime);
5777                    out.writeInt(ps.mStarts);
5778                    final int N = ps.mSpeedBins.length;
5779                    out.writeInt(N);
5780                    for (int i=0; i<N; i++) {
5781                        if (ps.mSpeedBins[i] != null) {
5782                            out.writeInt(1);
5783                            ps.mSpeedBins[i].writeSummaryFromParcelLocked(out);
5784                        } else {
5785                            out.writeInt(0);
5786                        }
5787                    }
5788                    ps.writeExcessivePowerToParcelLocked(out);
5789                }
5790            }
5791
5792            NP = u.mPackageStats.size();
5793            out.writeInt(NP);
5794            if (NP > 0) {
5795                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
5796                    : u.mPackageStats.entrySet()) {
5797                    out.writeString(ent.getKey());
5798                    Uid.Pkg ps = ent.getValue();
5799                    out.writeInt(ps.mWakeups);
5800                    final int NS = ps.mServiceStats.size();
5801                    out.writeInt(NS);
5802                    if (NS > 0) {
5803                        for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
5804                                : ps.mServiceStats.entrySet()) {
5805                            out.writeString(sent.getKey());
5806                            BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
5807                            long time = ss.getStartTimeToNowLocked(NOW);
5808                            out.writeLong(time);
5809                            out.writeInt(ss.mStarts);
5810                            out.writeInt(ss.mLaunches);
5811                        }
5812                    }
5813                }
5814            }
5815        }
5816    }
5817
5818    public void readFromParcel(Parcel in) {
5819        readFromParcelLocked(in);
5820    }
5821
5822    void readFromParcelLocked(Parcel in) {
5823        int magic = in.readInt();
5824        if (magic != MAGIC) {
5825            throw new ParcelFormatException("Bad magic number");
5826        }
5827
5828        readHistory(in, false);
5829
5830        mStartCount = in.readInt();
5831        mBatteryUptime = in.readLong();
5832        mBatteryLastUptime = 0;
5833        mBatteryRealtime = in.readLong();
5834        mBatteryLastRealtime = 0;
5835        mScreenOn = false;
5836        mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables, in);
5837        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5838            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i,
5839                    null, mUnpluggables, in);
5840        }
5841        mInputEventCounter = new Counter(mUnpluggables, in);
5842        mPhoneOn = false;
5843        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5844        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5845            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
5846                    null, mUnpluggables, in);
5847        }
5848        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables, in);
5849        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5850            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
5851                    null, mUnpluggables, in);
5852        }
5853        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
5854            mNetworkActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in);
5855        }
5856        mWifiOn = false;
5857        mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5858        mGlobalWifiRunning = false;
5859        mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5860        mBluetoothOn = false;
5861        mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5862        mUptime = in.readLong();
5863        mUptimeStart = in.readLong();
5864        mLastUptime = 0;
5865        mRealtime = in.readLong();
5866        mRealtimeStart = in.readLong();
5867        mLastRealtime = 0;
5868        mOnBattery = in.readInt() != 0;
5869        mOnBatteryInternal = false; // we are no longer really running.
5870        mTrackBatteryPastUptime = in.readLong();
5871        mTrackBatteryUptimeStart = in.readLong();
5872        mTrackBatteryPastRealtime = in.readLong();
5873        mTrackBatteryRealtimeStart = in.readLong();
5874        mUnpluggedBatteryUptime = in.readLong();
5875        mUnpluggedBatteryRealtime = in.readLong();
5876        mDischargeUnplugLevel = in.readInt();
5877        mDischargeCurrentLevel = in.readInt();
5878        mLowDischargeAmountSinceCharge = in.readInt();
5879        mHighDischargeAmountSinceCharge = in.readInt();
5880        mDischargeAmountScreenOn = in.readInt();
5881        mDischargeAmountScreenOnSinceCharge = in.readInt();
5882        mDischargeAmountScreenOff = in.readInt();
5883        mDischargeAmountScreenOffSinceCharge = in.readInt();
5884        mLastWriteTime = in.readLong();
5885
5886        mRadioDataUptime = in.readLong();
5887        mRadioDataStart = -1;
5888
5889        mBluetoothPingCount = in.readInt();
5890        mBluetoothPingStart = -1;
5891
5892        mKernelWakelockStats.clear();
5893        int NKW = in.readInt();
5894        for (int ikw = 0; ikw < NKW; ikw++) {
5895            if (in.readInt() != 0) {
5896                String wakelockName = in.readString();
5897                in.readInt(); // Extra 0/1 written by Timer.writeTimerToParcel
5898                SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
5899                mKernelWakelockStats.put(wakelockName, kwlt);
5900            }
5901        }
5902
5903        mPartialTimers.clear();
5904        mFullTimers.clear();
5905        mWindowTimers.clear();
5906        mWifiRunningTimers.clear();
5907        mFullWifiLockTimers.clear();
5908        mWifiScanTimers.clear();
5909        mWifiMulticastTimers.clear();
5910
5911        sNumSpeedSteps = in.readInt();
5912
5913        int numUids = in.readInt();
5914        mUidStats.clear();
5915        for (int i = 0; i < numUids; i++) {
5916            int uid = in.readInt();
5917            Uid u = new Uid(uid);
5918            u.readFromParcelLocked(mUnpluggables, in);
5919            mUidStats.append(uid, u);
5920        }
5921    }
5922
5923    public void writeToParcel(Parcel out, int flags) {
5924        writeToParcelLocked(out, true, flags);
5925    }
5926
5927    public void writeToParcelWithoutUids(Parcel out, int flags) {
5928        writeToParcelLocked(out, false, flags);
5929    }
5930
5931    @SuppressWarnings("unused")
5932    void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
5933        // Need to update with current kernel wake lock counts.
5934        updateKernelWakelocksLocked();
5935        updateNetworkActivityLocked();
5936
5937        final long uSecUptime = SystemClock.uptimeMillis() * 1000;
5938        final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
5939        final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
5940        final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
5941
5942        out.writeInt(MAGIC);
5943
5944        writeHistory(out, false);
5945
5946        out.writeInt(mStartCount);
5947        out.writeLong(mBatteryUptime);
5948        out.writeLong(mBatteryRealtime);
5949        mScreenOnTimer.writeToParcel(out, batteryRealtime);
5950        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5951            mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
5952        }
5953        mInputEventCounter.writeToParcel(out);
5954        mPhoneOnTimer.writeToParcel(out, batteryRealtime);
5955        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
5956            mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
5957        }
5958        mPhoneSignalScanningTimer.writeToParcel(out, batteryRealtime);
5959        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5960            mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
5961        }
5962        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
5963            mNetworkActivityCounters[i].writeToParcel(out);
5964        }
5965        mWifiOnTimer.writeToParcel(out, batteryRealtime);
5966        mGlobalWifiRunningTimer.writeToParcel(out, batteryRealtime);
5967        mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
5968        out.writeLong(mUptime);
5969        out.writeLong(mUptimeStart);
5970        out.writeLong(mRealtime);
5971        out.writeLong(mRealtimeStart);
5972        out.writeInt(mOnBattery ? 1 : 0);
5973        out.writeLong(batteryUptime);
5974        out.writeLong(mTrackBatteryUptimeStart);
5975        out.writeLong(batteryRealtime);
5976        out.writeLong(mTrackBatteryRealtimeStart);
5977        out.writeLong(mUnpluggedBatteryUptime);
5978        out.writeLong(mUnpluggedBatteryRealtime);
5979        out.writeInt(mDischargeUnplugLevel);
5980        out.writeInt(mDischargeCurrentLevel);
5981        out.writeInt(mLowDischargeAmountSinceCharge);
5982        out.writeInt(mHighDischargeAmountSinceCharge);
5983        out.writeInt(mDischargeAmountScreenOn);
5984        out.writeInt(mDischargeAmountScreenOnSinceCharge);
5985        out.writeInt(mDischargeAmountScreenOff);
5986        out.writeInt(mDischargeAmountScreenOffSinceCharge);
5987        out.writeLong(mLastWriteTime);
5988
5989        // Write radio uptime for data
5990        out.writeLong(getRadioDataUptime());
5991
5992        out.writeInt(getBluetoothPingCount());
5993
5994        if (inclUids) {
5995            out.writeInt(mKernelWakelockStats.size());
5996            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
5997                SamplingTimer kwlt = ent.getValue();
5998                if (kwlt != null) {
5999                    out.writeInt(1);
6000                    out.writeString(ent.getKey());
6001                    Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
6002                } else {
6003                    out.writeInt(0);
6004                }
6005            }
6006        } else {
6007            out.writeInt(0);
6008        }
6009
6010        out.writeInt(sNumSpeedSteps);
6011
6012        if (inclUids) {
6013            int size = mUidStats.size();
6014            out.writeInt(size);
6015            for (int i = 0; i < size; i++) {
6016                out.writeInt(mUidStats.keyAt(i));
6017                Uid uid = mUidStats.valueAt(i);
6018
6019                uid.writeToParcelLocked(out, batteryRealtime);
6020            }
6021        } else {
6022            out.writeInt(0);
6023        }
6024    }
6025
6026    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
6027        new Parcelable.Creator<BatteryStatsImpl>() {
6028        public BatteryStatsImpl createFromParcel(Parcel in) {
6029            return new BatteryStatsImpl(in);
6030        }
6031
6032        public BatteryStatsImpl[] newArray(int size) {
6033            return new BatteryStatsImpl[size];
6034        }
6035    };
6036
6037    public void prepareForDumpLocked() {
6038        // Need to retrieve current kernel wake lock stats before printing.
6039        updateKernelWakelocksLocked();
6040        updateNetworkActivityLocked();
6041    }
6042
6043    public void dumpLocked(PrintWriter pw, boolean isUnpluggedOnly, int reqUid) {
6044        if (DEBUG) {
6045            Printer pr = new PrintWriterPrinter(pw);
6046            pr.println("*** Screen timer:");
6047            mScreenOnTimer.logState(pr, "  ");
6048            for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
6049                pr.println("*** Screen brightness #" + i + ":");
6050                mScreenBrightnessTimer[i].logState(pr, "  ");
6051            }
6052            pr.println("*** Input event counter:");
6053            mInputEventCounter.logState(pr, "  ");
6054            pr.println("*** Phone timer:");
6055            mPhoneOnTimer.logState(pr, "  ");
6056            for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
6057                pr.println("*** Signal strength #" + i + ":");
6058                mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
6059            }
6060            pr.println("*** Signal scanning :");
6061            mPhoneSignalScanningTimer.logState(pr, "  ");
6062            for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
6063                pr.println("*** Data connection type #" + i + ":");
6064                mPhoneDataConnectionsTimer[i].logState(pr, "  ");
6065            }
6066            pr.println("*** Wifi timer:");
6067            mWifiOnTimer.logState(pr, "  ");
6068            pr.println("*** WifiRunning timer:");
6069            mGlobalWifiRunningTimer.logState(pr, "  ");
6070            pr.println("*** Bluetooth timer:");
6071            mBluetoothOnTimer.logState(pr, "  ");
6072        }
6073        super.dumpLocked(pw, isUnpluggedOnly, reqUid);
6074    }
6075}
6076