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