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