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