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