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