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