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