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