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