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