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