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