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