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