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