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