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