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