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