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