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