BatteryStatsImpl.java revision 3fa82a9fe89c55e4217307e06cc185812ad5a8f5
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                case TelephonyManager.NETWORK_TYPE_LTE:
1790                    bin = DATA_CONNECTION_LTE;
1791                    break;
1792                case TelephonyManager.NETWORK_TYPE_EHRPD:
1793                    bin = DATA_CONNECTION_EHRPD;
1794                    break;
1795                default:
1796                    bin = DATA_CONNECTION_OTHER;
1797                    break;
1798            }
1799        }
1800        if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
1801        if (mPhoneDataConnectionType != bin) {
1802            mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
1803                    | (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
1804            if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
1805                    + Integer.toHexString(mHistoryCur.states));
1806            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1807            if (mPhoneDataConnectionType >= 0) {
1808                mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this);
1809            }
1810            mPhoneDataConnectionType = bin;
1811            mPhoneDataConnectionsTimer[bin].startRunningLocked(this);
1812        }
1813    }
1814
1815    public void noteWifiOnLocked() {
1816        if (!mWifiOn) {
1817            mHistoryCur.states |= HistoryItem.STATE_WIFI_ON_FLAG;
1818            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
1819                    + Integer.toHexString(mHistoryCur.states));
1820            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1821            mWifiOn = true;
1822            mWifiOnTimer.startRunningLocked(this);
1823        }
1824    }
1825
1826    public void noteWifiOffLocked() {
1827        if (mWifiOn) {
1828            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_ON_FLAG;
1829            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
1830                    + Integer.toHexString(mHistoryCur.states));
1831            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1832            mWifiOn = false;
1833            mWifiOnTimer.stopRunningLocked(this);
1834        }
1835        if (mWifiOnUid >= 0) {
1836            getUidStatsLocked(mWifiOnUid).noteWifiStoppedLocked();
1837            mWifiOnUid = -1;
1838        }
1839    }
1840
1841    public void noteAudioOnLocked(int uid) {
1842        if (!mAudioOn) {
1843            mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
1844            if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
1845                    + Integer.toHexString(mHistoryCur.states));
1846            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1847            mAudioOn = true;
1848            mAudioOnTimer.startRunningLocked(this);
1849        }
1850        getUidStatsLocked(uid).noteAudioTurnedOnLocked();
1851    }
1852
1853    public void noteAudioOffLocked(int uid) {
1854        if (mAudioOn) {
1855            mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
1856            if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
1857                    + Integer.toHexString(mHistoryCur.states));
1858            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1859            mAudioOn = false;
1860            mAudioOnTimer.stopRunningLocked(this);
1861        }
1862        getUidStatsLocked(uid).noteAudioTurnedOffLocked();
1863    }
1864
1865    public void noteVideoOnLocked(int uid) {
1866        if (!mVideoOn) {
1867            mHistoryCur.states |= HistoryItem.STATE_VIDEO_ON_FLAG;
1868            if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
1869                    + Integer.toHexString(mHistoryCur.states));
1870            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1871            mVideoOn = true;
1872            mVideoOnTimer.startRunningLocked(this);
1873        }
1874        getUidStatsLocked(uid).noteVideoTurnedOnLocked();
1875    }
1876
1877    public void noteVideoOffLocked(int uid) {
1878        if (mVideoOn) {
1879            mHistoryCur.states &= ~HistoryItem.STATE_VIDEO_ON_FLAG;
1880            if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
1881                    + Integer.toHexString(mHistoryCur.states));
1882            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1883            mVideoOn = false;
1884            mVideoOnTimer.stopRunningLocked(this);
1885        }
1886        getUidStatsLocked(uid).noteVideoTurnedOffLocked();
1887    }
1888
1889    public void noteWifiRunningLocked(WorkSource ws) {
1890        if (!mGlobalWifiRunning) {
1891            mHistoryCur.states |= HistoryItem.STATE_WIFI_RUNNING_FLAG;
1892            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
1893                    + Integer.toHexString(mHistoryCur.states));
1894            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1895            mGlobalWifiRunning = true;
1896            mGlobalWifiRunningTimer.startRunningLocked(this);
1897            int N = ws.size();
1898            for (int i=0; i<N; i++) {
1899                getUidStatsLocked(ws.get(i)).noteWifiRunningLocked();
1900            }
1901        } else {
1902            Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
1903        }
1904    }
1905
1906    public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
1907        if (mGlobalWifiRunning) {
1908            int N = oldWs.size();
1909            for (int i=0; i<N; i++) {
1910                getUidStatsLocked(oldWs.get(i)).noteWifiStoppedLocked();
1911            }
1912            N = newWs.size();
1913            for (int i=0; i<N; i++) {
1914                getUidStatsLocked(newWs.get(i)).noteWifiRunningLocked();
1915            }
1916        } else {
1917            Log.w(TAG, "noteWifiRunningChangedLocked -- called while WIFI not running");
1918        }
1919    }
1920
1921    public void noteWifiStoppedLocked(WorkSource ws) {
1922        if (mGlobalWifiRunning) {
1923            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RUNNING_FLAG;
1924            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
1925                    + Integer.toHexString(mHistoryCur.states));
1926            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1927            mGlobalWifiRunning = false;
1928            mGlobalWifiRunningTimer.stopRunningLocked(this);
1929            int N = ws.size();
1930            for (int i=0; i<N; i++) {
1931                getUidStatsLocked(ws.get(i)).noteWifiStoppedLocked();
1932            }
1933        } else {
1934            Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
1935        }
1936    }
1937
1938    public void noteBluetoothOnLocked() {
1939        if (!mBluetoothOn) {
1940            mHistoryCur.states |= HistoryItem.STATE_BLUETOOTH_ON_FLAG;
1941            if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth on to: "
1942                    + Integer.toHexString(mHistoryCur.states));
1943            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1944            mBluetoothOn = true;
1945            mBluetoothOnTimer.startRunningLocked(this);
1946        }
1947    }
1948
1949    public void noteBluetoothOffLocked() {
1950        if (mBluetoothOn) {
1951            mHistoryCur.states &= ~HistoryItem.STATE_BLUETOOTH_ON_FLAG;
1952            if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth off to: "
1953                    + Integer.toHexString(mHistoryCur.states));
1954            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1955            mBluetoothOn = false;
1956            mBluetoothOnTimer.stopRunningLocked(this);
1957        }
1958    }
1959
1960    int mWifiFullLockNesting = 0;
1961
1962    public void noteFullWifiLockAcquiredLocked(int uid) {
1963        if (mWifiFullLockNesting == 0) {
1964            mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
1965            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
1966                    + Integer.toHexString(mHistoryCur.states));
1967            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1968        }
1969        mWifiFullLockNesting++;
1970        getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
1971    }
1972
1973    public void noteFullWifiLockReleasedLocked(int uid) {
1974        mWifiFullLockNesting--;
1975        if (mWifiFullLockNesting == 0) {
1976            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
1977            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
1978                    + Integer.toHexString(mHistoryCur.states));
1979            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1980        }
1981        getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
1982    }
1983
1984    int mWifiScanLockNesting = 0;
1985
1986    public void noteScanWifiLockAcquiredLocked(int uid) {
1987        if (mWifiScanLockNesting == 0) {
1988            mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_LOCK_FLAG;
1989            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock on to: "
1990                    + Integer.toHexString(mHistoryCur.states));
1991            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1992        }
1993        mWifiScanLockNesting++;
1994        getUidStatsLocked(uid).noteScanWifiLockAcquiredLocked();
1995    }
1996
1997    public void noteScanWifiLockReleasedLocked(int uid) {
1998        mWifiScanLockNesting--;
1999        if (mWifiScanLockNesting == 0) {
2000            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_LOCK_FLAG;
2001            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock off to: "
2002                    + Integer.toHexString(mHistoryCur.states));
2003            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2004        }
2005        getUidStatsLocked(uid).noteScanWifiLockReleasedLocked();
2006    }
2007
2008    int mWifiMulticastNesting = 0;
2009
2010    public void noteWifiMulticastEnabledLocked(int uid) {
2011        if (mWifiMulticastNesting == 0) {
2012            mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
2013            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
2014                    + Integer.toHexString(mHistoryCur.states));
2015            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2016        }
2017        mWifiMulticastNesting++;
2018        getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
2019    }
2020
2021    public void noteWifiMulticastDisabledLocked(int uid) {
2022        mWifiMulticastNesting--;
2023        if (mWifiMulticastNesting == 0) {
2024            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
2025            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
2026                    + Integer.toHexString(mHistoryCur.states));
2027            addHistoryRecordLocked(SystemClock.elapsedRealtime());
2028        }
2029        getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
2030    }
2031
2032    public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
2033        int N = ws.size();
2034        for (int i=0; i<N; i++) {
2035            noteFullWifiLockAcquiredLocked(ws.get(i));
2036        }
2037    }
2038
2039    public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
2040        int N = ws.size();
2041        for (int i=0; i<N; i++) {
2042            noteFullWifiLockReleasedLocked(ws.get(i));
2043        }
2044    }
2045
2046    public void noteScanWifiLockAcquiredFromSourceLocked(WorkSource ws) {
2047        int N = ws.size();
2048        for (int i=0; i<N; i++) {
2049            noteScanWifiLockAcquiredLocked(ws.get(i));
2050        }
2051    }
2052
2053    public void noteScanWifiLockReleasedFromSourceLocked(WorkSource ws) {
2054        int N = ws.size();
2055        for (int i=0; i<N; i++) {
2056            noteScanWifiLockReleasedLocked(ws.get(i));
2057        }
2058    }
2059
2060    public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
2061        int N = ws.size();
2062        for (int i=0; i<N; i++) {
2063            noteWifiMulticastEnabledLocked(ws.get(i));
2064        }
2065    }
2066
2067    public void noteWifiMulticastDisabledFromSourceLocked(WorkSource ws) {
2068        int N = ws.size();
2069        for (int i=0; i<N; i++) {
2070            noteWifiMulticastDisabledLocked(ws.get(i));
2071        }
2072    }
2073
2074    @Override public long getScreenOnTime(long batteryRealtime, int which) {
2075        return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
2076    }
2077
2078    @Override public long getScreenBrightnessTime(int brightnessBin,
2079            long batteryRealtime, int which) {
2080        return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
2081                batteryRealtime, which);
2082    }
2083
2084    @Override public int getInputEventCount(int which) {
2085        return mInputEventCounter.getCountLocked(which);
2086    }
2087
2088    @Override public long getPhoneOnTime(long batteryRealtime, int which) {
2089        return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
2090    }
2091
2092    @Override public long getPhoneSignalStrengthTime(int strengthBin,
2093            long batteryRealtime, int which) {
2094        return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
2095                batteryRealtime, which);
2096    }
2097
2098    @Override public long getPhoneSignalScanningTime(
2099            long batteryRealtime, int which) {
2100        return mPhoneSignalScanningTimer.getTotalTimeLocked(
2101                batteryRealtime, which);
2102    }
2103
2104    @Override public int getPhoneSignalStrengthCount(int dataType, int which) {
2105        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
2106    }
2107
2108    @Override public long getPhoneDataConnectionTime(int dataType,
2109            long batteryRealtime, int which) {
2110        return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
2111                batteryRealtime, which);
2112    }
2113
2114    @Override public int getPhoneDataConnectionCount(int dataType, int which) {
2115        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
2116    }
2117
2118    @Override public long getWifiOnTime(long batteryRealtime, int which) {
2119        return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
2120    }
2121
2122    @Override public long getGlobalWifiRunningTime(long batteryRealtime, int which) {
2123        return mGlobalWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
2124    }
2125
2126    @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
2127        return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
2128    }
2129
2130    @Override public boolean getIsOnBattery() {
2131        return mOnBattery;
2132    }
2133
2134    @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
2135        return mUidStats;
2136    }
2137
2138    /**
2139     * The statistics associated with a particular uid.
2140     */
2141    public final class Uid extends BatteryStats.Uid {
2142
2143        final int mUid;
2144        long mLoadedTcpBytesReceived;
2145        long mLoadedTcpBytesSent;
2146        long mCurrentTcpBytesReceived;
2147        long mCurrentTcpBytesSent;
2148        long mTcpBytesReceivedAtLastUnplug;
2149        long mTcpBytesSentAtLastUnplug;
2150
2151        // These are not saved/restored when parcelling, since we want
2152        // to return from the parcel with a snapshot of the state.
2153        long mStartedTcpBytesReceived = -1;
2154        long mStartedTcpBytesSent = -1;
2155
2156        boolean mWifiRunning;
2157        StopwatchTimer mWifiRunningTimer;
2158
2159        boolean mFullWifiLockOut;
2160        StopwatchTimer mFullWifiLockTimer;
2161
2162        boolean mScanWifiLockOut;
2163        StopwatchTimer mScanWifiLockTimer;
2164
2165        boolean mWifiMulticastEnabled;
2166        StopwatchTimer mWifiMulticastTimer;
2167
2168        boolean mAudioTurnedOn;
2169        StopwatchTimer mAudioTurnedOnTimer;
2170
2171        boolean mVideoTurnedOn;
2172        StopwatchTimer mVideoTurnedOnTimer;
2173
2174        Counter[] mUserActivityCounters;
2175
2176        /**
2177         * The statistics we have collected for this uid's wake locks.
2178         */
2179        final HashMap<String, Wakelock> mWakelockStats = new HashMap<String, Wakelock>();
2180
2181        /**
2182         * The statistics we have collected for this uid's sensor activations.
2183         */
2184        final HashMap<Integer, Sensor> mSensorStats = new HashMap<Integer, Sensor>();
2185
2186        /**
2187         * The statistics we have collected for this uid's processes.
2188         */
2189        final HashMap<String, Proc> mProcessStats = new HashMap<String, Proc>();
2190
2191        /**
2192         * The statistics we have collected for this uid's processes.
2193         */
2194        final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
2195
2196        /**
2197         * The transient wake stats we have collected for this uid's pids.
2198         */
2199        final SparseArray<Pid> mPids = new SparseArray<Pid>();
2200
2201        public Uid(int uid) {
2202            mUid = uid;
2203            mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
2204                    mWifiRunningTimers, mUnpluggables);
2205            mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
2206                    mFullWifiLockTimers, mUnpluggables);
2207            mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
2208                    mScanWifiLockTimers, mUnpluggables);
2209            mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
2210                    mWifiMulticastTimers, mUnpluggables);
2211            mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
2212                    null, mUnpluggables);
2213            mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
2214                    null, mUnpluggables);
2215        }
2216
2217        @Override
2218        public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
2219            return mWakelockStats;
2220        }
2221
2222        @Override
2223        public Map<Integer, ? extends BatteryStats.Uid.Sensor> getSensorStats() {
2224            return mSensorStats;
2225        }
2226
2227        @Override
2228        public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
2229            return mProcessStats;
2230        }
2231
2232        @Override
2233        public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
2234            return mPackageStats;
2235        }
2236
2237        @Override
2238        public int getUid() {
2239            return mUid;
2240        }
2241
2242        @Override
2243        public long getTcpBytesReceived(int which) {
2244            if (which == STATS_LAST) {
2245                return mLoadedTcpBytesReceived;
2246            } else {
2247                long current = computeCurrentTcpBytesReceived();
2248                if (which == STATS_SINCE_UNPLUGGED) {
2249                    current -= mTcpBytesReceivedAtLastUnplug;
2250                } else if (which == STATS_SINCE_CHARGED) {
2251                    current += mLoadedTcpBytesReceived;
2252                }
2253                return current;
2254            }
2255        }
2256
2257        public long computeCurrentTcpBytesReceived() {
2258            return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
2259                    ? (TrafficStats.getUidRxBytes(mUid) - mStartedTcpBytesReceived) : 0);
2260        }
2261
2262        @Override
2263        public long getTcpBytesSent(int which) {
2264            if (which == STATS_LAST) {
2265                return mLoadedTcpBytesSent;
2266            } else {
2267                long current = computeCurrentTcpBytesSent();
2268                if (which == STATS_SINCE_UNPLUGGED) {
2269                    current -= mTcpBytesSentAtLastUnplug;
2270                } else if (which == STATS_SINCE_CHARGED) {
2271                    current += mLoadedTcpBytesSent;
2272                }
2273                return current;
2274            }
2275        }
2276
2277        @Override
2278        public void noteWifiRunningLocked() {
2279            if (!mWifiRunning) {
2280                mWifiRunning = true;
2281                if (mWifiRunningTimer == null) {
2282                    mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
2283                            mWifiRunningTimers, mUnpluggables);
2284                }
2285                mWifiRunningTimer.startRunningLocked(BatteryStatsImpl.this);
2286            }
2287        }
2288
2289        @Override
2290        public void noteWifiStoppedLocked() {
2291            if (mWifiRunning) {
2292                mWifiRunning = false;
2293                mWifiRunningTimer.stopRunningLocked(BatteryStatsImpl.this);
2294            }
2295        }
2296
2297        @Override
2298        public void noteFullWifiLockAcquiredLocked() {
2299            if (!mFullWifiLockOut) {
2300                mFullWifiLockOut = true;
2301                if (mFullWifiLockTimer == null) {
2302                    mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
2303                            mFullWifiLockTimers, mUnpluggables);
2304                }
2305                mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
2306            }
2307        }
2308
2309        @Override
2310        public void noteFullWifiLockReleasedLocked() {
2311            if (mFullWifiLockOut) {
2312                mFullWifiLockOut = false;
2313                mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
2314            }
2315        }
2316
2317        @Override
2318        public void noteScanWifiLockAcquiredLocked() {
2319            if (!mScanWifiLockOut) {
2320                mScanWifiLockOut = true;
2321                if (mScanWifiLockTimer == null) {
2322                    mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
2323                            mScanWifiLockTimers, mUnpluggables);
2324                }
2325                mScanWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
2326            }
2327        }
2328
2329        @Override
2330        public void noteScanWifiLockReleasedLocked() {
2331            if (mScanWifiLockOut) {
2332                mScanWifiLockOut = false;
2333                mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
2334            }
2335        }
2336
2337        @Override
2338        public void noteWifiMulticastEnabledLocked() {
2339            if (!mWifiMulticastEnabled) {
2340                mWifiMulticastEnabled = true;
2341                if (mWifiMulticastTimer == null) {
2342                    mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
2343                            mWifiMulticastTimers, mUnpluggables);
2344                }
2345                mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
2346            }
2347        }
2348
2349        @Override
2350        public void noteWifiMulticastDisabledLocked() {
2351            if (mWifiMulticastEnabled) {
2352                mWifiMulticastEnabled = false;
2353                mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
2354            }
2355        }
2356
2357        @Override
2358        public void noteAudioTurnedOnLocked() {
2359            if (!mAudioTurnedOn) {
2360                mAudioTurnedOn = true;
2361                if (mAudioTurnedOnTimer == null) {
2362                    mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
2363                            null, mUnpluggables);
2364                }
2365                mAudioTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
2366            }
2367        }
2368
2369        @Override
2370        public void noteAudioTurnedOffLocked() {
2371            if (mAudioTurnedOn) {
2372                mAudioTurnedOn = false;
2373                mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
2374            }
2375        }
2376
2377        @Override
2378        public void noteVideoTurnedOnLocked() {
2379            if (!mVideoTurnedOn) {
2380                mVideoTurnedOn = true;
2381                if (mVideoTurnedOnTimer == null) {
2382                    mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
2383                            null, mUnpluggables);
2384                }
2385                mVideoTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
2386            }
2387        }
2388
2389        @Override
2390        public void noteVideoTurnedOffLocked() {
2391            if (mVideoTurnedOn) {
2392                mVideoTurnedOn = false;
2393                mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
2394            }
2395        }
2396
2397        @Override
2398        public long getWifiRunningTime(long batteryRealtime, int which) {
2399            if (mWifiRunningTimer == null) {
2400                return 0;
2401            }
2402            return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
2403        }
2404
2405        @Override
2406        public long getFullWifiLockTime(long batteryRealtime, int which) {
2407            if (mFullWifiLockTimer == null) {
2408                return 0;
2409            }
2410            return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
2411        }
2412
2413        @Override
2414        public long getScanWifiLockTime(long batteryRealtime, int which) {
2415            if (mScanWifiLockTimer == null) {
2416                return 0;
2417            }
2418            return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
2419        }
2420
2421        @Override
2422        public long getWifiMulticastTime(long batteryRealtime, int which) {
2423            if (mWifiMulticastTimer == null) {
2424                return 0;
2425            }
2426            return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime,
2427                                                          which);
2428        }
2429
2430        @Override
2431        public long getAudioTurnedOnTime(long batteryRealtime, int which) {
2432            if (mAudioTurnedOnTimer == null) {
2433                return 0;
2434            }
2435            return mAudioTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
2436        }
2437
2438        @Override
2439        public long getVideoTurnedOnTime(long batteryRealtime, int which) {
2440            if (mVideoTurnedOnTimer == null) {
2441                return 0;
2442            }
2443            return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
2444        }
2445
2446        @Override
2447        public void noteUserActivityLocked(int type) {
2448            if (mUserActivityCounters == null) {
2449                initUserActivityLocked();
2450            }
2451            if (type < 0) type = 0;
2452            else if (type >= NUM_USER_ACTIVITY_TYPES) type = NUM_USER_ACTIVITY_TYPES-1;
2453            mUserActivityCounters[type].stepAtomic();
2454        }
2455
2456        @Override
2457        public boolean hasUserActivity() {
2458            return mUserActivityCounters != null;
2459        }
2460
2461        @Override
2462        public int getUserActivityCount(int type, int which) {
2463            if (mUserActivityCounters == null) {
2464                return 0;
2465            }
2466            return mUserActivityCounters[type].getCountLocked(which);
2467        }
2468
2469        void initUserActivityLocked() {
2470            mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
2471            for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2472                mUserActivityCounters[i] = new Counter(mUnpluggables);
2473            }
2474        }
2475
2476        public long computeCurrentTcpBytesSent() {
2477            return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
2478                    ? (TrafficStats.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
2479        }
2480
2481        /**
2482         * Clear all stats for this uid.  Returns true if the uid is completely
2483         * inactive so can be dropped.
2484         */
2485        boolean reset() {
2486            boolean active = false;
2487
2488            if (mWifiRunningTimer != null) {
2489                active |= !mWifiRunningTimer.reset(BatteryStatsImpl.this, false);
2490                active |= mWifiRunning;
2491            }
2492            if (mFullWifiLockTimer != null) {
2493                active |= !mFullWifiLockTimer.reset(BatteryStatsImpl.this, false);
2494                active |= mFullWifiLockOut;
2495            }
2496            if (mScanWifiLockTimer != null) {
2497                active |= !mScanWifiLockTimer.reset(BatteryStatsImpl.this, false);
2498                active |= mScanWifiLockOut;
2499            }
2500            if (mWifiMulticastTimer != null) {
2501                active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
2502                active |= mWifiMulticastEnabled;
2503            }
2504            if (mAudioTurnedOnTimer != null) {
2505                active |= !mAudioTurnedOnTimer.reset(BatteryStatsImpl.this, false);
2506                active |= mAudioTurnedOn;
2507            }
2508            if (mVideoTurnedOnTimer != null) {
2509                active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
2510                active |= mVideoTurnedOn;
2511            }
2512
2513            mLoadedTcpBytesReceived = mLoadedTcpBytesSent = 0;
2514            mCurrentTcpBytesReceived = mCurrentTcpBytesSent = 0;
2515
2516            if (mUserActivityCounters != null) {
2517                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2518                    mUserActivityCounters[i].reset(false);
2519                }
2520            }
2521
2522            if (mWakelockStats.size() > 0) {
2523                Iterator<Map.Entry<String, Wakelock>> it = mWakelockStats.entrySet().iterator();
2524                while (it.hasNext()) {
2525                    Map.Entry<String, Wakelock> wakelockEntry = it.next();
2526                    Wakelock wl = wakelockEntry.getValue();
2527                    if (wl.reset()) {
2528                        it.remove();
2529                    } else {
2530                        active = true;
2531                    }
2532                }
2533            }
2534            if (mSensorStats.size() > 0) {
2535                Iterator<Map.Entry<Integer, Sensor>> it = mSensorStats.entrySet().iterator();
2536                while (it.hasNext()) {
2537                    Map.Entry<Integer, Sensor> sensorEntry = it.next();
2538                    Sensor s = sensorEntry.getValue();
2539                    if (s.reset()) {
2540                        it.remove();
2541                    } else {
2542                        active = true;
2543                    }
2544                }
2545            }
2546            if (mProcessStats.size() > 0) {
2547                Iterator<Map.Entry<String, Proc>> it = mProcessStats.entrySet().iterator();
2548                while (it.hasNext()) {
2549                    Map.Entry<String, Proc> procEntry = it.next();
2550                    procEntry.getValue().detach();
2551                }
2552                mProcessStats.clear();
2553            }
2554            if (mPids.size() > 0) {
2555                for (int i=0; !active && i<mPids.size(); i++) {
2556                    Pid pid = mPids.valueAt(i);
2557                    if (pid.mWakeStart != 0) {
2558                        active = true;
2559                    }
2560                }
2561            }
2562            if (mPackageStats.size() > 0) {
2563                Iterator<Map.Entry<String, Pkg>> it = mPackageStats.entrySet().iterator();
2564                while (it.hasNext()) {
2565                    Map.Entry<String, Pkg> pkgEntry = it.next();
2566                    Pkg p = pkgEntry.getValue();
2567                    p.detach();
2568                    if (p.mServiceStats.size() > 0) {
2569                        Iterator<Map.Entry<String, Pkg.Serv>> it2
2570                                = p.mServiceStats.entrySet().iterator();
2571                        while (it2.hasNext()) {
2572                            Map.Entry<String, Pkg.Serv> servEntry = it2.next();
2573                            servEntry.getValue().detach();
2574                        }
2575                    }
2576                }
2577                mPackageStats.clear();
2578            }
2579
2580            mPids.clear();
2581
2582            if (!active) {
2583                if (mWifiRunningTimer != null) {
2584                    mWifiRunningTimer.detach();
2585                }
2586                if (mFullWifiLockTimer != null) {
2587                    mFullWifiLockTimer.detach();
2588                }
2589                if (mScanWifiLockTimer != null) {
2590                    mScanWifiLockTimer.detach();
2591                }
2592                if (mWifiMulticastTimer != null) {
2593                    mWifiMulticastTimer.detach();
2594                }
2595                if (mAudioTurnedOnTimer != null) {
2596                    mAudioTurnedOnTimer.detach();
2597                }
2598                if (mVideoTurnedOnTimer != null) {
2599                    mVideoTurnedOnTimer.detach();
2600                }
2601                if (mUserActivityCounters != null) {
2602                    for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2603                        mUserActivityCounters[i].detach();
2604                    }
2605                }
2606            }
2607
2608            return !active;
2609        }
2610
2611        void writeToParcelLocked(Parcel out, long batteryRealtime) {
2612            out.writeInt(mWakelockStats.size());
2613            for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
2614                out.writeString(wakelockEntry.getKey());
2615                Uid.Wakelock wakelock = wakelockEntry.getValue();
2616                wakelock.writeToParcelLocked(out, batteryRealtime);
2617            }
2618
2619            out.writeInt(mSensorStats.size());
2620            for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
2621                out.writeInt(sensorEntry.getKey());
2622                Uid.Sensor sensor = sensorEntry.getValue();
2623                sensor.writeToParcelLocked(out, batteryRealtime);
2624            }
2625
2626            out.writeInt(mProcessStats.size());
2627            for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
2628                out.writeString(procEntry.getKey());
2629                Uid.Proc proc = procEntry.getValue();
2630                proc.writeToParcelLocked(out);
2631            }
2632
2633            out.writeInt(mPackageStats.size());
2634            for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
2635                out.writeString(pkgEntry.getKey());
2636                Uid.Pkg pkg = pkgEntry.getValue();
2637                pkg.writeToParcelLocked(out);
2638            }
2639
2640            out.writeLong(mLoadedTcpBytesReceived);
2641            out.writeLong(mLoadedTcpBytesSent);
2642            out.writeLong(computeCurrentTcpBytesReceived());
2643            out.writeLong(computeCurrentTcpBytesSent());
2644            out.writeLong(mTcpBytesReceivedAtLastUnplug);
2645            out.writeLong(mTcpBytesSentAtLastUnplug);
2646            if (mWifiRunningTimer != null) {
2647                out.writeInt(1);
2648                mWifiRunningTimer.writeToParcel(out, batteryRealtime);
2649            } else {
2650                out.writeInt(0);
2651            }
2652            if (mFullWifiLockTimer != null) {
2653                out.writeInt(1);
2654                mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
2655            } else {
2656                out.writeInt(0);
2657            }
2658            if (mScanWifiLockTimer != null) {
2659                out.writeInt(1);
2660                mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
2661            } else {
2662                out.writeInt(0);
2663            }
2664            if (mWifiMulticastTimer != null) {
2665                out.writeInt(1);
2666                mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
2667            } else {
2668                out.writeInt(0);
2669            }
2670            if (mAudioTurnedOnTimer != null) {
2671                out.writeInt(1);
2672                mAudioTurnedOnTimer.writeToParcel(out, batteryRealtime);
2673            } else {
2674                out.writeInt(0);
2675            }
2676            if (mVideoTurnedOnTimer != null) {
2677                out.writeInt(1);
2678                mVideoTurnedOnTimer.writeToParcel(out, batteryRealtime);
2679            } else {
2680                out.writeInt(0);
2681            }
2682            if (mUserActivityCounters != null) {
2683                out.writeInt(1);
2684                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2685                    mUserActivityCounters[i].writeToParcel(out);
2686                }
2687            } else {
2688                out.writeInt(0);
2689            }
2690        }
2691
2692        void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
2693            int numWakelocks = in.readInt();
2694            mWakelockStats.clear();
2695            for (int j = 0; j < numWakelocks; j++) {
2696                String wakelockName = in.readString();
2697                Uid.Wakelock wakelock = new Wakelock();
2698                wakelock.readFromParcelLocked(unpluggables, in);
2699                if (mWakelockStats.size() < MAX_WAKELOCKS_PER_UID) {
2700                    // We will just drop some random set of wakelocks if
2701                    // the previous run of the system was an older version
2702                    // that didn't impose a limit.
2703                    mWakelockStats.put(wakelockName, wakelock);
2704                }
2705            }
2706
2707            int numSensors = in.readInt();
2708            mSensorStats.clear();
2709            for (int k = 0; k < numSensors; k++) {
2710                int sensorNumber = in.readInt();
2711                Uid.Sensor sensor = new Sensor(sensorNumber);
2712                sensor.readFromParcelLocked(mUnpluggables, in);
2713                mSensorStats.put(sensorNumber, sensor);
2714            }
2715
2716            int numProcs = in.readInt();
2717            mProcessStats.clear();
2718            for (int k = 0; k < numProcs; k++) {
2719                String processName = in.readString();
2720                Uid.Proc proc = new Proc();
2721                proc.readFromParcelLocked(in);
2722                mProcessStats.put(processName, proc);
2723            }
2724
2725            int numPkgs = in.readInt();
2726            mPackageStats.clear();
2727            for (int l = 0; l < numPkgs; l++) {
2728                String packageName = in.readString();
2729                Uid.Pkg pkg = new Pkg();
2730                pkg.readFromParcelLocked(in);
2731                mPackageStats.put(packageName, pkg);
2732            }
2733
2734            mLoadedTcpBytesReceived = in.readLong();
2735            mLoadedTcpBytesSent = in.readLong();
2736            mCurrentTcpBytesReceived = in.readLong();
2737            mCurrentTcpBytesSent = in.readLong();
2738            mTcpBytesReceivedAtLastUnplug = in.readLong();
2739            mTcpBytesSentAtLastUnplug = in.readLong();
2740            mWifiRunning = false;
2741            if (in.readInt() != 0) {
2742                mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
2743                        mWifiRunningTimers, mUnpluggables, in);
2744            } else {
2745                mWifiRunningTimer = null;
2746            }
2747            mFullWifiLockOut = false;
2748            if (in.readInt() != 0) {
2749                mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
2750                        mFullWifiLockTimers, mUnpluggables, in);
2751            } else {
2752                mFullWifiLockTimer = null;
2753            }
2754            mScanWifiLockOut = false;
2755            if (in.readInt() != 0) {
2756                mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
2757                        mScanWifiLockTimers, mUnpluggables, in);
2758            } else {
2759                mScanWifiLockTimer = null;
2760            }
2761            mWifiMulticastEnabled = false;
2762            if (in.readInt() != 0) {
2763                mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
2764                        mWifiMulticastTimers, mUnpluggables, in);
2765            } else {
2766                mWifiMulticastTimer = null;
2767            }
2768            mAudioTurnedOn = false;
2769            if (in.readInt() != 0) {
2770                mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
2771                        null, mUnpluggables, in);
2772            } else {
2773                mAudioTurnedOnTimer = null;
2774            }
2775            mVideoTurnedOn = false;
2776            if (in.readInt() != 0) {
2777                mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
2778                        null, mUnpluggables, in);
2779            } else {
2780                mVideoTurnedOnTimer = null;
2781            }
2782            if (in.readInt() != 0) {
2783                mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
2784                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2785                    mUserActivityCounters[i] = new Counter(mUnpluggables, in);
2786                }
2787            } else {
2788                mUserActivityCounters = null;
2789            }
2790        }
2791
2792        /**
2793         * The statistics associated with a particular wake lock.
2794         */
2795        public final class Wakelock extends BatteryStats.Uid.Wakelock {
2796            /**
2797             * How long (in ms) this uid has been keeping the device partially awake.
2798             */
2799            StopwatchTimer mTimerPartial;
2800
2801            /**
2802             * How long (in ms) this uid has been keeping the device fully awake.
2803             */
2804            StopwatchTimer mTimerFull;
2805
2806            /**
2807             * How long (in ms) this uid has had a window keeping the device awake.
2808             */
2809            StopwatchTimer mTimerWindow;
2810
2811            /**
2812             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
2813             * proper timer pool from the given BatteryStatsImpl object.
2814             *
2815             * @param in the Parcel to be read from.
2816             * return a new Timer, or null.
2817             */
2818            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
2819                    ArrayList<Unpluggable> unpluggables, Parcel in) {
2820                if (in.readInt() == 0) {
2821                    return null;
2822                }
2823
2824                return new StopwatchTimer(Uid.this, type, pool, unpluggables, in);
2825            }
2826
2827            boolean reset() {
2828                boolean wlactive = false;
2829                if (mTimerFull != null) {
2830                    wlactive |= !mTimerFull.reset(BatteryStatsImpl.this, false);
2831                }
2832                if (mTimerPartial != null) {
2833                    wlactive |= !mTimerPartial.reset(BatteryStatsImpl.this, false);
2834                }
2835                if (mTimerWindow != null) {
2836                    wlactive |= !mTimerWindow.reset(BatteryStatsImpl.this, false);
2837                }
2838                if (!wlactive) {
2839                    if (mTimerFull != null) {
2840                        mTimerFull.detach();
2841                        mTimerFull = null;
2842                    }
2843                    if (mTimerPartial != null) {
2844                        mTimerPartial.detach();
2845                        mTimerPartial = null;
2846                    }
2847                    if (mTimerWindow != null) {
2848                        mTimerWindow.detach();
2849                        mTimerWindow = null;
2850                    }
2851                }
2852                return !wlactive;
2853            }
2854
2855            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
2856                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
2857                        mPartialTimers, unpluggables, in);
2858                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
2859                        mFullTimers, unpluggables, in);
2860                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
2861                        mWindowTimers, unpluggables, in);
2862            }
2863
2864            void writeToParcelLocked(Parcel out, long batteryRealtime) {
2865                Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
2866                Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
2867                Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
2868            }
2869
2870            @Override
2871            public Timer getWakeTime(int type) {
2872                switch (type) {
2873                case WAKE_TYPE_FULL: return mTimerFull;
2874                case WAKE_TYPE_PARTIAL: return mTimerPartial;
2875                case WAKE_TYPE_WINDOW: return mTimerWindow;
2876                default: throw new IllegalArgumentException("type = " + type);
2877                }
2878            }
2879        }
2880
2881        public final class Sensor extends BatteryStats.Uid.Sensor {
2882            final int mHandle;
2883            StopwatchTimer mTimer;
2884
2885            public Sensor(int handle) {
2886                mHandle = handle;
2887            }
2888
2889            private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
2890                    Parcel in) {
2891                if (in.readInt() == 0) {
2892                    return null;
2893                }
2894
2895                ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
2896                if (pool == null) {
2897                    pool = new ArrayList<StopwatchTimer>();
2898                    mSensorTimers.put(mHandle, pool);
2899                }
2900                return new StopwatchTimer(Uid.this, 0, pool, unpluggables, in);
2901            }
2902
2903            boolean reset() {
2904                if (mTimer.reset(BatteryStatsImpl.this, true)) {
2905                    mTimer = null;
2906                    return true;
2907                }
2908                return false;
2909            }
2910
2911            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
2912                mTimer = readTimerFromParcel(unpluggables, in);
2913            }
2914
2915            void writeToParcelLocked(Parcel out, long batteryRealtime) {
2916                Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
2917            }
2918
2919            @Override
2920            public Timer getSensorTime() {
2921                return mTimer;
2922            }
2923
2924            @Override
2925            public int getHandle() {
2926                return mHandle;
2927            }
2928        }
2929
2930        /**
2931         * The statistics associated with a particular process.
2932         */
2933        public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
2934            /**
2935             * Total time (in 1/100 sec) spent executing in user code.
2936             */
2937            long mUserTime;
2938
2939            /**
2940             * Total time (in 1/100 sec) spent executing in kernel code.
2941             */
2942            long mSystemTime;
2943
2944            /**
2945             * Number of times the process has been started.
2946             */
2947            int mStarts;
2948
2949            /**
2950             * Amount of time the process was running in the foreground.
2951             */
2952            long mForegroundTime;
2953
2954            /**
2955             * The amount of user time loaded from a previous save.
2956             */
2957            long mLoadedUserTime;
2958
2959            /**
2960             * The amount of system time loaded from a previous save.
2961             */
2962            long mLoadedSystemTime;
2963
2964            /**
2965             * The number of times the process has started from a previous save.
2966             */
2967            int mLoadedStarts;
2968
2969            /**
2970             * The amount of foreground time loaded from a previous save.
2971             */
2972            long mLoadedForegroundTime;
2973
2974            /**
2975             * The amount of user time loaded from the previous run.
2976             */
2977            long mLastUserTime;
2978
2979            /**
2980             * The amount of system time loaded from the previous run.
2981             */
2982            long mLastSystemTime;
2983
2984            /**
2985             * The number of times the process has started from the previous run.
2986             */
2987            int mLastStarts;
2988
2989            /**
2990             * The amount of foreground time loaded from the previous run
2991             */
2992            long mLastForegroundTime;
2993
2994            /**
2995             * The amount of user time when last unplugged.
2996             */
2997            long mUnpluggedUserTime;
2998
2999            /**
3000             * The amount of system time when last unplugged.
3001             */
3002            long mUnpluggedSystemTime;
3003
3004            /**
3005             * The number of times the process has started before unplugged.
3006             */
3007            int mUnpluggedStarts;
3008
3009            /**
3010             * The amount of foreground time since unplugged.
3011             */
3012            long mUnpluggedForegroundTime;
3013
3014            SamplingCounter[] mSpeedBins;
3015
3016            ArrayList<ExcessivePower> mExcessivePower;
3017
3018            Proc() {
3019                mUnpluggables.add(this);
3020                mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
3021            }
3022
3023            public void unplug(long batteryUptime, long batteryRealtime) {
3024                mUnpluggedUserTime = mUserTime;
3025                mUnpluggedSystemTime = mSystemTime;
3026                mUnpluggedStarts = mStarts;
3027                mUnpluggedForegroundTime = mForegroundTime;
3028            }
3029
3030            public void plug(long batteryUptime, long batteryRealtime) {
3031            }
3032
3033            void detach() {
3034                mUnpluggables.remove(this);
3035                for (int i = 0; i < mSpeedBins.length; i++) {
3036                    SamplingCounter c = mSpeedBins[i];
3037                    if (c != null) {
3038                        mUnpluggables.remove(c);
3039                        mSpeedBins[i] = null;
3040                    }
3041                }
3042            }
3043
3044            public int countExcessivePowers() {
3045                return mExcessivePower != null ? mExcessivePower.size() : 0;
3046            }
3047
3048            public ExcessivePower getExcessivePower(int i) {
3049                if (mExcessivePower != null) {
3050                    return mExcessivePower.get(i);
3051                }
3052                return null;
3053            }
3054
3055            public void addExcessiveWake(long overTime, long usedTime) {
3056                if (mExcessivePower == null) {
3057                    mExcessivePower = new ArrayList<ExcessivePower>();
3058                }
3059                ExcessivePower ew = new ExcessivePower();
3060                ew.type = ExcessivePower.TYPE_WAKE;
3061                ew.overTime = overTime;
3062                ew.usedTime = usedTime;
3063                mExcessivePower.add(ew);
3064            }
3065
3066            public void addExcessiveCpu(long overTime, long usedTime) {
3067                if (mExcessivePower == null) {
3068                    mExcessivePower = new ArrayList<ExcessivePower>();
3069                }
3070                ExcessivePower ew = new ExcessivePower();
3071                ew.type = ExcessivePower.TYPE_CPU;
3072                ew.overTime = overTime;
3073                ew.usedTime = usedTime;
3074                mExcessivePower.add(ew);
3075            }
3076
3077            void writeExcessivePowerToParcelLocked(Parcel out) {
3078                if (mExcessivePower == null) {
3079                    out.writeInt(0);
3080                    return;
3081                }
3082
3083                final int N = mExcessivePower.size();
3084                out.writeInt(N);
3085                for (int i=0; i<N; i++) {
3086                    ExcessivePower ew = mExcessivePower.get(i);
3087                    out.writeInt(ew.type);
3088                    out.writeLong(ew.overTime);
3089                    out.writeLong(ew.usedTime);
3090                }
3091            }
3092
3093            boolean readExcessivePowerFromParcelLocked(Parcel in) {
3094                final int N = in.readInt();
3095                if (N == 0) {
3096                    mExcessivePower = null;
3097                    return true;
3098                }
3099
3100                if (N > 10000) {
3101                    Slog.w(TAG, "File corrupt: too many excessive power entries " + N);
3102                    return false;
3103                }
3104
3105                mExcessivePower = new ArrayList<ExcessivePower>();
3106                for (int i=0; i<N; i++) {
3107                    ExcessivePower ew = new ExcessivePower();
3108                    ew.type = in.readInt();
3109                    ew.overTime = in.readLong();
3110                    ew.usedTime = in.readLong();
3111                    mExcessivePower.add(ew);
3112                }
3113                return true;
3114            }
3115
3116            void writeToParcelLocked(Parcel out) {
3117                out.writeLong(mUserTime);
3118                out.writeLong(mSystemTime);
3119                out.writeLong(mForegroundTime);
3120                out.writeInt(mStarts);
3121                out.writeLong(mLoadedUserTime);
3122                out.writeLong(mLoadedSystemTime);
3123                out.writeLong(mLoadedForegroundTime);
3124                out.writeInt(mLoadedStarts);
3125                out.writeLong(mUnpluggedUserTime);
3126                out.writeLong(mUnpluggedSystemTime);
3127                out.writeLong(mUnpluggedForegroundTime);
3128                out.writeInt(mUnpluggedStarts);
3129
3130                out.writeInt(mSpeedBins.length);
3131                for (int i = 0; i < mSpeedBins.length; i++) {
3132                    SamplingCounter c = mSpeedBins[i];
3133                    if (c != null) {
3134                        out.writeInt(1);
3135                        c.writeToParcel(out);
3136                    } else {
3137                        out.writeInt(0);
3138                    }
3139                }
3140
3141                writeExcessivePowerToParcelLocked(out);
3142            }
3143
3144            void readFromParcelLocked(Parcel in) {
3145                mUserTime = in.readLong();
3146                mSystemTime = in.readLong();
3147                mForegroundTime = in.readLong();
3148                mStarts = in.readInt();
3149                mLoadedUserTime = in.readLong();
3150                mLoadedSystemTime = in.readLong();
3151                mLoadedForegroundTime = in.readLong();
3152                mLoadedStarts = in.readInt();
3153                mLastUserTime = 0;
3154                mLastSystemTime = 0;
3155                mLastForegroundTime = 0;
3156                mLastStarts = 0;
3157                mUnpluggedUserTime = in.readLong();
3158                mUnpluggedSystemTime = in.readLong();
3159                mUnpluggedForegroundTime = in.readLong();
3160                mUnpluggedStarts = in.readInt();
3161
3162                int bins = in.readInt();
3163                int steps = getCpuSpeedSteps();
3164                mSpeedBins = new SamplingCounter[bins >= steps ? bins : steps];
3165                for (int i = 0; i < bins; i++) {
3166                    if (in.readInt() != 0) {
3167                        mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
3168                    }
3169                }
3170
3171                readExcessivePowerFromParcelLocked(in);
3172            }
3173
3174            public BatteryStatsImpl getBatteryStats() {
3175                return BatteryStatsImpl.this;
3176            }
3177
3178            public void addCpuTimeLocked(int utime, int stime) {
3179                mUserTime += utime;
3180                mSystemTime += stime;
3181            }
3182
3183            public void addForegroundTimeLocked(long ttime) {
3184                mForegroundTime += ttime;
3185            }
3186
3187            public void incStartsLocked() {
3188                mStarts++;
3189            }
3190
3191            @Override
3192            public long getUserTime(int which) {
3193                long val;
3194                if (which == STATS_LAST) {
3195                    val = mLastUserTime;
3196                } else {
3197                    val = mUserTime;
3198                    if (which == STATS_CURRENT) {
3199                        val -= mLoadedUserTime;
3200                    } else if (which == STATS_SINCE_UNPLUGGED) {
3201                        val -= mUnpluggedUserTime;
3202                    }
3203                }
3204                return val;
3205            }
3206
3207            @Override
3208            public long getSystemTime(int which) {
3209                long val;
3210                if (which == STATS_LAST) {
3211                    val = mLastSystemTime;
3212                } else {
3213                    val = mSystemTime;
3214                    if (which == STATS_CURRENT) {
3215                        val -= mLoadedSystemTime;
3216                    } else if (which == STATS_SINCE_UNPLUGGED) {
3217                        val -= mUnpluggedSystemTime;
3218                    }
3219                }
3220                return val;
3221            }
3222
3223            @Override
3224            public long getForegroundTime(int which) {
3225                long val;
3226                if (which == STATS_LAST) {
3227                    val = mLastForegroundTime;
3228                } else {
3229                    val = mForegroundTime;
3230                    if (which == STATS_CURRENT) {
3231                        val -= mLoadedForegroundTime;
3232                    } else if (which == STATS_SINCE_UNPLUGGED) {
3233                        val -= mUnpluggedForegroundTime;
3234                    }
3235                }
3236                return val;
3237            }
3238
3239            @Override
3240            public int getStarts(int which) {
3241                int val;
3242                if (which == STATS_LAST) {
3243                    val = mLastStarts;
3244                } else {
3245                    val = mStarts;
3246                    if (which == STATS_CURRENT) {
3247                        val -= mLoadedStarts;
3248                    } else if (which == STATS_SINCE_UNPLUGGED) {
3249                        val -= mUnpluggedStarts;
3250                    }
3251                }
3252                return val;
3253            }
3254
3255            /* Called by ActivityManagerService when CPU times are updated. */
3256            public void addSpeedStepTimes(long[] values) {
3257                for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
3258                    long amt = values[i];
3259                    if (amt != 0) {
3260                        SamplingCounter c = mSpeedBins[i];
3261                        if (c == null) {
3262                            mSpeedBins[i] = c = new SamplingCounter(mUnpluggables);
3263                        }
3264                        c.addCountAtomic(values[i]);
3265                    }
3266                }
3267            }
3268
3269            @Override
3270            public long getTimeAtCpuSpeedStep(int speedStep, int which) {
3271                if (speedStep < mSpeedBins.length) {
3272                    SamplingCounter c = mSpeedBins[speedStep];
3273                    return c != null ? c.getCountLocked(which) : 0;
3274                } else {
3275                    return 0;
3276                }
3277            }
3278        }
3279
3280        /**
3281         * The statistics associated with a particular package.
3282         */
3283        public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
3284            /**
3285             * Number of times this package has done something that could wake up the
3286             * device from sleep.
3287             */
3288            int mWakeups;
3289
3290            /**
3291             * Number of things that could wake up the device loaded from a
3292             * previous save.
3293             */
3294            int mLoadedWakeups;
3295
3296            /**
3297             * Number of things that could wake up the device as of the
3298             * last run.
3299             */
3300            int mLastWakeups;
3301
3302            /**
3303             * Number of things that could wake up the device as of the
3304             * last run.
3305             */
3306            int mUnpluggedWakeups;
3307
3308            /**
3309             * The statics we have collected for this package's services.
3310             */
3311            final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
3312
3313            Pkg() {
3314                mUnpluggables.add(this);
3315            }
3316
3317            public void unplug(long batteryUptime, long batteryRealtime) {
3318                mUnpluggedWakeups = mWakeups;
3319            }
3320
3321            public void plug(long batteryUptime, long batteryRealtime) {
3322            }
3323
3324            void detach() {
3325                mUnpluggables.remove(this);
3326            }
3327
3328            void readFromParcelLocked(Parcel in) {
3329                mWakeups = in.readInt();
3330                mLoadedWakeups = in.readInt();
3331                mLastWakeups = 0;
3332                mUnpluggedWakeups = in.readInt();
3333
3334                int numServs = in.readInt();
3335                mServiceStats.clear();
3336                for (int m = 0; m < numServs; m++) {
3337                    String serviceName = in.readString();
3338                    Uid.Pkg.Serv serv = new Serv();
3339                    mServiceStats.put(serviceName, serv);
3340
3341                    serv.readFromParcelLocked(in);
3342                }
3343            }
3344
3345            void writeToParcelLocked(Parcel out) {
3346                out.writeInt(mWakeups);
3347                out.writeInt(mLoadedWakeups);
3348                out.writeInt(mUnpluggedWakeups);
3349
3350                out.writeInt(mServiceStats.size());
3351                for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
3352                    out.writeString(servEntry.getKey());
3353                    Uid.Pkg.Serv serv = servEntry.getValue();
3354
3355                    serv.writeToParcelLocked(out);
3356                }
3357            }
3358
3359            @Override
3360            public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
3361                return mServiceStats;
3362            }
3363
3364            @Override
3365            public int getWakeups(int which) {
3366                int val;
3367                if (which == STATS_LAST) {
3368                    val = mLastWakeups;
3369                } else {
3370                    val = mWakeups;
3371                    if (which == STATS_CURRENT) {
3372                        val -= mLoadedWakeups;
3373                    } else if (which == STATS_SINCE_UNPLUGGED) {
3374                        val -= mUnpluggedWakeups;
3375                    }
3376                }
3377
3378                return val;
3379            }
3380
3381            /**
3382             * The statistics associated with a particular service.
3383             */
3384            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
3385                /**
3386                 * Total time (ms in battery uptime) the service has been left started.
3387                 */
3388                long mStartTime;
3389
3390                /**
3391                 * If service has been started and not yet stopped, this is
3392                 * when it was started.
3393                 */
3394                long mRunningSince;
3395
3396                /**
3397                 * True if we are currently running.
3398                 */
3399                boolean mRunning;
3400
3401                /**
3402                 * Total number of times startService() has been called.
3403                 */
3404                int mStarts;
3405
3406                /**
3407                 * Total time (ms in battery uptime) the service has been left launched.
3408                 */
3409                long mLaunchedTime;
3410
3411                /**
3412                 * If service has been launched and not yet exited, this is
3413                 * when it was launched (ms in battery uptime).
3414                 */
3415                long mLaunchedSince;
3416
3417                /**
3418                 * True if we are currently launched.
3419                 */
3420                boolean mLaunched;
3421
3422                /**
3423                 * Total number times the service has been launched.
3424                 */
3425                int mLaunches;
3426
3427                /**
3428                 * The amount of time spent started loaded from a previous save
3429                 * (ms in battery uptime).
3430                 */
3431                long mLoadedStartTime;
3432
3433                /**
3434                 * The number of starts loaded from a previous save.
3435                 */
3436                int mLoadedStarts;
3437
3438                /**
3439                 * The number of launches loaded from a previous save.
3440                 */
3441                int mLoadedLaunches;
3442
3443                /**
3444                 * The amount of time spent started as of the last run (ms
3445                 * in battery uptime).
3446                 */
3447                long mLastStartTime;
3448
3449                /**
3450                 * The number of starts as of the last run.
3451                 */
3452                int mLastStarts;
3453
3454                /**
3455                 * The number of launches as of the last run.
3456                 */
3457                int mLastLaunches;
3458
3459                /**
3460                 * The amount of time spent started when last unplugged (ms
3461                 * in battery uptime).
3462                 */
3463                long mUnpluggedStartTime;
3464
3465                /**
3466                 * The number of starts when last unplugged.
3467                 */
3468                int mUnpluggedStarts;
3469
3470                /**
3471                 * The number of launches when last unplugged.
3472                 */
3473                int mUnpluggedLaunches;
3474
3475                Serv() {
3476                    mUnpluggables.add(this);
3477                }
3478
3479                public void unplug(long batteryUptime, long batteryRealtime) {
3480                    mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
3481                    mUnpluggedStarts = mStarts;
3482                    mUnpluggedLaunches = mLaunches;
3483                }
3484
3485                public void plug(long batteryUptime, long batteryRealtime) {
3486                }
3487
3488                void detach() {
3489                    mUnpluggables.remove(this);
3490                }
3491
3492                void readFromParcelLocked(Parcel in) {
3493                    mStartTime = in.readLong();
3494                    mRunningSince = in.readLong();
3495                    mRunning = in.readInt() != 0;
3496                    mStarts = in.readInt();
3497                    mLaunchedTime = in.readLong();
3498                    mLaunchedSince = in.readLong();
3499                    mLaunched = in.readInt() != 0;
3500                    mLaunches = in.readInt();
3501                    mLoadedStartTime = in.readLong();
3502                    mLoadedStarts = in.readInt();
3503                    mLoadedLaunches = in.readInt();
3504                    mLastStartTime = 0;
3505                    mLastStarts = 0;
3506                    mLastLaunches = 0;
3507                    mUnpluggedStartTime = in.readLong();
3508                    mUnpluggedStarts = in.readInt();
3509                    mUnpluggedLaunches = in.readInt();
3510                }
3511
3512                void writeToParcelLocked(Parcel out) {
3513                    out.writeLong(mStartTime);
3514                    out.writeLong(mRunningSince);
3515                    out.writeInt(mRunning ? 1 : 0);
3516                    out.writeInt(mStarts);
3517                    out.writeLong(mLaunchedTime);
3518                    out.writeLong(mLaunchedSince);
3519                    out.writeInt(mLaunched ? 1 : 0);
3520                    out.writeInt(mLaunches);
3521                    out.writeLong(mLoadedStartTime);
3522                    out.writeInt(mLoadedStarts);
3523                    out.writeInt(mLoadedLaunches);
3524                    out.writeLong(mUnpluggedStartTime);
3525                    out.writeInt(mUnpluggedStarts);
3526                    out.writeInt(mUnpluggedLaunches);
3527                }
3528
3529                long getLaunchTimeToNowLocked(long batteryUptime) {
3530                    if (!mLaunched) return mLaunchedTime;
3531                    return mLaunchedTime + batteryUptime - mLaunchedSince;
3532                }
3533
3534                long getStartTimeToNowLocked(long batteryUptime) {
3535                    if (!mRunning) return mStartTime;
3536                    return mStartTime + batteryUptime - mRunningSince;
3537                }
3538
3539                public void startLaunchedLocked() {
3540                    if (!mLaunched) {
3541                        mLaunches++;
3542                        mLaunchedSince = getBatteryUptimeLocked();
3543                        mLaunched = true;
3544                    }
3545                }
3546
3547                public void stopLaunchedLocked() {
3548                    if (mLaunched) {
3549                        long time = getBatteryUptimeLocked() - mLaunchedSince;
3550                        if (time > 0) {
3551                            mLaunchedTime += time;
3552                        } else {
3553                            mLaunches--;
3554                        }
3555                        mLaunched = false;
3556                    }
3557                }
3558
3559                public void startRunningLocked() {
3560                    if (!mRunning) {
3561                        mStarts++;
3562                        mRunningSince = getBatteryUptimeLocked();
3563                        mRunning = true;
3564                    }
3565                }
3566
3567                public void stopRunningLocked() {
3568                    if (mRunning) {
3569                        long time = getBatteryUptimeLocked() - mRunningSince;
3570                        if (time > 0) {
3571                            mStartTime += time;
3572                        } else {
3573                            mStarts--;
3574                        }
3575                        mRunning = false;
3576                    }
3577                }
3578
3579                public BatteryStatsImpl getBatteryStats() {
3580                    return BatteryStatsImpl.this;
3581                }
3582
3583                @Override
3584                public int getLaunches(int which) {
3585                    int val;
3586
3587                    if (which == STATS_LAST) {
3588                        val = mLastLaunches;
3589                    } else {
3590                        val = mLaunches;
3591                        if (which == STATS_CURRENT) {
3592                            val -= mLoadedLaunches;
3593                        } else if (which == STATS_SINCE_UNPLUGGED) {
3594                            val -= mUnpluggedLaunches;
3595                        }
3596                    }
3597
3598                    return val;
3599                }
3600
3601                @Override
3602                public long getStartTime(long now, int which) {
3603                    long val;
3604                    if (which == STATS_LAST) {
3605                        val = mLastStartTime;
3606                    } else {
3607                        val = getStartTimeToNowLocked(now);
3608                        if (which == STATS_CURRENT) {
3609                            val -= mLoadedStartTime;
3610                        } else if (which == STATS_SINCE_UNPLUGGED) {
3611                            val -= mUnpluggedStartTime;
3612                        }
3613                    }
3614
3615                    return val;
3616                }
3617
3618                @Override
3619                public int getStarts(int which) {
3620                    int val;
3621                    if (which == STATS_LAST) {
3622                        val = mLastStarts;
3623                    } else {
3624                        val = mStarts;
3625                        if (which == STATS_CURRENT) {
3626                            val -= mLoadedStarts;
3627                        } else if (which == STATS_SINCE_UNPLUGGED) {
3628                            val -= mUnpluggedStarts;
3629                        }
3630                    }
3631
3632                    return val;
3633                }
3634            }
3635
3636            public BatteryStatsImpl getBatteryStats() {
3637                return BatteryStatsImpl.this;
3638            }
3639
3640            public void incWakeupsLocked() {
3641                mWakeups++;
3642            }
3643
3644            final Serv newServiceStatsLocked() {
3645                return new Serv();
3646            }
3647        }
3648
3649        /**
3650         * Retrieve the statistics object for a particular process, creating
3651         * if needed.
3652         */
3653        public Proc getProcessStatsLocked(String name) {
3654            Proc ps = mProcessStats.get(name);
3655            if (ps == null) {
3656                ps = new Proc();
3657                mProcessStats.put(name, ps);
3658            }
3659
3660            return ps;
3661        }
3662
3663        public SparseArray<? extends Pid> getPidStats() {
3664            return mPids;
3665        }
3666
3667        public Pid getPidStatsLocked(int pid) {
3668            Pid p = mPids.get(pid);
3669            if (p == null) {
3670                p = new Pid();
3671                mPids.put(pid, p);
3672            }
3673            return p;
3674        }
3675
3676        /**
3677         * Retrieve the statistics object for a particular service, creating
3678         * if needed.
3679         */
3680        public Pkg getPackageStatsLocked(String name) {
3681            Pkg ps = mPackageStats.get(name);
3682            if (ps == null) {
3683                ps = new Pkg();
3684                mPackageStats.put(name, ps);
3685            }
3686
3687            return ps;
3688        }
3689
3690        /**
3691         * Retrieve the statistics object for a particular service, creating
3692         * if needed.
3693         */
3694        public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
3695            Pkg ps = getPackageStatsLocked(pkg);
3696            Pkg.Serv ss = ps.mServiceStats.get(serv);
3697            if (ss == null) {
3698                ss = ps.newServiceStatsLocked();
3699                ps.mServiceStats.put(serv, ss);
3700            }
3701
3702            return ss;
3703        }
3704
3705        public StopwatchTimer getWakeTimerLocked(String name, int type) {
3706            Wakelock wl = mWakelockStats.get(name);
3707            if (wl == null) {
3708                if (mWakelockStats.size() > MAX_WAKELOCKS_PER_UID) {
3709                    name = BATCHED_WAKELOCK_NAME;
3710                    wl = mWakelockStats.get(name);
3711                }
3712                if (wl == null) {
3713                    wl = new Wakelock();
3714                    mWakelockStats.put(name, wl);
3715                }
3716            }
3717            StopwatchTimer t = null;
3718            switch (type) {
3719                case WAKE_TYPE_PARTIAL:
3720                    t = wl.mTimerPartial;
3721                    if (t == null) {
3722                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
3723                                mPartialTimers, mUnpluggables);
3724                        wl.mTimerPartial = t;
3725                    }
3726                    return t;
3727                case WAKE_TYPE_FULL:
3728                    t = wl.mTimerFull;
3729                    if (t == null) {
3730                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
3731                                mFullTimers, mUnpluggables);
3732                        wl.mTimerFull = t;
3733                    }
3734                    return t;
3735                case WAKE_TYPE_WINDOW:
3736                    t = wl.mTimerWindow;
3737                    if (t == null) {
3738                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
3739                                mWindowTimers, mUnpluggables);
3740                        wl.mTimerWindow = t;
3741                    }
3742                    return t;
3743                default:
3744                    throw new IllegalArgumentException("type=" + type);
3745            }
3746        }
3747
3748        public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
3749            Sensor se = mSensorStats.get(sensor);
3750            if (se == null) {
3751                if (!create) {
3752                    return null;
3753                }
3754                se = new Sensor(sensor);
3755                mSensorStats.put(sensor, se);
3756            }
3757            StopwatchTimer t = se.mTimer;
3758            if (t != null) {
3759                return t;
3760            }
3761            ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
3762            if (timers == null) {
3763                timers = new ArrayList<StopwatchTimer>();
3764                mSensorTimers.put(sensor, timers);
3765            }
3766            t = new StopwatchTimer(Uid.this, BatteryStats.SENSOR, timers, mUnpluggables);
3767            se.mTimer = t;
3768            return t;
3769        }
3770
3771        public void noteStartWakeLocked(int pid, String name, int type) {
3772            StopwatchTimer t = getWakeTimerLocked(name, type);
3773            if (t != null) {
3774                t.startRunningLocked(BatteryStatsImpl.this);
3775            }
3776            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
3777                Pid p = getPidStatsLocked(pid);
3778                if (p.mWakeStart == 0) {
3779                    p.mWakeStart = SystemClock.elapsedRealtime();
3780                }
3781            }
3782        }
3783
3784        public void noteStopWakeLocked(int pid, String name, int type) {
3785            StopwatchTimer t = getWakeTimerLocked(name, type);
3786            if (t != null) {
3787                t.stopRunningLocked(BatteryStatsImpl.this);
3788            }
3789            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
3790                Pid p = mPids.get(pid);
3791                if (p != null && p.mWakeStart != 0) {
3792                    p.mWakeSum += SystemClock.elapsedRealtime() - p.mWakeStart;
3793                    p.mWakeStart = 0;
3794                }
3795            }
3796        }
3797
3798        public void reportExcessiveWakeLocked(String proc, long overTime, long usedTime) {
3799            Proc p = getProcessStatsLocked(proc);
3800            if (p != null) {
3801                p.addExcessiveWake(overTime, usedTime);
3802            }
3803        }
3804
3805        public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) {
3806            Proc p = getProcessStatsLocked(proc);
3807            if (p != null) {
3808                p.addExcessiveCpu(overTime, usedTime);
3809            }
3810        }
3811
3812        public void noteStartSensor(int sensor) {
3813            StopwatchTimer t = getSensorTimerLocked(sensor, true);
3814            if (t != null) {
3815                t.startRunningLocked(BatteryStatsImpl.this);
3816            }
3817        }
3818
3819        public void noteStopSensor(int sensor) {
3820            // Don't create a timer if one doesn't already exist
3821            StopwatchTimer t = getSensorTimerLocked(sensor, false);
3822            if (t != null) {
3823                t.stopRunningLocked(BatteryStatsImpl.this);
3824            }
3825        }
3826
3827        public void noteStartGps() {
3828            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
3829            if (t != null) {
3830                t.startRunningLocked(BatteryStatsImpl.this);
3831            }
3832        }
3833
3834        public void noteStopGps() {
3835            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
3836            if (t != null) {
3837                t.stopRunningLocked(BatteryStatsImpl.this);
3838            }
3839        }
3840
3841        public BatteryStatsImpl getBatteryStats() {
3842            return BatteryStatsImpl.this;
3843        }
3844    }
3845
3846    public BatteryStatsImpl(String filename) {
3847        mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
3848        mHandler = new MyHandler();
3849        mStartCount++;
3850        mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables);
3851        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3852            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mUnpluggables);
3853        }
3854        mInputEventCounter = new Counter(mUnpluggables);
3855        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables);
3856        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3857            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null, mUnpluggables);
3858        }
3859        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables);
3860        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3861            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null, mUnpluggables);
3862        }
3863        mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables);
3864        mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
3865        mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables);
3866        mAudioOnTimer = new StopwatchTimer(null, -6, null, mUnpluggables);
3867        mVideoOnTimer = new StopwatchTimer(null, -7, null, mUnpluggables);
3868        mOnBattery = mOnBatteryInternal = false;
3869        initTimes();
3870        mTrackBatteryPastUptime = 0;
3871        mTrackBatteryPastRealtime = 0;
3872        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
3873        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
3874        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
3875        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
3876        mDischargeStartLevel = 0;
3877        mDischargeUnplugLevel = 0;
3878        mDischargeCurrentLevel = 0;
3879        mLowDischargeAmountSinceCharge = 0;
3880        mHighDischargeAmountSinceCharge = 0;
3881    }
3882
3883    public BatteryStatsImpl(Parcel p) {
3884        mFile = null;
3885        mHandler = null;
3886        readFromParcel(p);
3887    }
3888
3889    public void setCallback(BatteryCallback cb) {
3890        mCallback = cb;
3891    }
3892
3893    public void setNumSpeedSteps(int steps) {
3894        if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
3895    }
3896
3897    public void setRadioScanningTimeout(long timeout) {
3898        if (mPhoneSignalScanningTimer != null) {
3899            mPhoneSignalScanningTimer.setTimeout(timeout);
3900        }
3901    }
3902
3903    private HistoryItem mHistoryIterator;
3904
3905    public boolean startIteratingHistoryLocked() {
3906        return (mHistoryIterator = mHistory) != null;
3907    }
3908
3909    public boolean getNextHistoryLocked(HistoryItem out) {
3910        HistoryItem cur = mHistoryIterator;
3911        if (cur == null) {
3912            return false;
3913        }
3914        out.setTo(cur);
3915        mHistoryIterator = cur.next;
3916        return true;
3917    }
3918
3919    @Override
3920    public HistoryItem getHistory() {
3921        return mHistory;
3922    }
3923
3924    @Override
3925    public long getHistoryBaseTime() {
3926        return mHistoryBaseTime;
3927    }
3928
3929    @Override
3930    public int getStartCount() {
3931        return mStartCount;
3932    }
3933
3934    public boolean isOnBattery() {
3935        return mOnBattery;
3936    }
3937
3938    public boolean isScreenOn() {
3939        return mScreenOn;
3940    }
3941
3942    void initTimes() {
3943        mBatteryRealtime = mTrackBatteryPastUptime = 0;
3944        mBatteryUptime = mTrackBatteryPastRealtime = 0;
3945        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
3946        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
3947        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
3948        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
3949    }
3950
3951    public void resetAllStatsLocked() {
3952        mStartCount = 0;
3953        initTimes();
3954        mScreenOnTimer.reset(this, false);
3955        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3956            mScreenBrightnessTimer[i].reset(this, false);
3957        }
3958        mInputEventCounter.reset(false);
3959        mPhoneOnTimer.reset(this, false);
3960        mAudioOnTimer.reset(this, false);
3961        mVideoOnTimer.reset(this, false);
3962        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3963            mPhoneSignalStrengthsTimer[i].reset(this, false);
3964        }
3965        mPhoneSignalScanningTimer.reset(this, false);
3966        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3967            mPhoneDataConnectionsTimer[i].reset(this, false);
3968        }
3969        mWifiOnTimer.reset(this, false);
3970        mGlobalWifiRunningTimer.reset(this, false);
3971        mBluetoothOnTimer.reset(this, false);
3972
3973        for (int i=0; i<mUidStats.size(); i++) {
3974            if (mUidStats.valueAt(i).reset()) {
3975                mUidStats.remove(mUidStats.keyAt(i));
3976                i--;
3977            }
3978        }
3979
3980        if (mKernelWakelockStats.size() > 0) {
3981            for (SamplingTimer timer : mKernelWakelockStats.values()) {
3982                mUnpluggables.remove(timer);
3983            }
3984            mKernelWakelockStats.clear();
3985        }
3986
3987        clearHistoryLocked();
3988    }
3989
3990    void setOnBattery(boolean onBattery, int oldStatus, int level) {
3991        synchronized(this) {
3992            boolean doWrite = false;
3993            Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
3994            m.arg1 = onBattery ? 1 : 0;
3995            mHandler.sendMessage(m);
3996            mOnBattery = mOnBatteryInternal = onBattery;
3997
3998            long uptime = SystemClock.uptimeMillis() * 1000;
3999            long mSecRealtime = SystemClock.elapsedRealtime();
4000            long realtime = mSecRealtime * 1000;
4001            if (onBattery) {
4002                // We will reset our status if we are unplugging after the
4003                // battery was last full, or the level is at 100, or
4004                // we have gone through a significant charge (from a very low
4005                // level to a now very high level).
4006                if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
4007                        || level >= 95
4008                        || (mDischargeCurrentLevel < 30 && level >= 90)) {
4009                    doWrite = true;
4010                    resetAllStatsLocked();
4011                    mDischargeStartLevel = level;
4012                    mLowDischargeAmountSinceCharge = 0;
4013                    mHighDischargeAmountSinceCharge = 0;
4014                }
4015                updateKernelWakelocksLocked();
4016                mHistoryCur.batteryLevel = (byte)level;
4017                mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4018                if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
4019                        + Integer.toHexString(mHistoryCur.states));
4020                addHistoryRecordLocked(mSecRealtime);
4021                mTrackBatteryUptimeStart = uptime;
4022                mTrackBatteryRealtimeStart = realtime;
4023                mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
4024                mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
4025                mDischargeCurrentLevel = mDischargeUnplugLevel = level;
4026                doUnplugLocked(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
4027            } else {
4028                updateKernelWakelocksLocked();
4029                mHistoryCur.batteryLevel = (byte)level;
4030                mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4031                if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
4032                        + Integer.toHexString(mHistoryCur.states));
4033                addHistoryRecordLocked(mSecRealtime);
4034                mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
4035                mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
4036                mDischargeCurrentLevel = level;
4037                if (level < mDischargeUnplugLevel) {
4038                    mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
4039                    mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
4040                }
4041                doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
4042            }
4043            if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
4044                if (mFile != null) {
4045                    writeAsyncLocked();
4046                }
4047            }
4048        }
4049    }
4050
4051    // This should probably be exposed in the API, though it's not critical
4052    private static final int BATTERY_PLUGGED_NONE = 0;
4053
4054    public void setBatteryState(int status, int health, int plugType, int level,
4055            int temp, int volt) {
4056        boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
4057        int oldStatus = mHistoryCur.batteryStatus;
4058        if (!mHaveBatteryLevel) {
4059            mHaveBatteryLevel = true;
4060            // We start out assuming that the device is plugged in (not
4061            // on battery).  If our first report is now that we are indeed
4062            // plugged in, then twiddle our state to correctly reflect that
4063            // since we won't be going through the full setOnBattery().
4064            if (onBattery == mOnBattery) {
4065                if (onBattery) {
4066                    mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4067                } else {
4068                    mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
4069                }
4070            }
4071            oldStatus = status;
4072        }
4073        if (onBattery) {
4074            mDischargeCurrentLevel = level;
4075            mRecordingHistory = true;
4076        }
4077        if (onBattery != mOnBattery) {
4078            mHistoryCur.batteryLevel = (byte)level;
4079            mHistoryCur.batteryStatus = (byte)status;
4080            mHistoryCur.batteryHealth = (byte)health;
4081            mHistoryCur.batteryPlugType = (byte)plugType;
4082            mHistoryCur.batteryTemperature = (char)temp;
4083            mHistoryCur.batteryVoltage = (char)volt;
4084            setOnBattery(onBattery, oldStatus, level);
4085        } else {
4086            boolean changed = false;
4087            if (mHistoryCur.batteryLevel != level) {
4088                mHistoryCur.batteryLevel = (byte)level;
4089                changed = true;
4090            }
4091            if (mHistoryCur.batteryStatus != status) {
4092                mHistoryCur.batteryStatus = (byte)status;
4093                changed = true;
4094            }
4095            if (mHistoryCur.batteryHealth != health) {
4096                mHistoryCur.batteryHealth = (byte)health;
4097                changed = true;
4098            }
4099            if (mHistoryCur.batteryPlugType != plugType) {
4100                mHistoryCur.batteryPlugType = (byte)plugType;
4101                changed = true;
4102            }
4103            if (mHistoryCur.batteryTemperature != temp) {
4104                mHistoryCur.batteryTemperature = (char)temp;
4105                changed = true;
4106            }
4107            if (mHistoryCur.batteryVoltage != volt) {
4108                mHistoryCur.batteryVoltage = (char)volt;
4109                changed = true;
4110            }
4111            if (changed) {
4112                addHistoryRecordLocked(SystemClock.elapsedRealtime());
4113            }
4114        }
4115        if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
4116            // We don't record history while we are plugged in and fully charged.
4117            // The next time we are unplugged, history will be cleared.
4118            mRecordingHistory = false;
4119        }
4120    }
4121
4122    public void updateKernelWakelocksLocked() {
4123        Map<String, KernelWakelockStats> m = readKernelWakelockStats();
4124
4125        if (m == null) {
4126            // Not crashing might make board bringup easier.
4127            Slog.w(TAG, "Couldn't get kernel wake lock stats");
4128            return;
4129        }
4130
4131        for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
4132            String name = ent.getKey();
4133            KernelWakelockStats kws = ent.getValue();
4134
4135            SamplingTimer kwlt = mKernelWakelockStats.get(name);
4136            if (kwlt == null) {
4137                kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
4138                        true /* track reported values */);
4139                mKernelWakelockStats.put(name, kwlt);
4140            }
4141            kwlt.updateCurrentReportedCount(kws.mCount);
4142            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
4143            kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
4144        }
4145
4146        if (m.size() != mKernelWakelockStats.size()) {
4147            // Set timers to stale if they didn't appear in /proc/wakelocks this time.
4148            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
4149                SamplingTimer st = ent.getValue();
4150                if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
4151                    st.setStale();
4152                }
4153            }
4154        }
4155    }
4156
4157    public long getAwakeTimeBattery() {
4158        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
4159    }
4160
4161    public long getAwakeTimePlugged() {
4162        return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
4163    }
4164
4165    @Override
4166    public long computeUptime(long curTime, int which) {
4167        switch (which) {
4168            case STATS_SINCE_CHARGED: return mUptime + (curTime-mUptimeStart);
4169            case STATS_LAST: return mLastUptime;
4170            case STATS_CURRENT: return (curTime-mUptimeStart);
4171            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
4172        }
4173        return 0;
4174    }
4175
4176    @Override
4177    public long computeRealtime(long curTime, int which) {
4178        switch (which) {
4179            case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
4180            case STATS_LAST: return mLastRealtime;
4181            case STATS_CURRENT: return (curTime-mRealtimeStart);
4182            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
4183        }
4184        return 0;
4185    }
4186
4187    @Override
4188    public long computeBatteryUptime(long curTime, int which) {
4189        switch (which) {
4190            case STATS_SINCE_CHARGED:
4191                return mBatteryUptime + getBatteryUptime(curTime);
4192            case STATS_LAST:
4193                return mBatteryLastUptime;
4194            case STATS_CURRENT:
4195                return getBatteryUptime(curTime);
4196            case STATS_SINCE_UNPLUGGED:
4197                return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
4198        }
4199        return 0;
4200    }
4201
4202    @Override
4203    public long computeBatteryRealtime(long curTime, int which) {
4204        switch (which) {
4205            case STATS_SINCE_CHARGED:
4206                return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
4207            case STATS_LAST:
4208                return mBatteryLastRealtime;
4209            case STATS_CURRENT:
4210                return getBatteryRealtimeLocked(curTime);
4211            case STATS_SINCE_UNPLUGGED:
4212                return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
4213        }
4214        return 0;
4215    }
4216
4217    long getBatteryUptimeLocked(long curTime) {
4218        long time = mTrackBatteryPastUptime;
4219        if (mOnBatteryInternal) {
4220            time += curTime - mTrackBatteryUptimeStart;
4221        }
4222        return time;
4223    }
4224
4225    long getBatteryUptimeLocked() {
4226        return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
4227    }
4228
4229    @Override
4230    public long getBatteryUptime(long curTime) {
4231        return getBatteryUptimeLocked(curTime);
4232    }
4233
4234    long getBatteryRealtimeLocked(long curTime) {
4235        long time = mTrackBatteryPastRealtime;
4236        if (mOnBatteryInternal) {
4237            time += curTime - mTrackBatteryRealtimeStart;
4238        }
4239        return time;
4240    }
4241
4242    @Override
4243    public long getBatteryRealtime(long curTime) {
4244        return getBatteryRealtimeLocked(curTime);
4245    }
4246
4247    private long getTcpBytes(long current, long[] dataBytes, int which) {
4248        if (which == STATS_LAST) {
4249            return dataBytes[STATS_LAST];
4250        } else {
4251            if (which == STATS_SINCE_UNPLUGGED) {
4252                if (dataBytes[STATS_SINCE_UNPLUGGED] < 0) {
4253                    return dataBytes[STATS_LAST];
4254                } else {
4255                    return current - dataBytes[STATS_SINCE_UNPLUGGED];
4256                }
4257            } else if (which == STATS_SINCE_CHARGED) {
4258                return (current - dataBytes[STATS_CURRENT]) + dataBytes[STATS_SINCE_CHARGED];
4259            }
4260            return current - dataBytes[STATS_CURRENT];
4261        }
4262    }
4263
4264    /** Only STATS_UNPLUGGED works properly */
4265    public long getMobileTcpBytesSent(int which) {
4266        return getTcpBytes(TrafficStats.getMobileTxBytes(), mMobileDataTx, which);
4267    }
4268
4269    /** Only STATS_UNPLUGGED works properly */
4270    public long getMobileTcpBytesReceived(int which) {
4271        return getTcpBytes(TrafficStats.getMobileRxBytes(), mMobileDataRx, which);
4272    }
4273
4274    /** Only STATS_UNPLUGGED works properly */
4275    public long getTotalTcpBytesSent(int which) {
4276        return getTcpBytes(TrafficStats.getTotalTxBytes(), mTotalDataTx, which);
4277    }
4278
4279    /** Only STATS_UNPLUGGED works properly */
4280    public long getTotalTcpBytesReceived(int which) {
4281        return getTcpBytes(TrafficStats.getTotalRxBytes(), mTotalDataRx, which);
4282    }
4283
4284    @Override
4285    public int getDischargeStartLevel() {
4286        synchronized(this) {
4287            return getDischargeStartLevelLocked();
4288        }
4289    }
4290
4291    public int getDischargeStartLevelLocked() {
4292            return mDischargeUnplugLevel;
4293    }
4294
4295    @Override
4296    public int getDischargeCurrentLevel() {
4297        synchronized(this) {
4298            return getDischargeCurrentLevelLocked();
4299        }
4300    }
4301
4302    public int getDischargeCurrentLevelLocked() {
4303            return mDischargeCurrentLevel;
4304    }
4305
4306    @Override
4307    public int getLowDischargeAmountSinceCharge() {
4308        synchronized(this) {
4309            return mLowDischargeAmountSinceCharge;
4310        }
4311    }
4312
4313    @Override
4314    public int getHighDischargeAmountSinceCharge() {
4315        synchronized(this) {
4316            return mHighDischargeAmountSinceCharge;
4317        }
4318    }
4319
4320    @Override
4321    public int getCpuSpeedSteps() {
4322        return sNumSpeedSteps;
4323    }
4324
4325    /**
4326     * Retrieve the statistics object for a particular uid, creating if needed.
4327     */
4328    public Uid getUidStatsLocked(int uid) {
4329        Uid u = mUidStats.get(uid);
4330        if (u == null) {
4331            u = new Uid(uid);
4332            mUidStats.put(uid, u);
4333        }
4334        return u;
4335    }
4336
4337    /**
4338     * Remove the statistics object for a particular uid.
4339     */
4340    public void removeUidStatsLocked(int uid) {
4341        mUidStats.remove(uid);
4342    }
4343
4344    /**
4345     * Retrieve the statistics object for a particular process, creating
4346     * if needed.
4347     */
4348    public Uid.Proc getProcessStatsLocked(int uid, String name) {
4349        Uid u = getUidStatsLocked(uid);
4350        return u.getProcessStatsLocked(name);
4351    }
4352
4353    /**
4354     * Retrieve the statistics object for a particular process, given
4355     * the name of the process.
4356     * @param name process name
4357     * @return the statistics object for the process
4358     */
4359    public Uid.Proc getProcessStatsLocked(String name, int pid) {
4360        int uid;
4361        if (mUidCache.containsKey(name)) {
4362            uid = mUidCache.get(name);
4363        } else {
4364            uid = Process.getUidForPid(pid);
4365            mUidCache.put(name, uid);
4366        }
4367        Uid u = getUidStatsLocked(uid);
4368        return u.getProcessStatsLocked(name);
4369    }
4370
4371    /**
4372     * Retrieve the statistics object for a particular process, creating
4373     * if needed.
4374     */
4375    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
4376        Uid u = getUidStatsLocked(uid);
4377        return u.getPackageStatsLocked(pkg);
4378    }
4379
4380    /**
4381     * Retrieve the statistics object for a particular service, creating
4382     * if needed.
4383     */
4384    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
4385        Uid u = getUidStatsLocked(uid);
4386        return u.getServiceStatsLocked(pkg, name);
4387    }
4388
4389    /**
4390     * Massage data to distribute any reasonable work down to more specific
4391     * owners.  Must only be called on a dead BatteryStats object!
4392     */
4393    public void distributeWorkLocked(int which) {
4394        // Aggregate all CPU time associated with WIFI.
4395        Uid wifiUid = mUidStats.get(Process.WIFI_UID);
4396        if (wifiUid != null) {
4397            long uSecTime = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
4398            for (Uid.Proc proc : wifiUid.mProcessStats.values()) {
4399                long totalRunningTime = getGlobalWifiRunningTime(uSecTime, which);
4400                for (int i=0; i<mUidStats.size(); i++) {
4401                    Uid uid = mUidStats.valueAt(i);
4402                    if (uid.mUid != Process.WIFI_UID) {
4403                        long uidRunningTime = uid.getWifiRunningTime(uSecTime, which);
4404                        if (uidRunningTime > 0) {
4405                            Uid.Proc uidProc = uid.getProcessStatsLocked("*wifi*");
4406                            long time = proc.getUserTime(which);
4407                            time = (time*uidRunningTime)/totalRunningTime;
4408                            uidProc.mUserTime += time;
4409                            proc.mUserTime -= time;
4410                            time = proc.getSystemTime(which);
4411                            time = (time*uidRunningTime)/totalRunningTime;
4412                            uidProc.mSystemTime += time;
4413                            proc.mSystemTime -= time;
4414                            time = proc.getForegroundTime(which);
4415                            time = (time*uidRunningTime)/totalRunningTime;
4416                            uidProc.mForegroundTime += time;
4417                            proc.mForegroundTime -= time;
4418                            for (int sb=0; sb<proc.mSpeedBins.length; sb++) {
4419                                SamplingCounter sc = proc.mSpeedBins[sb];
4420                                if (sc != null) {
4421                                    time = sc.getCountLocked(which);
4422                                    time = (time*uidRunningTime)/totalRunningTime;
4423                                    SamplingCounter uidSc = uidProc.mSpeedBins[sb];
4424                                    if (uidSc == null) {
4425                                        uidSc = new SamplingCounter(mUnpluggables);
4426                                        uidProc.mSpeedBins[sb] = uidSc;
4427                                    }
4428                                    uidSc.mCount.addAndGet((int)time);
4429                                    sc.mCount.addAndGet((int)-time);
4430                                }
4431                            }
4432                            totalRunningTime -= uidRunningTime;
4433                        }
4434                    }
4435                }
4436            }
4437        }
4438    }
4439
4440    public void shutdownLocked() {
4441        writeSyncLocked();
4442        mShuttingDown = true;
4443    }
4444
4445    Parcel mPendingWrite = null;
4446    final ReentrantLock mWriteLock = new ReentrantLock();
4447
4448    public void writeAsyncLocked() {
4449        writeLocked(false);
4450    }
4451
4452    public void writeSyncLocked() {
4453        writeLocked(true);
4454    }
4455
4456    void writeLocked(boolean sync) {
4457        if (mFile == null) {
4458            Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
4459            return;
4460        }
4461
4462        if (mShuttingDown) {
4463            return;
4464        }
4465
4466        Parcel out = Parcel.obtain();
4467        writeSummaryToParcel(out);
4468        mLastWriteTime = SystemClock.elapsedRealtime();
4469
4470        if (mPendingWrite != null) {
4471            mPendingWrite.recycle();
4472        }
4473        mPendingWrite = out;
4474
4475        if (sync) {
4476            commitPendingDataToDisk();
4477        } else {
4478            Thread thr = new Thread("BatteryStats-Write") {
4479                @Override
4480                public void run() {
4481                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
4482                    commitPendingDataToDisk();
4483                }
4484            };
4485            thr.start();
4486        }
4487    }
4488
4489    public void commitPendingDataToDisk() {
4490        final Parcel next;
4491        synchronized (this) {
4492            next = mPendingWrite;
4493            mPendingWrite = null;
4494            if (next == null) {
4495                return;
4496            }
4497
4498            mWriteLock.lock();
4499        }
4500
4501        try {
4502            FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
4503            stream.write(next.marshall());
4504            stream.flush();
4505            FileUtils.sync(stream);
4506            stream.close();
4507            mFile.commit();
4508        } catch (IOException e) {
4509            Slog.w("BatteryStats", "Error writing battery statistics", e);
4510            mFile.rollback();
4511        } finally {
4512            next.recycle();
4513            mWriteLock.unlock();
4514        }
4515    }
4516
4517    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
4518        int pos = 0;
4519        int avail = stream.available();
4520        byte[] data = new byte[avail];
4521        while (true) {
4522            int amt = stream.read(data, pos, data.length-pos);
4523            //Log.i("foo", "Read " + amt + " bytes at " + pos
4524            //        + " of avail " + data.length);
4525            if (amt <= 0) {
4526                //Log.i("foo", "**** FINISHED READING: pos=" + pos
4527                //        + " len=" + data.length);
4528                return data;
4529            }
4530            pos += amt;
4531            avail = stream.available();
4532            if (avail > data.length-pos) {
4533                byte[] newData = new byte[pos+avail];
4534                System.arraycopy(data, 0, newData, 0, pos);
4535                data = newData;
4536            }
4537        }
4538    }
4539
4540    public void readLocked() {
4541        if (mFile == null) {
4542            Slog.w("BatteryStats", "readLocked: no file associated with this instance");
4543            return;
4544        }
4545
4546        mUidStats.clear();
4547
4548        try {
4549            File file = mFile.chooseForRead();
4550            if (!file.exists()) {
4551                return;
4552            }
4553            FileInputStream stream = new FileInputStream(file);
4554
4555            byte[] raw = readFully(stream);
4556            Parcel in = Parcel.obtain();
4557            in.unmarshall(raw, 0, raw.length);
4558            in.setDataPosition(0);
4559            stream.close();
4560
4561            readSummaryFromParcel(in);
4562        } catch(java.io.IOException e) {
4563            Slog.e("BatteryStats", "Error reading battery statistics", e);
4564        }
4565
4566        addHistoryRecordLocked(SystemClock.elapsedRealtime(), HistoryItem.CMD_START);
4567    }
4568
4569    public int describeContents() {
4570        return 0;
4571    }
4572
4573    void readHistory(Parcel in) {
4574        mHistory = mHistoryEnd = mHistoryCache = null;
4575        mHistoryBaseTime = 0;
4576        long time;
4577        while ((time=in.readLong()) >= 0) {
4578            HistoryItem rec = new HistoryItem(time, in);
4579            addHistoryRecordLocked(rec);
4580            if (rec.time > mHistoryBaseTime) {
4581                mHistoryBaseTime = rec.time;
4582            }
4583        }
4584
4585        long oldnow = SystemClock.elapsedRealtime() - (5*60*100);
4586        if (oldnow > 0) {
4587            // If the system process has restarted, but not the entire
4588            // system, then the mHistoryBaseTime already accounts for
4589            // much of the elapsed time.  We thus want to adjust it back,
4590            // to avoid large gaps in the data.  We determine we are
4591            // in this case by arbitrarily saying it is so if at this
4592            // point in boot the elapsed time is already more than 5 seconds.
4593            mHistoryBaseTime -= oldnow;
4594        }
4595    }
4596
4597    void writeHistory(Parcel out) {
4598        HistoryItem rec = mHistory;
4599        while (rec != null) {
4600            if (rec.time >= 0) rec.writeToParcel(out, 0);
4601            rec = rec.next;
4602        }
4603        out.writeLong(-1);
4604    }
4605
4606    private void readSummaryFromParcel(Parcel in) {
4607        final int version = in.readInt();
4608        if (version != VERSION) {
4609            Slog.w("BatteryStats", "readFromParcel: version got " + version
4610                + ", expected " + VERSION + "; erasing old stats");
4611            return;
4612        }
4613
4614        readHistory(in);
4615
4616        mStartCount = in.readInt();
4617        mBatteryUptime = in.readLong();
4618        mBatteryRealtime = in.readLong();
4619        mUptime = in.readLong();
4620        mRealtime = in.readLong();
4621        mDischargeUnplugLevel = in.readInt();
4622        mDischargeCurrentLevel = in.readInt();
4623        mLowDischargeAmountSinceCharge = in.readInt();
4624        mHighDischargeAmountSinceCharge = in.readInt();
4625
4626        mStartCount++;
4627
4628        mScreenOn = false;
4629        mScreenOnTimer.readSummaryFromParcelLocked(in);
4630        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4631            mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
4632        }
4633        mInputEventCounter.readSummaryFromParcelLocked(in);
4634        mPhoneOn = false;
4635        mPhoneOnTimer.readSummaryFromParcelLocked(in);
4636        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
4637            mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
4638        }
4639        mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
4640        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4641            mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
4642        }
4643        mWifiOn = false;
4644        mWifiOnTimer.readSummaryFromParcelLocked(in);
4645        mGlobalWifiRunning = false;
4646        mGlobalWifiRunningTimer.readSummaryFromParcelLocked(in);
4647        mBluetoothOn = false;
4648        mBluetoothOnTimer.readSummaryFromParcelLocked(in);
4649
4650        int NKW = in.readInt();
4651        if (NKW > 10000) {
4652            Slog.w(TAG, "File corrupt: too many kernel wake locks " + NKW);
4653            return;
4654        }
4655        for (int ikw = 0; ikw < NKW; ikw++) {
4656            if (in.readInt() != 0) {
4657                String kwltName = in.readString();
4658                getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
4659            }
4660        }
4661
4662        sNumSpeedSteps = in.readInt();
4663
4664        final int NU = in.readInt();
4665        if (NU > 10000) {
4666            Slog.w(TAG, "File corrupt: too many uids " + NU);
4667            return;
4668        }
4669        for (int iu = 0; iu < NU; iu++) {
4670            int uid = in.readInt();
4671            Uid u = new Uid(uid);
4672            mUidStats.put(uid, u);
4673
4674            u.mWifiRunning = false;
4675            if (in.readInt() != 0) {
4676                u.mWifiRunningTimer.readSummaryFromParcelLocked(in);
4677            }
4678            u.mFullWifiLockOut = false;
4679            if (in.readInt() != 0) {
4680                u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
4681            }
4682            u.mScanWifiLockOut = false;
4683            if (in.readInt() != 0) {
4684                u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
4685            }
4686            u.mWifiMulticastEnabled = false;
4687            if (in.readInt() != 0) {
4688                u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
4689            }
4690            u.mAudioTurnedOn = false;
4691            if (in.readInt() != 0) {
4692                u.mAudioTurnedOnTimer.readSummaryFromParcelLocked(in);
4693            }
4694            u.mVideoTurnedOn = false;
4695            if (in.readInt() != 0) {
4696                u.mVideoTurnedOnTimer.readSummaryFromParcelLocked(in);
4697            }
4698
4699            if (in.readInt() != 0) {
4700                if (u.mUserActivityCounters == null) {
4701                    u.initUserActivityLocked();
4702                }
4703                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
4704                    u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
4705                }
4706            }
4707
4708            int NW = in.readInt();
4709            if (NW > 100) {
4710                Slog.w(TAG, "File corrupt: too many wake locks " + NW);
4711                return;
4712            }
4713            for (int iw = 0; iw < NW; iw++) {
4714                String wlName = in.readString();
4715                if (in.readInt() != 0) {
4716                    u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
4717                }
4718                if (in.readInt() != 0) {
4719                    u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
4720                }
4721                if (in.readInt() != 0) {
4722                    u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
4723                }
4724            }
4725
4726            int NP = in.readInt();
4727            if (NP > 1000) {
4728                Slog.w(TAG, "File corrupt: too many sensors " + NP);
4729                return;
4730            }
4731            for (int is = 0; is < NP; is++) {
4732                int seNumber = in.readInt();
4733                if (in.readInt() != 0) {
4734                    u.getSensorTimerLocked(seNumber, true)
4735                            .readSummaryFromParcelLocked(in);
4736                }
4737            }
4738
4739            NP = in.readInt();
4740            if (NP > 1000) {
4741                Slog.w(TAG, "File corrupt: too many processes " + NP);
4742                return;
4743            }
4744            for (int ip = 0; ip < NP; ip++) {
4745                String procName = in.readString();
4746                Uid.Proc p = u.getProcessStatsLocked(procName);
4747                p.mUserTime = p.mLoadedUserTime = in.readLong();
4748                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
4749                p.mStarts = p.mLoadedStarts = in.readInt();
4750                int NSB = in.readInt();
4751                if (NSB > 100) {
4752                    Slog.w(TAG, "File corrupt: too many speed bins " + NSB);
4753                    return;
4754                }
4755                p.mSpeedBins = new SamplingCounter[NSB];
4756                for (int i=0; i<NSB; i++) {
4757                    if (in.readInt() != 0) {
4758                        p.mSpeedBins[i] = new SamplingCounter(mUnpluggables);
4759                        p.mSpeedBins[i].readSummaryFromParcelLocked(in);
4760                    }
4761                }
4762                if (!p.readExcessivePowerFromParcelLocked(in)) {
4763                    return;
4764                }
4765            }
4766
4767            NP = in.readInt();
4768            if (NP > 10000) {
4769                Slog.w(TAG, "File corrupt: too many packages " + NP);
4770                return;
4771            }
4772            for (int ip = 0; ip < NP; ip++) {
4773                String pkgName = in.readString();
4774                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
4775                p.mWakeups = p.mLoadedWakeups = in.readInt();
4776                final int NS = in.readInt();
4777                if (NS > 1000) {
4778                    Slog.w(TAG, "File corrupt: too many services " + NS);
4779                    return;
4780                }
4781                for (int is = 0; is < NS; is++) {
4782                    String servName = in.readString();
4783                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
4784                    s.mStartTime = s.mLoadedStartTime = in.readLong();
4785                    s.mStarts = s.mLoadedStarts = in.readInt();
4786                    s.mLaunches = s.mLoadedLaunches = in.readInt();
4787                }
4788            }
4789
4790            u.mLoadedTcpBytesReceived = in.readLong();
4791            u.mLoadedTcpBytesSent = in.readLong();
4792        }
4793    }
4794
4795    /**
4796     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
4797     * disk.  This format does not allow a lossless round-trip.
4798     *
4799     * @param out the Parcel to be written to.
4800     */
4801    public void writeSummaryToParcel(Parcel out) {
4802        final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
4803        final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
4804        final long NOW = getBatteryUptimeLocked(NOW_SYS);
4805        final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
4806
4807        out.writeInt(VERSION);
4808
4809        writeHistory(out);
4810
4811        out.writeInt(mStartCount);
4812        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_SINCE_CHARGED));
4813        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
4814        out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
4815        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
4816        out.writeInt(mDischargeUnplugLevel);
4817        out.writeInt(mDischargeCurrentLevel);
4818        out.writeInt(mLowDischargeAmountSinceCharge);
4819        out.writeInt(mHighDischargeAmountSinceCharge);
4820
4821        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4822        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4823            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
4824        }
4825        mInputEventCounter.writeSummaryFromParcelLocked(out);
4826        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4827        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
4828            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
4829        }
4830        mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4831        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4832            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
4833        }
4834        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4835        mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4836        mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4837
4838        out.writeInt(mKernelWakelockStats.size());
4839        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
4840            Timer kwlt = ent.getValue();
4841            if (kwlt != null) {
4842                out.writeInt(1);
4843                out.writeString(ent.getKey());
4844                ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
4845            } else {
4846                out.writeInt(0);
4847            }
4848        }
4849
4850        out.writeInt(sNumSpeedSteps);
4851        final int NU = mUidStats.size();
4852        out.writeInt(NU);
4853        for (int iu = 0; iu < NU; iu++) {
4854            out.writeInt(mUidStats.keyAt(iu));
4855            Uid u = mUidStats.valueAt(iu);
4856
4857            if (u.mWifiRunningTimer != null) {
4858                out.writeInt(1);
4859                u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4860            } else {
4861                out.writeInt(0);
4862            }
4863            if (u.mFullWifiLockTimer != null) {
4864                out.writeInt(1);
4865                u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4866            } else {
4867                out.writeInt(0);
4868            }
4869            if (u.mScanWifiLockTimer != null) {
4870                out.writeInt(1);
4871                u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4872            } else {
4873                out.writeInt(0);
4874            }
4875            if (u.mWifiMulticastTimer != null) {
4876                out.writeInt(1);
4877                u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4878            } else {
4879                out.writeInt(0);
4880            }
4881            if (u.mAudioTurnedOnTimer != null) {
4882                out.writeInt(1);
4883                u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4884            } else {
4885                out.writeInt(0);
4886            }
4887            if (u.mVideoTurnedOnTimer != null) {
4888                out.writeInt(1);
4889                u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4890            } else {
4891                out.writeInt(0);
4892            }
4893
4894            if (u.mUserActivityCounters == null) {
4895                out.writeInt(0);
4896            } else {
4897                out.writeInt(1);
4898                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
4899                    u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
4900                }
4901            }
4902
4903            int NW = u.mWakelockStats.size();
4904            out.writeInt(NW);
4905            if (NW > 0) {
4906                for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
4907                        : u.mWakelockStats.entrySet()) {
4908                    out.writeString(ent.getKey());
4909                    Uid.Wakelock wl = ent.getValue();
4910                    if (wl.mTimerFull != null) {
4911                        out.writeInt(1);
4912                        wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
4913                    } else {
4914                        out.writeInt(0);
4915                    }
4916                    if (wl.mTimerPartial != null) {
4917                        out.writeInt(1);
4918                        wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
4919                    } else {
4920                        out.writeInt(0);
4921                    }
4922                    if (wl.mTimerWindow != null) {
4923                        out.writeInt(1);
4924                        wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
4925                    } else {
4926                        out.writeInt(0);
4927                    }
4928                }
4929            }
4930
4931            int NSE = u.mSensorStats.size();
4932            out.writeInt(NSE);
4933            if (NSE > 0) {
4934                for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
4935                        : u.mSensorStats.entrySet()) {
4936                    out.writeInt(ent.getKey());
4937                    Uid.Sensor se = ent.getValue();
4938                    if (se.mTimer != null) {
4939                        out.writeInt(1);
4940                        se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4941                    } else {
4942                        out.writeInt(0);
4943                    }
4944                }
4945            }
4946
4947            int NP = u.mProcessStats.size();
4948            out.writeInt(NP);
4949            if (NP > 0) {
4950                for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
4951                    : u.mProcessStats.entrySet()) {
4952                    out.writeString(ent.getKey());
4953                    Uid.Proc ps = ent.getValue();
4954                    out.writeLong(ps.mUserTime);
4955                    out.writeLong(ps.mSystemTime);
4956                    out.writeInt(ps.mStarts);
4957                    final int N = ps.mSpeedBins.length;
4958                    out.writeInt(N);
4959                    for (int i=0; i<N; i++) {
4960                        if (ps.mSpeedBins[i] != null) {
4961                            out.writeInt(1);
4962                            ps.mSpeedBins[i].writeSummaryFromParcelLocked(out);
4963                        } else {
4964                            out.writeInt(0);
4965                        }
4966                    }
4967                    ps.writeExcessivePowerToParcelLocked(out);
4968                }
4969            }
4970
4971            NP = u.mPackageStats.size();
4972            out.writeInt(NP);
4973            if (NP > 0) {
4974                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
4975                    : u.mPackageStats.entrySet()) {
4976                    out.writeString(ent.getKey());
4977                    Uid.Pkg ps = ent.getValue();
4978                    out.writeInt(ps.mWakeups);
4979                    final int NS = ps.mServiceStats.size();
4980                    out.writeInt(NS);
4981                    if (NS > 0) {
4982                        for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
4983                                : ps.mServiceStats.entrySet()) {
4984                            out.writeString(sent.getKey());
4985                            BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
4986                            long time = ss.getStartTimeToNowLocked(NOW);
4987                            out.writeLong(time);
4988                            out.writeInt(ss.mStarts);
4989                            out.writeInt(ss.mLaunches);
4990                        }
4991                    }
4992                }
4993            }
4994
4995            out.writeLong(u.getTcpBytesReceived(STATS_SINCE_CHARGED));
4996            out.writeLong(u.getTcpBytesSent(STATS_SINCE_CHARGED));
4997        }
4998    }
4999
5000    public void readFromParcel(Parcel in) {
5001        readFromParcelLocked(in);
5002    }
5003
5004    void readFromParcelLocked(Parcel in) {
5005        int magic = in.readInt();
5006        if (magic != MAGIC) {
5007            throw new ParcelFormatException("Bad magic number");
5008        }
5009
5010        readHistory(in);
5011
5012        mStartCount = in.readInt();
5013        mBatteryUptime = in.readLong();
5014        mBatteryLastUptime = 0;
5015        mBatteryRealtime = in.readLong();
5016        mBatteryLastRealtime = 0;
5017        mScreenOn = false;
5018        mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables, in);
5019        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5020            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i,
5021                    null, mUnpluggables, in);
5022        }
5023        mInputEventCounter = new Counter(mUnpluggables, in);
5024        mPhoneOn = false;
5025        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5026        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
5027            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
5028                    null, mUnpluggables, in);
5029        }
5030        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables, in);
5031        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5032            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
5033                    null, mUnpluggables, in);
5034        }
5035        mWifiOn = false;
5036        mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5037        mGlobalWifiRunning = false;
5038        mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5039        mBluetoothOn = false;
5040        mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
5041        mUptime = in.readLong();
5042        mUptimeStart = in.readLong();
5043        mLastUptime = 0;
5044        mRealtime = in.readLong();
5045        mRealtimeStart = in.readLong();
5046        mLastRealtime = 0;
5047        mOnBattery = in.readInt() != 0;
5048        mOnBatteryInternal = false; // we are no longer really running.
5049        mTrackBatteryPastUptime = in.readLong();
5050        mTrackBatteryUptimeStart = in.readLong();
5051        mTrackBatteryPastRealtime = in.readLong();
5052        mTrackBatteryRealtimeStart = in.readLong();
5053        mUnpluggedBatteryUptime = in.readLong();
5054        mUnpluggedBatteryRealtime = in.readLong();
5055        mDischargeUnplugLevel = in.readInt();
5056        mDischargeCurrentLevel = in.readInt();
5057        mLowDischargeAmountSinceCharge = in.readInt();
5058        mHighDischargeAmountSinceCharge = in.readInt();
5059        mLastWriteTime = in.readLong();
5060
5061        mMobileDataRx[STATS_LAST] = in.readLong();
5062        mMobileDataRx[STATS_SINCE_UNPLUGGED] = -1;
5063        mMobileDataTx[STATS_LAST] = in.readLong();
5064        mMobileDataTx[STATS_SINCE_UNPLUGGED] = -1;
5065        mTotalDataRx[STATS_LAST] = in.readLong();
5066        mTotalDataRx[STATS_SINCE_UNPLUGGED] = -1;
5067        mTotalDataTx[STATS_LAST] = in.readLong();
5068        mTotalDataTx[STATS_SINCE_UNPLUGGED] = -1;
5069
5070        mRadioDataUptime = in.readLong();
5071        mRadioDataStart = -1;
5072
5073        mBluetoothPingCount = in.readInt();
5074        mBluetoothPingStart = -1;
5075
5076        mKernelWakelockStats.clear();
5077        int NKW = in.readInt();
5078        for (int ikw = 0; ikw < NKW; ikw++) {
5079            if (in.readInt() != 0) {
5080                String wakelockName = in.readString();
5081                in.readInt(); // Extra 0/1 written by Timer.writeTimerToParcel
5082                SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
5083                mKernelWakelockStats.put(wakelockName, kwlt);
5084            }
5085        }
5086
5087        mPartialTimers.clear();
5088        mFullTimers.clear();
5089        mWindowTimers.clear();
5090        mWifiRunningTimers.clear();
5091        mFullWifiLockTimers.clear();
5092        mScanWifiLockTimers.clear();
5093        mWifiMulticastTimers.clear();
5094
5095        sNumSpeedSteps = in.readInt();
5096
5097        int numUids = in.readInt();
5098        mUidStats.clear();
5099        for (int i = 0; i < numUids; i++) {
5100            int uid = in.readInt();
5101            Uid u = new Uid(uid);
5102            u.readFromParcelLocked(mUnpluggables, in);
5103            mUidStats.append(uid, u);
5104        }
5105    }
5106
5107    public void writeToParcel(Parcel out, int flags) {
5108        writeToParcelLocked(out, true, flags);
5109    }
5110
5111    public void writeToParcelWithoutUids(Parcel out, int flags) {
5112        writeToParcelLocked(out, false, flags);
5113    }
5114
5115    @SuppressWarnings("unused")
5116    void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
5117        final long uSecUptime = SystemClock.uptimeMillis() * 1000;
5118        final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
5119        final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
5120        final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
5121
5122        out.writeInt(MAGIC);
5123
5124        writeHistory(out);
5125
5126        out.writeInt(mStartCount);
5127        out.writeLong(mBatteryUptime);
5128        out.writeLong(mBatteryRealtime);
5129        mScreenOnTimer.writeToParcel(out, batteryRealtime);
5130        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5131            mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
5132        }
5133        mInputEventCounter.writeToParcel(out);
5134        mPhoneOnTimer.writeToParcel(out, batteryRealtime);
5135        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
5136            mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
5137        }
5138        mPhoneSignalScanningTimer.writeToParcel(out, batteryRealtime);
5139        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5140            mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
5141        }
5142        mWifiOnTimer.writeToParcel(out, batteryRealtime);
5143        mGlobalWifiRunningTimer.writeToParcel(out, batteryRealtime);
5144        mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
5145        out.writeLong(mUptime);
5146        out.writeLong(mUptimeStart);
5147        out.writeLong(mRealtime);
5148        out.writeLong(mRealtimeStart);
5149        out.writeInt(mOnBattery ? 1 : 0);
5150        out.writeLong(batteryUptime);
5151        out.writeLong(mTrackBatteryUptimeStart);
5152        out.writeLong(batteryRealtime);
5153        out.writeLong(mTrackBatteryRealtimeStart);
5154        out.writeLong(mUnpluggedBatteryUptime);
5155        out.writeLong(mUnpluggedBatteryRealtime);
5156        out.writeInt(mDischargeUnplugLevel);
5157        out.writeInt(mDischargeCurrentLevel);
5158        out.writeInt(mLowDischargeAmountSinceCharge);
5159        out.writeInt(mHighDischargeAmountSinceCharge);
5160        out.writeLong(mLastWriteTime);
5161
5162        out.writeLong(getMobileTcpBytesReceived(STATS_SINCE_UNPLUGGED));
5163        out.writeLong(getMobileTcpBytesSent(STATS_SINCE_UNPLUGGED));
5164        out.writeLong(getTotalTcpBytesReceived(STATS_SINCE_UNPLUGGED));
5165        out.writeLong(getTotalTcpBytesSent(STATS_SINCE_UNPLUGGED));
5166
5167        // Write radio uptime for data
5168        out.writeLong(getRadioDataUptime());
5169
5170        out.writeInt(getBluetoothPingCount());
5171
5172        if (inclUids) {
5173            out.writeInt(mKernelWakelockStats.size());
5174            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
5175                SamplingTimer kwlt = ent.getValue();
5176                if (kwlt != null) {
5177                    out.writeInt(1);
5178                    out.writeString(ent.getKey());
5179                    Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
5180                } else {
5181                    out.writeInt(0);
5182                }
5183            }
5184        } else {
5185            out.writeInt(0);
5186        }
5187
5188        out.writeInt(sNumSpeedSteps);
5189
5190        if (inclUids) {
5191            int size = mUidStats.size();
5192            out.writeInt(size);
5193            for (int i = 0; i < size; i++) {
5194                out.writeInt(mUidStats.keyAt(i));
5195                Uid uid = mUidStats.valueAt(i);
5196
5197                uid.writeToParcelLocked(out, batteryRealtime);
5198            }
5199        } else {
5200            out.writeInt(0);
5201        }
5202    }
5203
5204    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
5205        new Parcelable.Creator<BatteryStatsImpl>() {
5206        public BatteryStatsImpl createFromParcel(Parcel in) {
5207            return new BatteryStatsImpl(in);
5208        }
5209
5210        public BatteryStatsImpl[] newArray(int size) {
5211            return new BatteryStatsImpl[size];
5212        }
5213    };
5214
5215    public void dumpLocked(PrintWriter pw) {
5216        if (DEBUG) {
5217            Printer pr = new PrintWriterPrinter(pw);
5218            pr.println("*** Screen timer:");
5219            mScreenOnTimer.logState(pr, "  ");
5220            for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
5221                pr.println("*** Screen brightness #" + i + ":");
5222                mScreenBrightnessTimer[i].logState(pr, "  ");
5223            }
5224            pr.println("*** Input event counter:");
5225            mInputEventCounter.logState(pr, "  ");
5226            pr.println("*** Phone timer:");
5227            mPhoneOnTimer.logState(pr, "  ");
5228            for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
5229                pr.println("*** Signal strength #" + i + ":");
5230                mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
5231            }
5232            pr.println("*** Signal scanning :");
5233            mPhoneSignalScanningTimer.logState(pr, "  ");
5234            for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
5235                pr.println("*** Data connection type #" + i + ":");
5236                mPhoneDataConnectionsTimer[i].logState(pr, "  ");
5237            }
5238            pr.println("*** Wifi timer:");
5239            mWifiOnTimer.logState(pr, "  ");
5240            pr.println("*** WifiRunning timer:");
5241            mGlobalWifiRunningTimer.logState(pr, "  ");
5242            pr.println("*** Bluetooth timer:");
5243            mBluetoothOnTimer.logState(pr, "  ");
5244        }
5245        super.dumpLocked(pw);
5246    }
5247}
5248