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