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