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