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