BatteryStatsImpl.java revision d9b99be587962e5cb696327cf837f8b82ecd6b5c
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 = 142 + (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_DEEP;
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_DEEP) {
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_DEEP) {
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            mBluetoothScanTimer.startRunningLocked(elapsedRealtime);
4016        }
4017        mBluetoothScanNesting++;
4018        getUidStatsLocked(uid).noteBluetoothScanStartedLocked(elapsedRealtime);
4019    }
4020
4021    public void noteBluetoothScanStartedFromSourceLocked(WorkSource ws) {
4022        final int N = ws.size();
4023        for (int i = 0; i < N; i++) {
4024            noteBluetoothScanStartedLocked(ws.get(i));
4025        }
4026    }
4027
4028    private void noteBluetoothScanStoppedLocked(int uid) {
4029        uid = mapUid(uid);
4030        final long elapsedRealtime = SystemClock.elapsedRealtime();
4031        final long uptime = SystemClock.uptimeMillis();
4032        mBluetoothScanNesting--;
4033        if (mBluetoothScanNesting == 0) {
4034            mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
4035            if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan stopped for: "
4036                    + Integer.toHexString(mHistoryCur.states2));
4037            addHistoryRecordLocked(elapsedRealtime, uptime);
4038            mBluetoothScanTimer.stopRunningLocked(elapsedRealtime);
4039        }
4040        getUidStatsLocked(uid).noteBluetoothScanStoppedLocked(elapsedRealtime);
4041    }
4042
4043    public void noteBluetoothScanStoppedFromSourceLocked(WorkSource ws) {
4044        final int N = ws.size();
4045        for (int i = 0; i < N; i++) {
4046            noteBluetoothScanStoppedLocked(ws.get(i));
4047        }
4048    }
4049
4050    public void noteResetBluetoothScanLocked() {
4051        if (mBluetoothScanNesting > 0) {
4052            final long elapsedRealtime = SystemClock.elapsedRealtime();
4053            final long uptime = SystemClock.uptimeMillis();
4054            mBluetoothScanNesting = 0;
4055            mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
4056            if (DEBUG_HISTORY) Slog.v(TAG, "BLE can stopped for: "
4057                    + Integer.toHexString(mHistoryCur.states2));
4058            addHistoryRecordLocked(elapsedRealtime, uptime);
4059            mBluetoothScanTimer.stopAllRunningLocked(elapsedRealtime);
4060            for (int i=0; i<mUidStats.size(); i++) {
4061                BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
4062                uid.noteResetBluetoothScanLocked(elapsedRealtime);
4063            }
4064        }
4065    }
4066
4067    public void noteWifiRadioPowerState(int powerState, long timestampNs) {
4068        final long elapsedRealtime = mClocks.elapsedRealtime();
4069        final long uptime = mClocks.uptimeMillis();
4070        if (mWifiRadioPowerState != powerState) {
4071            final boolean active =
4072                    powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
4073                            || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
4074            if (active) {
4075                mHistoryCur.states |= HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG;
4076            } else {
4077                mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG;
4078            }
4079            if (DEBUG_HISTORY) Slog.v(TAG, "Wifi network active " + active + " to: "
4080                    + Integer.toHexString(mHistoryCur.states));
4081            addHistoryRecordLocked(elapsedRealtime, uptime);
4082            mWifiRadioPowerState = powerState;
4083        }
4084    }
4085
4086    public void noteWifiRunningLocked(WorkSource ws) {
4087        if (!mGlobalWifiRunning) {
4088            final long elapsedRealtime = mClocks.elapsedRealtime();
4089            final long uptime = mClocks.uptimeMillis();
4090            mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_RUNNING_FLAG;
4091            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
4092                    + Integer.toHexString(mHistoryCur.states));
4093            addHistoryRecordLocked(elapsedRealtime, uptime);
4094            mGlobalWifiRunning = true;
4095            mGlobalWifiRunningTimer.startRunningLocked(elapsedRealtime);
4096            int N = ws.size();
4097            for (int i=0; i<N; i++) {
4098                int uid = mapUid(ws.get(i));
4099                getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
4100            }
4101            scheduleSyncExternalStatsLocked("wifi-running", ExternalStatsSync.UPDATE_WIFI);
4102        } else {
4103            Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
4104        }
4105    }
4106
4107    public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
4108        if (mGlobalWifiRunning) {
4109            final long elapsedRealtime = mClocks.elapsedRealtime();
4110            int N = oldWs.size();
4111            for (int i=0; i<N; i++) {
4112                int uid = mapUid(oldWs.get(i));
4113                getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
4114            }
4115            N = newWs.size();
4116            for (int i=0; i<N; i++) {
4117                int uid = mapUid(newWs.get(i));
4118                getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
4119            }
4120        } else {
4121            Log.w(TAG, "noteWifiRunningChangedLocked -- called while WIFI not running");
4122        }
4123    }
4124
4125    public void noteWifiStoppedLocked(WorkSource ws) {
4126        if (mGlobalWifiRunning) {
4127            final long elapsedRealtime = mClocks.elapsedRealtime();
4128            final long uptime = mClocks.uptimeMillis();
4129            mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_RUNNING_FLAG;
4130            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
4131                    + Integer.toHexString(mHistoryCur.states));
4132            addHistoryRecordLocked(elapsedRealtime, uptime);
4133            mGlobalWifiRunning = false;
4134            mGlobalWifiRunningTimer.stopRunningLocked(elapsedRealtime);
4135            int N = ws.size();
4136            for (int i=0; i<N; i++) {
4137                int uid = mapUid(ws.get(i));
4138                getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
4139            }
4140            scheduleSyncExternalStatsLocked("wifi-stopped", ExternalStatsSync.UPDATE_WIFI);
4141        } else {
4142            Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
4143        }
4144    }
4145
4146    public void noteWifiStateLocked(int wifiState, String accessPoint) {
4147        if (DEBUG) Log.i(TAG, "WiFi state -> " + wifiState);
4148        if (mWifiState != wifiState) {
4149            final long elapsedRealtime = mClocks.elapsedRealtime();
4150            if (mWifiState >= 0) {
4151                mWifiStateTimer[mWifiState].stopRunningLocked(elapsedRealtime);
4152            }
4153            mWifiState = wifiState;
4154            mWifiStateTimer[wifiState].startRunningLocked(elapsedRealtime);
4155            scheduleSyncExternalStatsLocked("wifi-state", ExternalStatsSync.UPDATE_WIFI);
4156        }
4157    }
4158
4159    public void noteWifiSupplicantStateChangedLocked(int supplState, boolean failedAuth) {
4160        if (DEBUG) Log.i(TAG, "WiFi suppl state -> " + supplState);
4161        if (mWifiSupplState != supplState) {
4162            final long elapsedRealtime = mClocks.elapsedRealtime();
4163            final long uptime = mClocks.uptimeMillis();
4164            if (mWifiSupplState >= 0) {
4165                mWifiSupplStateTimer[mWifiSupplState].stopRunningLocked(elapsedRealtime);
4166            }
4167            mWifiSupplState = supplState;
4168            mWifiSupplStateTimer[supplState].startRunningLocked(elapsedRealtime);
4169            mHistoryCur.states2 =
4170                    (mHistoryCur.states2&~HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK)
4171                    | (supplState << HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT);
4172            if (DEBUG_HISTORY) Slog.v(TAG, "Wifi suppl state " + supplState + " to: "
4173                    + Integer.toHexString(mHistoryCur.states2));
4174            addHistoryRecordLocked(elapsedRealtime, uptime);
4175        }
4176    }
4177
4178    void stopAllWifiSignalStrengthTimersLocked(int except) {
4179        final long elapsedRealtime = mClocks.elapsedRealtime();
4180        for (int i = 0; i < NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
4181            if (i == except) {
4182                continue;
4183            }
4184            while (mWifiSignalStrengthsTimer[i].isRunningLocked()) {
4185                mWifiSignalStrengthsTimer[i].stopRunningLocked(elapsedRealtime);
4186            }
4187        }
4188    }
4189
4190    public void noteWifiRssiChangedLocked(int newRssi) {
4191        int strengthBin = WifiManager.calculateSignalLevel(newRssi, NUM_WIFI_SIGNAL_STRENGTH_BINS);
4192        if (DEBUG) Log.i(TAG, "WiFi rssi -> " + newRssi + " bin=" + strengthBin);
4193        if (mWifiSignalStrengthBin != strengthBin) {
4194            final long elapsedRealtime = mClocks.elapsedRealtime();
4195            final long uptime = mClocks.uptimeMillis();
4196            if (mWifiSignalStrengthBin >= 0) {
4197                mWifiSignalStrengthsTimer[mWifiSignalStrengthBin].stopRunningLocked(
4198                        elapsedRealtime);
4199            }
4200            if (strengthBin >= 0) {
4201                if (!mWifiSignalStrengthsTimer[strengthBin].isRunningLocked()) {
4202                    mWifiSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtime);
4203                }
4204                mHistoryCur.states2 =
4205                        (mHistoryCur.states2&~HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK)
4206                        | (strengthBin << HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT);
4207                if (DEBUG_HISTORY) Slog.v(TAG, "Wifi signal strength " + strengthBin + " to: "
4208                        + Integer.toHexString(mHistoryCur.states2));
4209                addHistoryRecordLocked(elapsedRealtime, uptime);
4210            } else {
4211                stopAllWifiSignalStrengthTimersLocked(-1);
4212            }
4213            mWifiSignalStrengthBin = strengthBin;
4214        }
4215    }
4216
4217    int mWifiFullLockNesting = 0;
4218
4219    public void noteFullWifiLockAcquiredLocked(int uid) {
4220        uid = mapUid(uid);
4221        final long elapsedRealtime = mClocks.elapsedRealtime();
4222        final long uptime = mClocks.uptimeMillis();
4223        if (mWifiFullLockNesting == 0) {
4224            mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
4225            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
4226                    + Integer.toHexString(mHistoryCur.states));
4227            addHistoryRecordLocked(elapsedRealtime, uptime);
4228        }
4229        mWifiFullLockNesting++;
4230        getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked(elapsedRealtime);
4231    }
4232
4233    public void noteFullWifiLockReleasedLocked(int uid) {
4234        uid = mapUid(uid);
4235        final long elapsedRealtime = mClocks.elapsedRealtime();
4236        final long uptime = mClocks.uptimeMillis();
4237        mWifiFullLockNesting--;
4238        if (mWifiFullLockNesting == 0) {
4239            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
4240            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
4241                    + Integer.toHexString(mHistoryCur.states));
4242            addHistoryRecordLocked(elapsedRealtime, uptime);
4243        }
4244        getUidStatsLocked(uid).noteFullWifiLockReleasedLocked(elapsedRealtime);
4245    }
4246
4247    int mWifiScanNesting = 0;
4248
4249    public void noteWifiScanStartedLocked(int uid) {
4250        uid = mapUid(uid);
4251        final long elapsedRealtime = mClocks.elapsedRealtime();
4252        final long uptime = mClocks.uptimeMillis();
4253        if (mWifiScanNesting == 0) {
4254            mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG;
4255            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: "
4256                    + Integer.toHexString(mHistoryCur.states));
4257            addHistoryRecordLocked(elapsedRealtime, uptime);
4258        }
4259        mWifiScanNesting++;
4260        getUidStatsLocked(uid).noteWifiScanStartedLocked(elapsedRealtime);
4261    }
4262
4263    public void noteWifiScanStoppedLocked(int uid) {
4264        uid = mapUid(uid);
4265        final long elapsedRealtime = mClocks.elapsedRealtime();
4266        final long uptime = mClocks.uptimeMillis();
4267        mWifiScanNesting--;
4268        if (mWifiScanNesting == 0) {
4269            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG;
4270            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan stopped for: "
4271                    + Integer.toHexString(mHistoryCur.states));
4272            addHistoryRecordLocked(elapsedRealtime, uptime);
4273        }
4274        getUidStatsLocked(uid).noteWifiScanStoppedLocked(elapsedRealtime);
4275    }
4276
4277    public void noteWifiBatchedScanStartedLocked(int uid, int csph) {
4278        uid = mapUid(uid);
4279        final long elapsedRealtime = mClocks.elapsedRealtime();
4280        getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph, elapsedRealtime);
4281    }
4282
4283    public void noteWifiBatchedScanStoppedLocked(int uid) {
4284        uid = mapUid(uid);
4285        final long elapsedRealtime = mClocks.elapsedRealtime();
4286        getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked(elapsedRealtime);
4287    }
4288
4289    int mWifiMulticastNesting = 0;
4290
4291    public void noteWifiMulticastEnabledLocked(int uid) {
4292        uid = mapUid(uid);
4293        final long elapsedRealtime = mClocks.elapsedRealtime();
4294        final long uptime = mClocks.uptimeMillis();
4295        if (mWifiMulticastNesting == 0) {
4296            mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
4297            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
4298                    + Integer.toHexString(mHistoryCur.states));
4299            addHistoryRecordLocked(elapsedRealtime, uptime);
4300        }
4301        mWifiMulticastNesting++;
4302        getUidStatsLocked(uid).noteWifiMulticastEnabledLocked(elapsedRealtime);
4303    }
4304
4305    public void noteWifiMulticastDisabledLocked(int uid) {
4306        uid = mapUid(uid);
4307        final long elapsedRealtime = mClocks.elapsedRealtime();
4308        final long uptime = mClocks.uptimeMillis();
4309        mWifiMulticastNesting--;
4310        if (mWifiMulticastNesting == 0) {
4311            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
4312            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
4313                    + Integer.toHexString(mHistoryCur.states));
4314            addHistoryRecordLocked(elapsedRealtime, uptime);
4315        }
4316        getUidStatsLocked(uid).noteWifiMulticastDisabledLocked(elapsedRealtime);
4317    }
4318
4319    public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
4320        int N = ws.size();
4321        for (int i=0; i<N; i++) {
4322            noteFullWifiLockAcquiredLocked(ws.get(i));
4323        }
4324    }
4325
4326    public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
4327        int N = ws.size();
4328        for (int i=0; i<N; i++) {
4329            noteFullWifiLockReleasedLocked(ws.get(i));
4330        }
4331    }
4332
4333    public void noteWifiScanStartedFromSourceLocked(WorkSource ws) {
4334        int N = ws.size();
4335        for (int i=0; i<N; i++) {
4336            noteWifiScanStartedLocked(ws.get(i));
4337        }
4338    }
4339
4340    public void noteWifiScanStoppedFromSourceLocked(WorkSource ws) {
4341        int N = ws.size();
4342        for (int i=0; i<N; i++) {
4343            noteWifiScanStoppedLocked(ws.get(i));
4344        }
4345    }
4346
4347    public void noteWifiBatchedScanStartedFromSourceLocked(WorkSource ws, int csph) {
4348        int N = ws.size();
4349        for (int i=0; i<N; i++) {
4350            noteWifiBatchedScanStartedLocked(ws.get(i), csph);
4351        }
4352    }
4353
4354    public void noteWifiBatchedScanStoppedFromSourceLocked(WorkSource ws) {
4355        int N = ws.size();
4356        for (int i=0; i<N; i++) {
4357            noteWifiBatchedScanStoppedLocked(ws.get(i));
4358        }
4359    }
4360
4361    public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
4362        int N = ws.size();
4363        for (int i=0; i<N; i++) {
4364            noteWifiMulticastEnabledLocked(ws.get(i));
4365        }
4366    }
4367
4368    public void noteWifiMulticastDisabledFromSourceLocked(WorkSource ws) {
4369        int N = ws.size();
4370        for (int i=0; i<N; i++) {
4371            noteWifiMulticastDisabledLocked(ws.get(i));
4372        }
4373    }
4374
4375    private static String[] includeInStringArray(String[] array, String str) {
4376        if (ArrayUtils.indexOf(array, str) >= 0) {
4377            return array;
4378        }
4379        String[] newArray = new String[array.length+1];
4380        System.arraycopy(array, 0, newArray, 0, array.length);
4381        newArray[array.length] = str;
4382        return newArray;
4383    }
4384
4385    private static String[] excludeFromStringArray(String[] array, String str) {
4386        int index = ArrayUtils.indexOf(array, str);
4387        if (index >= 0) {
4388            String[] newArray = new String[array.length-1];
4389            if (index > 0) {
4390                System.arraycopy(array, 0, newArray, 0, index);
4391            }
4392            if (index < array.length-1) {
4393                System.arraycopy(array, index+1, newArray, index, array.length-index-1);
4394            }
4395            return newArray;
4396        }
4397        return array;
4398    }
4399
4400    public void noteNetworkInterfaceTypeLocked(String iface, int networkType) {
4401        if (TextUtils.isEmpty(iface)) return;
4402        if (ConnectivityManager.isNetworkTypeMobile(networkType)) {
4403            mMobileIfaces = includeInStringArray(mMobileIfaces, iface);
4404            if (DEBUG) Slog.d(TAG, "Note mobile iface " + iface + ": " + mMobileIfaces);
4405        } else {
4406            mMobileIfaces = excludeFromStringArray(mMobileIfaces, iface);
4407            if (DEBUG) Slog.d(TAG, "Note non-mobile iface " + iface + ": " + mMobileIfaces);
4408        }
4409        if (ConnectivityManager.isNetworkTypeWifi(networkType)) {
4410            mWifiIfaces = includeInStringArray(mWifiIfaces, iface);
4411            if (DEBUG) Slog.d(TAG, "Note wifi iface " + iface + ": " + mWifiIfaces);
4412        } else {
4413            mWifiIfaces = excludeFromStringArray(mWifiIfaces, iface);
4414            if (DEBUG) Slog.d(TAG, "Note non-wifi iface " + iface + ": " + mWifiIfaces);
4415        }
4416    }
4417
4418    public void noteNetworkStatsEnabledLocked() {
4419        // During device boot, qtaguid isn't enabled until after the inital
4420        // loading of battery stats. Now that they're enabled, take our initial
4421        // snapshot for future delta calculation.
4422        updateMobileRadioStateLocked(mClocks.elapsedRealtime(), null);
4423        updateWifiStateLocked(null);
4424    }
4425
4426    @Override public long getScreenOnTime(long elapsedRealtimeUs, int which) {
4427        return mScreenOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4428    }
4429
4430    @Override public int getScreenOnCount(int which) {
4431        return mScreenOnTimer.getCountLocked(which);
4432    }
4433
4434    @Override public long getScreenBrightnessTime(int brightnessBin,
4435            long elapsedRealtimeUs, int which) {
4436        return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
4437                elapsedRealtimeUs, which);
4438    }
4439
4440    @Override public long getInteractiveTime(long elapsedRealtimeUs, int which) {
4441        return mInteractiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4442    }
4443
4444    @Override public long getPowerSaveModeEnabledTime(long elapsedRealtimeUs, int which) {
4445        return mPowerSaveModeEnabledTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4446    }
4447
4448    @Override public int getPowerSaveModeEnabledCount(int which) {
4449        return mPowerSaveModeEnabledTimer.getCountLocked(which);
4450    }
4451
4452    @Override public long getDeviceIdleModeTime(int mode, long elapsedRealtimeUs,
4453            int which) {
4454        switch (mode) {
4455            case DEVICE_IDLE_MODE_LIGHT:
4456                return mDeviceIdleModeLightTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4457            case DEVICE_IDLE_MODE_DEEP:
4458                return mDeviceIdleModeFullTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4459        }
4460        return 0;
4461    }
4462
4463    @Override public int getDeviceIdleModeCount(int mode, int which) {
4464        switch (mode) {
4465            case DEVICE_IDLE_MODE_LIGHT:
4466                return mDeviceIdleModeLightTimer.getCountLocked(which);
4467            case DEVICE_IDLE_MODE_DEEP:
4468                return mDeviceIdleModeFullTimer.getCountLocked(which);
4469        }
4470        return 0;
4471    }
4472
4473    @Override public long getLongestDeviceIdleModeTime(int mode) {
4474        switch (mode) {
4475            case DEVICE_IDLE_MODE_LIGHT:
4476                return mLongestLightIdleTime;
4477            case DEVICE_IDLE_MODE_DEEP:
4478                return mLongestFullIdleTime;
4479        }
4480        return 0;
4481    }
4482
4483    @Override public long getDeviceIdlingTime(int mode, long elapsedRealtimeUs, int which) {
4484        switch (mode) {
4485            case DEVICE_IDLE_MODE_LIGHT:
4486                return mDeviceLightIdlingTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4487            case DEVICE_IDLE_MODE_DEEP:
4488                return mDeviceIdlingTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4489        }
4490        return 0;
4491    }
4492
4493    @Override public int getDeviceIdlingCount(int mode, int which) {
4494        switch (mode) {
4495            case DEVICE_IDLE_MODE_LIGHT:
4496                return mDeviceLightIdlingTimer.getCountLocked(which);
4497            case DEVICE_IDLE_MODE_DEEP:
4498                return mDeviceIdlingTimer.getCountLocked(which);
4499        }
4500        return 0;
4501    }
4502
4503    @Override public int getNumConnectivityChange(int which) {
4504        int val = mNumConnectivityChange;
4505        if (which == STATS_CURRENT) {
4506            val -= mLoadedNumConnectivityChange;
4507        } else if (which == STATS_SINCE_UNPLUGGED) {
4508            val -= mUnpluggedNumConnectivityChange;
4509        }
4510        return val;
4511    }
4512
4513    @Override public long getPhoneOnTime(long elapsedRealtimeUs, int which) {
4514        return mPhoneOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4515    }
4516
4517    @Override public int getPhoneOnCount(int which) {
4518        return mPhoneOnTimer.getCountLocked(which);
4519    }
4520
4521    @Override public long getPhoneSignalStrengthTime(int strengthBin,
4522            long elapsedRealtimeUs, int which) {
4523        return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
4524                elapsedRealtimeUs, which);
4525    }
4526
4527    @Override public long getPhoneSignalScanningTime(
4528            long elapsedRealtimeUs, int which) {
4529        return mPhoneSignalScanningTimer.getTotalTimeLocked(
4530                elapsedRealtimeUs, which);
4531    }
4532
4533    @Override public int getPhoneSignalStrengthCount(int strengthBin, int which) {
4534        return mPhoneSignalStrengthsTimer[strengthBin].getCountLocked(which);
4535    }
4536
4537    @Override public long getPhoneDataConnectionTime(int dataType,
4538            long elapsedRealtimeUs, int which) {
4539        return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
4540                elapsedRealtimeUs, which);
4541    }
4542
4543    @Override public int getPhoneDataConnectionCount(int dataType, int which) {
4544        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
4545    }
4546
4547    @Override public long getMobileRadioActiveTime(long elapsedRealtimeUs, int which) {
4548        return mMobileRadioActiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4549    }
4550
4551    @Override public int getMobileRadioActiveCount(int which) {
4552        return mMobileRadioActiveTimer.getCountLocked(which);
4553    }
4554
4555    @Override public long getMobileRadioActiveAdjustedTime(int which) {
4556        return mMobileRadioActiveAdjustedTime.getCountLocked(which);
4557    }
4558
4559    @Override public long getMobileRadioActiveUnknownTime(int which) {
4560        return mMobileRadioActiveUnknownTime.getCountLocked(which);
4561    }
4562
4563    @Override public int getMobileRadioActiveUnknownCount(int which) {
4564        return (int)mMobileRadioActiveUnknownCount.getCountLocked(which);
4565    }
4566
4567    @Override public long getWifiOnTime(long elapsedRealtimeUs, int which) {
4568        return mWifiOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4569    }
4570
4571    @Override public long getGlobalWifiRunningTime(long elapsedRealtimeUs, int which) {
4572        return mGlobalWifiRunningTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4573    }
4574
4575    @Override public long getWifiStateTime(int wifiState,
4576            long elapsedRealtimeUs, int which) {
4577        return mWifiStateTimer[wifiState].getTotalTimeLocked(
4578                elapsedRealtimeUs, which);
4579    }
4580
4581    @Override public int getWifiStateCount(int wifiState, int which) {
4582        return mWifiStateTimer[wifiState].getCountLocked(which);
4583    }
4584
4585    @Override public long getWifiSupplStateTime(int state,
4586            long elapsedRealtimeUs, int which) {
4587        return mWifiSupplStateTimer[state].getTotalTimeLocked(
4588                elapsedRealtimeUs, which);
4589    }
4590
4591    @Override public int getWifiSupplStateCount(int state, int which) {
4592        return mWifiSupplStateTimer[state].getCountLocked(which);
4593    }
4594
4595    @Override public long getWifiSignalStrengthTime(int strengthBin,
4596            long elapsedRealtimeUs, int which) {
4597        return mWifiSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
4598                elapsedRealtimeUs, which);
4599    }
4600
4601    @Override public int getWifiSignalStrengthCount(int strengthBin, int which) {
4602        return mWifiSignalStrengthsTimer[strengthBin].getCountLocked(which);
4603    }
4604
4605    @Override
4606    public ControllerActivityCounter getBluetoothControllerActivity() {
4607        return mBluetoothActivity;
4608    }
4609
4610    @Override
4611    public ControllerActivityCounter getWifiControllerActivity() {
4612        return mWifiActivity;
4613    }
4614
4615    @Override
4616    public ControllerActivityCounter getModemControllerActivity() {
4617        return mModemActivity;
4618    }
4619
4620    @Override
4621    public boolean hasBluetoothActivityReporting() {
4622        return mHasBluetoothReporting;
4623    }
4624
4625    @Override
4626    public boolean hasWifiActivityReporting() {
4627        return mHasWifiReporting;
4628    }
4629
4630    @Override
4631    public boolean hasModemActivityReporting() {
4632        return mHasModemReporting;
4633    }
4634
4635    @Override
4636    public long getFlashlightOnTime(long elapsedRealtimeUs, int which) {
4637        return mFlashlightOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4638    }
4639
4640    @Override
4641    public long getFlashlightOnCount(int which) {
4642        return mFlashlightOnTimer.getCountLocked(which);
4643    }
4644
4645    @Override
4646    public long getCameraOnTime(long elapsedRealtimeUs, int which) {
4647        return mCameraOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4648    }
4649
4650    @Override
4651    public long getBluetoothScanTime(long elapsedRealtimeUs, int which) {
4652        return mBluetoothScanTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
4653    }
4654
4655    @Override
4656    public long getNetworkActivityBytes(int type, int which) {
4657        if (type >= 0 && type < mNetworkByteActivityCounters.length) {
4658            return mNetworkByteActivityCounters[type].getCountLocked(which);
4659        } else {
4660            return 0;
4661        }
4662    }
4663
4664    @Override
4665    public long getNetworkActivityPackets(int type, int which) {
4666        if (type >= 0 && type < mNetworkPacketActivityCounters.length) {
4667            return mNetworkPacketActivityCounters[type].getCountLocked(which);
4668        } else {
4669            return 0;
4670        }
4671    }
4672
4673    @Override public long getStartClockTime() {
4674        final long currentTime = System.currentTimeMillis();
4675        if (ensureStartClockTime(currentTime)) {
4676            recordCurrentTimeChangeLocked(currentTime, mClocks.elapsedRealtime(),
4677                    mClocks.uptimeMillis());
4678        }
4679        return mStartClockTime;
4680    }
4681
4682    @Override public String getStartPlatformVersion() {
4683        return mStartPlatformVersion;
4684    }
4685
4686    @Override public String getEndPlatformVersion() {
4687        return mEndPlatformVersion;
4688    }
4689
4690    @Override public int getParcelVersion() {
4691        return VERSION;
4692    }
4693
4694    @Override public boolean getIsOnBattery() {
4695        return mOnBattery;
4696    }
4697
4698    @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
4699        return mUidStats;
4700    }
4701
4702    /**
4703     * The statistics associated with a particular uid.
4704     */
4705    public static class Uid extends BatteryStats.Uid {
4706        /**
4707         * BatteryStatsImpl that we are associated with.
4708         */
4709        protected BatteryStatsImpl mBsi;
4710
4711        final int mUid;
4712
4713        boolean mWifiRunning;
4714        StopwatchTimer mWifiRunningTimer;
4715
4716        boolean mFullWifiLockOut;
4717        StopwatchTimer mFullWifiLockTimer;
4718
4719        boolean mWifiScanStarted;
4720        StopwatchTimer mWifiScanTimer;
4721
4722        static final int NO_BATCHED_SCAN_STARTED = -1;
4723        int mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
4724        StopwatchTimer[] mWifiBatchedScanTimer;
4725
4726        boolean mWifiMulticastEnabled;
4727        StopwatchTimer mWifiMulticastTimer;
4728
4729        StopwatchTimer mAudioTurnedOnTimer;
4730        StopwatchTimer mVideoTurnedOnTimer;
4731        StopwatchTimer mFlashlightTurnedOnTimer;
4732        StopwatchTimer mCameraTurnedOnTimer;
4733        StopwatchTimer mForegroundActivityTimer;
4734        StopwatchTimer mBluetoothScanTimer;
4735
4736        int mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
4737        StopwatchTimer[] mProcessStateTimer;
4738
4739        BatchTimer mVibratorOnTimer;
4740
4741        Counter[] mUserActivityCounters;
4742
4743        LongSamplingCounter[] mNetworkByteActivityCounters;
4744        LongSamplingCounter[] mNetworkPacketActivityCounters;
4745        LongSamplingCounter mMobileRadioActiveTime;
4746        LongSamplingCounter mMobileRadioActiveCount;
4747
4748        /**
4749         * The amount of time this uid has kept the WiFi controller in idle, tx, and rx mode.
4750         * Can be null if the UID has had no such activity.
4751         */
4752        private ControllerActivityCounterImpl mWifiControllerActivity;
4753
4754        /**
4755         * The amount of time this uid has kept the Bluetooth controller in idle, tx, and rx mode.
4756         * Can be null if the UID has had no such activity.
4757         */
4758        private ControllerActivityCounterImpl mBluetoothControllerActivity;
4759
4760        /**
4761         * The amount of time this uid has kept the Modem controller in idle, tx, and rx mode.
4762         * Can be null if the UID has had no such activity.
4763         */
4764        private ControllerActivityCounterImpl mModemControllerActivity;
4765
4766        /**
4767         * The CPU times we had at the last history details update.
4768         */
4769        long mLastStepUserTime;
4770        long mLastStepSystemTime;
4771        long mCurStepUserTime;
4772        long mCurStepSystemTime;
4773
4774        LongSamplingCounter mUserCpuTime;
4775        LongSamplingCounter mSystemCpuTime;
4776        LongSamplingCounter mCpuPower;
4777        LongSamplingCounter[][] mCpuClusterSpeed;
4778
4779        /**
4780         * The statistics we have collected for this uid's wake locks.
4781         */
4782        final OverflowArrayMap<Wakelock> mWakelockStats;
4783
4784        /**
4785         * The statistics we have collected for this uid's syncs.
4786         */
4787        final OverflowArrayMap<StopwatchTimer> mSyncStats;
4788
4789        /**
4790         * The statistics we have collected for this uid's jobs.
4791         */
4792        final OverflowArrayMap<StopwatchTimer> mJobStats;
4793
4794        /**
4795         * The statistics we have collected for this uid's sensor activations.
4796         */
4797        final SparseArray<Sensor> mSensorStats = new SparseArray<>();
4798
4799        /**
4800         * The statistics we have collected for this uid's processes.
4801         */
4802        final ArrayMap<String, Proc> mProcessStats = new ArrayMap<>();
4803
4804        /**
4805         * The statistics we have collected for this uid's processes.
4806         */
4807        final ArrayMap<String, Pkg> mPackageStats = new ArrayMap<>();
4808
4809        /**
4810         * The transient wake stats we have collected for this uid's pids.
4811         */
4812        final SparseArray<Pid> mPids = new SparseArray<>();
4813
4814        public Uid(BatteryStatsImpl bsi, int uid) {
4815            mBsi = bsi;
4816            mUid = uid;
4817
4818            mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
4819            mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
4820            mCpuPower = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
4821
4822            mWakelockStats = mBsi.new OverflowArrayMap<Wakelock>() {
4823                @Override public Wakelock instantiateObject() {
4824                    return new Wakelock(mBsi, Uid.this);
4825                }
4826            };
4827            mSyncStats = mBsi.new OverflowArrayMap<StopwatchTimer>() {
4828                @Override public StopwatchTimer instantiateObject() {
4829                    return new StopwatchTimer(mBsi.mClocks, Uid.this, SYNC, null,
4830                            mBsi.mOnBatteryTimeBase);
4831                }
4832            };
4833            mJobStats = mBsi.new OverflowArrayMap<StopwatchTimer>() {
4834                @Override public StopwatchTimer instantiateObject() {
4835                    return new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null,
4836                            mBsi.mOnBatteryTimeBase);
4837                }
4838            };
4839
4840            mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_RUNNING,
4841                    mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase);
4842            mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, this, FULL_WIFI_LOCK,
4843                    mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase);
4844            mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_SCAN,
4845                    mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase);
4846            mWifiBatchedScanTimer = new StopwatchTimer[NUM_WIFI_BATCHED_SCAN_BINS];
4847            mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_MULTICAST_ENABLED,
4848                    mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase);
4849            mProcessStateTimer = new StopwatchTimer[NUM_PROCESS_STATE];
4850        }
4851
4852        @Override
4853        public ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
4854            return mWakelockStats.getMap();
4855        }
4856
4857        @Override
4858        public ArrayMap<String, ? extends BatteryStats.Timer> getSyncStats() {
4859            return mSyncStats.getMap();
4860        }
4861
4862        @Override
4863        public ArrayMap<String, ? extends BatteryStats.Timer> getJobStats() {
4864            return mJobStats.getMap();
4865        }
4866
4867        @Override
4868        public SparseArray<? extends BatteryStats.Uid.Sensor> getSensorStats() {
4869            return mSensorStats;
4870        }
4871
4872        @Override
4873        public ArrayMap<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
4874            return mProcessStats;
4875        }
4876
4877        @Override
4878        public ArrayMap<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
4879            return mPackageStats;
4880        }
4881
4882        @Override
4883        public int getUid() {
4884            return mUid;
4885        }
4886
4887        @Override
4888        public void noteWifiRunningLocked(long elapsedRealtimeMs) {
4889            if (!mWifiRunning) {
4890                mWifiRunning = true;
4891                if (mWifiRunningTimer == null) {
4892                    mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_RUNNING,
4893                            mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase);
4894                }
4895                mWifiRunningTimer.startRunningLocked(elapsedRealtimeMs);
4896            }
4897        }
4898
4899        @Override
4900        public void noteWifiStoppedLocked(long elapsedRealtimeMs) {
4901            if (mWifiRunning) {
4902                mWifiRunning = false;
4903                mWifiRunningTimer.stopRunningLocked(elapsedRealtimeMs);
4904            }
4905        }
4906
4907        @Override
4908        public void noteFullWifiLockAcquiredLocked(long elapsedRealtimeMs) {
4909            if (!mFullWifiLockOut) {
4910                mFullWifiLockOut = true;
4911                if (mFullWifiLockTimer == null) {
4912                    mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, FULL_WIFI_LOCK,
4913                            mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase);
4914                }
4915                mFullWifiLockTimer.startRunningLocked(elapsedRealtimeMs);
4916            }
4917        }
4918
4919        @Override
4920        public void noteFullWifiLockReleasedLocked(long elapsedRealtimeMs) {
4921            if (mFullWifiLockOut) {
4922                mFullWifiLockOut = false;
4923                mFullWifiLockTimer.stopRunningLocked(elapsedRealtimeMs);
4924            }
4925        }
4926
4927        @Override
4928        public void noteWifiScanStartedLocked(long elapsedRealtimeMs) {
4929            if (!mWifiScanStarted) {
4930                mWifiScanStarted = true;
4931                if (mWifiScanTimer == null) {
4932                    mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
4933                            mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase);
4934                }
4935                mWifiScanTimer.startRunningLocked(elapsedRealtimeMs);
4936            }
4937        }
4938
4939        @Override
4940        public void noteWifiScanStoppedLocked(long elapsedRealtimeMs) {
4941            if (mWifiScanStarted) {
4942                mWifiScanStarted = false;
4943                mWifiScanTimer.stopRunningLocked(elapsedRealtimeMs);
4944            }
4945        }
4946
4947        @Override
4948        public void noteWifiBatchedScanStartedLocked(int csph, long elapsedRealtimeMs) {
4949            int bin = 0;
4950            while (csph > 8 && bin < NUM_WIFI_BATCHED_SCAN_BINS-1) {
4951                csph = csph >> 3;
4952                bin++;
4953            }
4954
4955            if (mWifiBatchedScanBinStarted == bin) return;
4956
4957            if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
4958                mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
4959                        stopRunningLocked(elapsedRealtimeMs);
4960            }
4961            mWifiBatchedScanBinStarted = bin;
4962            if (mWifiBatchedScanTimer[bin] == null) {
4963                makeWifiBatchedScanBin(bin, null);
4964            }
4965            mWifiBatchedScanTimer[bin].startRunningLocked(elapsedRealtimeMs);
4966        }
4967
4968        @Override
4969        public void noteWifiBatchedScanStoppedLocked(long elapsedRealtimeMs) {
4970            if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
4971                mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
4972                        stopRunningLocked(elapsedRealtimeMs);
4973                mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
4974            }
4975        }
4976
4977        @Override
4978        public void noteWifiMulticastEnabledLocked(long elapsedRealtimeMs) {
4979            if (!mWifiMulticastEnabled) {
4980                mWifiMulticastEnabled = true;
4981                if (mWifiMulticastTimer == null) {
4982                    mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
4983                            WIFI_MULTICAST_ENABLED, mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase);
4984                }
4985                mWifiMulticastTimer.startRunningLocked(elapsedRealtimeMs);
4986            }
4987        }
4988
4989        @Override
4990        public void noteWifiMulticastDisabledLocked(long elapsedRealtimeMs) {
4991            if (mWifiMulticastEnabled) {
4992                mWifiMulticastEnabled = false;
4993                mWifiMulticastTimer.stopRunningLocked(elapsedRealtimeMs);
4994            }
4995        }
4996
4997        @Override
4998        public ControllerActivityCounter getWifiControllerActivity() {
4999            return mWifiControllerActivity;
5000        }
5001
5002        @Override
5003        public ControllerActivityCounter getBluetoothControllerActivity() {
5004            return mBluetoothControllerActivity;
5005        }
5006
5007        @Override
5008        public ControllerActivityCounter getModemControllerActivity() {
5009            return mModemControllerActivity;
5010        }
5011
5012        public ControllerActivityCounterImpl getOrCreateWifiControllerActivityLocked() {
5013            if (mWifiControllerActivity == null) {
5014                mWifiControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
5015                        NUM_BT_TX_LEVELS);
5016            }
5017            return mWifiControllerActivity;
5018        }
5019
5020        public ControllerActivityCounterImpl getOrCreateBluetoothControllerActivityLocked() {
5021            if (mBluetoothControllerActivity == null) {
5022                mBluetoothControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
5023                        NUM_BT_TX_LEVELS);
5024            }
5025            return mBluetoothControllerActivity;
5026        }
5027
5028        public ControllerActivityCounterImpl getOrCreateModemControllerActivityLocked() {
5029            if (mModemControllerActivity == null) {
5030                mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
5031                        ModemActivityInfo.TX_POWER_LEVELS);
5032            }
5033            return mModemControllerActivity;
5034        }
5035
5036        public StopwatchTimer createAudioTurnedOnTimerLocked() {
5037            if (mAudioTurnedOnTimer == null) {
5038                mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, AUDIO_TURNED_ON,
5039                        mBsi.mAudioTurnedOnTimers, mBsi.mOnBatteryTimeBase);
5040            }
5041            return mAudioTurnedOnTimer;
5042        }
5043
5044        public void noteAudioTurnedOnLocked(long elapsedRealtimeMs) {
5045            createAudioTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
5046        }
5047
5048        public void noteAudioTurnedOffLocked(long elapsedRealtimeMs) {
5049            if (mAudioTurnedOnTimer != null) {
5050                mAudioTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
5051            }
5052        }
5053
5054        public void noteResetAudioLocked(long elapsedRealtimeMs) {
5055            if (mAudioTurnedOnTimer != null) {
5056                mAudioTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
5057            }
5058        }
5059
5060        public StopwatchTimer createVideoTurnedOnTimerLocked() {
5061            if (mVideoTurnedOnTimer == null) {
5062                mVideoTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, VIDEO_TURNED_ON,
5063                        mBsi.mVideoTurnedOnTimers, mBsi.mOnBatteryTimeBase);
5064            }
5065            return mVideoTurnedOnTimer;
5066        }
5067
5068        public void noteVideoTurnedOnLocked(long elapsedRealtimeMs) {
5069            createVideoTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
5070        }
5071
5072        public void noteVideoTurnedOffLocked(long elapsedRealtimeMs) {
5073            if (mVideoTurnedOnTimer != null) {
5074                mVideoTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
5075            }
5076        }
5077
5078        public void noteResetVideoLocked(long elapsedRealtimeMs) {
5079            if (mVideoTurnedOnTimer != null) {
5080                mVideoTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
5081            }
5082        }
5083
5084        public StopwatchTimer createFlashlightTurnedOnTimerLocked() {
5085            if (mFlashlightTurnedOnTimer == null) {
5086                mFlashlightTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
5087                        FLASHLIGHT_TURNED_ON, mBsi.mFlashlightTurnedOnTimers, mBsi.mOnBatteryTimeBase);
5088            }
5089            return mFlashlightTurnedOnTimer;
5090        }
5091
5092        public void noteFlashlightTurnedOnLocked(long elapsedRealtimeMs) {
5093            createFlashlightTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
5094        }
5095
5096        public void noteFlashlightTurnedOffLocked(long elapsedRealtimeMs) {
5097            if (mFlashlightTurnedOnTimer != null) {
5098                mFlashlightTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
5099            }
5100        }
5101
5102        public void noteResetFlashlightLocked(long elapsedRealtimeMs) {
5103            if (mFlashlightTurnedOnTimer != null) {
5104                mFlashlightTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
5105            }
5106        }
5107
5108        public StopwatchTimer createCameraTurnedOnTimerLocked() {
5109            if (mCameraTurnedOnTimer == null) {
5110                mCameraTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, CAMERA_TURNED_ON,
5111                        mBsi.mCameraTurnedOnTimers, mBsi.mOnBatteryTimeBase);
5112            }
5113            return mCameraTurnedOnTimer;
5114        }
5115
5116        public void noteCameraTurnedOnLocked(long elapsedRealtimeMs) {
5117            createCameraTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
5118        }
5119
5120        public void noteCameraTurnedOffLocked(long elapsedRealtimeMs) {
5121            if (mCameraTurnedOnTimer != null) {
5122                mCameraTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
5123            }
5124        }
5125
5126        public void noteResetCameraLocked(long elapsedRealtimeMs) {
5127            if (mCameraTurnedOnTimer != null) {
5128                mCameraTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
5129            }
5130        }
5131
5132        public StopwatchTimer createForegroundActivityTimerLocked() {
5133            if (mForegroundActivityTimer == null) {
5134                mForegroundActivityTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
5135                        FOREGROUND_ACTIVITY, null, mBsi.mOnBatteryTimeBase);
5136            }
5137            return mForegroundActivityTimer;
5138        }
5139
5140        public StopwatchTimer createBluetoothScanTimerLocked() {
5141            if (mBluetoothScanTimer == null) {
5142                mBluetoothScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
5143                        mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase);
5144            }
5145            return mBluetoothScanTimer;
5146        }
5147
5148        public void noteBluetoothScanStartedLocked(long elapsedRealtimeMs) {
5149            createBluetoothScanTimerLocked().startRunningLocked(elapsedRealtimeMs);
5150        }
5151
5152        public void noteBluetoothScanStoppedLocked(long elapsedRealtimeMs) {
5153            if (mBluetoothScanTimer != null) {
5154                mBluetoothScanTimer.stopRunningLocked(elapsedRealtimeMs);
5155            }
5156        }
5157
5158        public void noteResetBluetoothScanLocked(long elapsedRealtimeMs) {
5159            if (mBluetoothScanTimer != null) {
5160                mBluetoothScanTimer.stopAllRunningLocked(elapsedRealtimeMs);
5161            }
5162        }
5163
5164        @Override
5165        public void noteActivityResumedLocked(long elapsedRealtimeMs) {
5166            // We always start, since we want multiple foreground PIDs to nest
5167            createForegroundActivityTimerLocked().startRunningLocked(elapsedRealtimeMs);
5168        }
5169
5170        @Override
5171        public void noteActivityPausedLocked(long elapsedRealtimeMs) {
5172            if (mForegroundActivityTimer != null) {
5173                mForegroundActivityTimer.stopRunningLocked(elapsedRealtimeMs);
5174            }
5175        }
5176
5177        public BatchTimer createVibratorOnTimerLocked() {
5178            if (mVibratorOnTimer == null) {
5179                mVibratorOnTimer = new BatchTimer(mBsi.mClocks, Uid.this, VIBRATOR_ON,
5180                        mBsi.mOnBatteryTimeBase);
5181            }
5182            return mVibratorOnTimer;
5183        }
5184
5185        public void noteVibratorOnLocked(long durationMillis) {
5186            createVibratorOnTimerLocked().addDuration(mBsi, durationMillis);
5187        }
5188
5189        public void noteVibratorOffLocked() {
5190            if (mVibratorOnTimer != null) {
5191                mVibratorOnTimer.abortLastDuration(mBsi);
5192            }
5193        }
5194
5195        @Override
5196        public long getWifiRunningTime(long elapsedRealtimeUs, int which) {
5197            if (mWifiRunningTimer == null) {
5198                return 0;
5199            }
5200            return mWifiRunningTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
5201        }
5202
5203        @Override
5204        public long getFullWifiLockTime(long elapsedRealtimeUs, int which) {
5205            if (mFullWifiLockTimer == null) {
5206                return 0;
5207            }
5208            return mFullWifiLockTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
5209        }
5210
5211        @Override
5212        public long getWifiScanTime(long elapsedRealtimeUs, int which) {
5213            if (mWifiScanTimer == null) {
5214                return 0;
5215            }
5216            return mWifiScanTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
5217        }
5218
5219        @Override
5220        public int getWifiScanCount(int which) {
5221            if (mWifiScanTimer == null) {
5222                return 0;
5223            }
5224            return mWifiScanTimer.getCountLocked(which);
5225        }
5226
5227        @Override
5228        public long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which) {
5229            if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0;
5230            if (mWifiBatchedScanTimer[csphBin] == null) {
5231                return 0;
5232            }
5233            return mWifiBatchedScanTimer[csphBin].getTotalTimeLocked(elapsedRealtimeUs, which);
5234        }
5235
5236        @Override
5237        public int getWifiBatchedScanCount(int csphBin, int which) {
5238            if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0;
5239            if (mWifiBatchedScanTimer[csphBin] == null) {
5240                return 0;
5241            }
5242            return mWifiBatchedScanTimer[csphBin].getCountLocked(which);
5243        }
5244
5245        @Override
5246        public long getWifiMulticastTime(long elapsedRealtimeUs, int which) {
5247            if (mWifiMulticastTimer == null) {
5248                return 0;
5249            }
5250            return mWifiMulticastTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
5251        }
5252
5253        @Override
5254        public Timer getAudioTurnedOnTimer() {
5255            return mAudioTurnedOnTimer;
5256        }
5257
5258        @Override
5259        public Timer getVideoTurnedOnTimer() {
5260            return mVideoTurnedOnTimer;
5261        }
5262
5263        @Override
5264        public Timer getFlashlightTurnedOnTimer() {
5265            return mFlashlightTurnedOnTimer;
5266        }
5267
5268        @Override
5269        public Timer getCameraTurnedOnTimer() {
5270            return mCameraTurnedOnTimer;
5271        }
5272
5273        @Override
5274        public Timer getForegroundActivityTimer() {
5275            return mForegroundActivityTimer;
5276        }
5277
5278        @Override
5279        public Timer getBluetoothScanTimer() {
5280            return mBluetoothScanTimer;
5281        }
5282
5283        void makeProcessState(int i, Parcel in) {
5284            if (i < 0 || i >= NUM_PROCESS_STATE) return;
5285
5286            if (in == null) {
5287                mProcessStateTimer[i] = new StopwatchTimer(mBsi.mClocks, this, PROCESS_STATE, null,
5288                        mBsi.mOnBatteryTimeBase);
5289            } else {
5290                mProcessStateTimer[i] = new StopwatchTimer(mBsi.mClocks, this, PROCESS_STATE, null,
5291                        mBsi.mOnBatteryTimeBase, in);
5292            }
5293        }
5294
5295        @Override
5296        public long getProcessStateTime(int state, long elapsedRealtimeUs, int which) {
5297            if (state < 0 || state >= NUM_PROCESS_STATE) return 0;
5298            if (mProcessStateTimer[state] == null) {
5299                return 0;
5300            }
5301            return mProcessStateTimer[state].getTotalTimeLocked(elapsedRealtimeUs, which);
5302        }
5303
5304        @Override
5305        public Timer getProcessStateTimer(int state) {
5306            if (state < 0 || state >= NUM_PROCESS_STATE) return null;
5307            return mProcessStateTimer[state];
5308        }
5309
5310        @Override
5311        public Timer getVibratorOnTimer() {
5312            return mVibratorOnTimer;
5313        }
5314
5315        @Override
5316        public void noteUserActivityLocked(int type) {
5317            if (mUserActivityCounters == null) {
5318                initUserActivityLocked();
5319            }
5320            if (type >= 0 && type < NUM_USER_ACTIVITY_TYPES) {
5321                mUserActivityCounters[type].stepAtomic();
5322            } else {
5323                Slog.w(TAG, "Unknown user activity type " + type + " was specified.",
5324                        new Throwable());
5325            }
5326        }
5327
5328        @Override
5329        public boolean hasUserActivity() {
5330            return mUserActivityCounters != null;
5331        }
5332
5333        @Override
5334        public int getUserActivityCount(int type, int which) {
5335            if (mUserActivityCounters == null) {
5336                return 0;
5337            }
5338            return mUserActivityCounters[type].getCountLocked(which);
5339        }
5340
5341        void makeWifiBatchedScanBin(int i, Parcel in) {
5342            if (i < 0 || i >= NUM_WIFI_BATCHED_SCAN_BINS) return;
5343
5344            ArrayList<StopwatchTimer> collected = mBsi.mWifiBatchedScanTimers.get(i);
5345            if (collected == null) {
5346                collected = new ArrayList<StopwatchTimer>();
5347                mBsi.mWifiBatchedScanTimers.put(i, collected);
5348            }
5349            if (in == null) {
5350                mWifiBatchedScanTimer[i] = new StopwatchTimer(mBsi.mClocks, this, WIFI_BATCHED_SCAN,
5351                        collected, mBsi.mOnBatteryTimeBase);
5352            } else {
5353                mWifiBatchedScanTimer[i] = new StopwatchTimer(mBsi.mClocks, this, WIFI_BATCHED_SCAN,
5354                        collected, mBsi.mOnBatteryTimeBase, in);
5355            }
5356        }
5357
5358
5359        void initUserActivityLocked() {
5360            mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
5361            for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
5362                mUserActivityCounters[i] = new Counter(mBsi.mOnBatteryTimeBase);
5363            }
5364        }
5365
5366        void noteNetworkActivityLocked(int type, long deltaBytes, long deltaPackets) {
5367            if (mNetworkByteActivityCounters == null) {
5368                initNetworkActivityLocked();
5369            }
5370            if (type >= 0 && type < NUM_NETWORK_ACTIVITY_TYPES) {
5371                mNetworkByteActivityCounters[type].addCountLocked(deltaBytes);
5372                mNetworkPacketActivityCounters[type].addCountLocked(deltaPackets);
5373            } else {
5374                Slog.w(TAG, "Unknown network activity type " + type + " was specified.",
5375                        new Throwable());
5376            }
5377        }
5378
5379        void noteMobileRadioActiveTimeLocked(long batteryUptime) {
5380            if (mNetworkByteActivityCounters == null) {
5381                initNetworkActivityLocked();
5382            }
5383            mMobileRadioActiveTime.addCountLocked(batteryUptime);
5384            mMobileRadioActiveCount.addCountLocked(1);
5385        }
5386
5387        @Override
5388        public boolean hasNetworkActivity() {
5389            return mNetworkByteActivityCounters != null;
5390        }
5391
5392        @Override
5393        public long getNetworkActivityBytes(int type, int which) {
5394            if (mNetworkByteActivityCounters != null && type >= 0
5395                    && type < mNetworkByteActivityCounters.length) {
5396                return mNetworkByteActivityCounters[type].getCountLocked(which);
5397            } else {
5398                return 0;
5399            }
5400        }
5401
5402        @Override
5403        public long getNetworkActivityPackets(int type, int which) {
5404            if (mNetworkPacketActivityCounters != null && type >= 0
5405                    && type < mNetworkPacketActivityCounters.length) {
5406                return mNetworkPacketActivityCounters[type].getCountLocked(which);
5407            } else {
5408                return 0;
5409            }
5410        }
5411
5412        @Override
5413        public long getMobileRadioActiveTime(int which) {
5414            return mMobileRadioActiveTime != null
5415                    ? mMobileRadioActiveTime.getCountLocked(which) : 0;
5416        }
5417
5418        @Override
5419        public int getMobileRadioActiveCount(int which) {
5420            return mMobileRadioActiveCount != null
5421                    ? (int)mMobileRadioActiveCount.getCountLocked(which) : 0;
5422        }
5423
5424        @Override
5425        public long getUserCpuTimeUs(int which) {
5426            return mUserCpuTime.getCountLocked(which);
5427        }
5428
5429        @Override
5430        public long getSystemCpuTimeUs(int which) {
5431            return mSystemCpuTime.getCountLocked(which);
5432        }
5433
5434        @Override
5435        public long getCpuPowerMaUs(int which) {
5436            return mCpuPower.getCountLocked(which);
5437        }
5438
5439        @Override
5440        public long getTimeAtCpuSpeed(int cluster, int step, int which) {
5441            if (mCpuClusterSpeed != null) {
5442                if (cluster >= 0 && cluster < mCpuClusterSpeed.length) {
5443                    final LongSamplingCounter[] cpuSpeeds = mCpuClusterSpeed[cluster];
5444                    if (cpuSpeeds != null) {
5445                        if (step >= 0 && step < cpuSpeeds.length) {
5446                            final LongSamplingCounter c = cpuSpeeds[step];
5447                            if (c != null) {
5448                                return c.getCountLocked(which);
5449                            }
5450                        }
5451                    }
5452                }
5453            }
5454            return 0;
5455        }
5456
5457        void initNetworkActivityLocked() {
5458            mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
5459            mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
5460            for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
5461                mNetworkByteActivityCounters[i] = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
5462                mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
5463            }
5464            mMobileRadioActiveTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
5465            mMobileRadioActiveCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
5466        }
5467
5468        /**
5469         * Clear all stats for this uid.  Returns true if the uid is completely
5470         * inactive so can be dropped.
5471         */
5472        boolean reset() {
5473            boolean active = false;
5474
5475            if (mWifiRunningTimer != null) {
5476                active |= !mWifiRunningTimer.reset(false);
5477                active |= mWifiRunning;
5478            }
5479            if (mFullWifiLockTimer != null) {
5480                active |= !mFullWifiLockTimer.reset(false);
5481                active |= mFullWifiLockOut;
5482            }
5483            if (mWifiScanTimer != null) {
5484                active |= !mWifiScanTimer.reset(false);
5485                active |= mWifiScanStarted;
5486            }
5487            if (mWifiBatchedScanTimer != null) {
5488                for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
5489                    if (mWifiBatchedScanTimer[i] != null) {
5490                        active |= !mWifiBatchedScanTimer[i].reset(false);
5491                    }
5492                }
5493                active |= (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED);
5494            }
5495            if (mWifiMulticastTimer != null) {
5496                active |= !mWifiMulticastTimer.reset(false);
5497                active |= mWifiMulticastEnabled;
5498            }
5499            if (mAudioTurnedOnTimer != null) {
5500                active |= !mAudioTurnedOnTimer.reset(false);
5501            }
5502            if (mVideoTurnedOnTimer != null) {
5503                active |= !mVideoTurnedOnTimer.reset(false);
5504            }
5505            if (mFlashlightTurnedOnTimer != null) {
5506                active |= !mFlashlightTurnedOnTimer.reset(false);
5507            }
5508            if (mCameraTurnedOnTimer != null) {
5509                active |= !mCameraTurnedOnTimer.reset(false);
5510            }
5511            if (mForegroundActivityTimer != null) {
5512                active |= !mForegroundActivityTimer.reset(false);
5513            }
5514            if (mBluetoothScanTimer != null) {
5515                active |= !mBluetoothScanTimer.reset(false);
5516            }
5517            if (mProcessStateTimer != null) {
5518                for (int i = 0; i < NUM_PROCESS_STATE; i++) {
5519                    if (mProcessStateTimer[i] != null) {
5520                        active |= !mProcessStateTimer[i].reset(false);
5521                    }
5522                }
5523                active |= (mProcessState != ActivityManager.PROCESS_STATE_NONEXISTENT);
5524            }
5525            if (mVibratorOnTimer != null) {
5526                if (mVibratorOnTimer.reset(false)) {
5527                    mVibratorOnTimer.detach();
5528                    mVibratorOnTimer = null;
5529                } else {
5530                    active = true;
5531                }
5532            }
5533
5534            if (mUserActivityCounters != null) {
5535                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
5536                    mUserActivityCounters[i].reset(false);
5537                }
5538            }
5539
5540            if (mNetworkByteActivityCounters != null) {
5541                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
5542                    mNetworkByteActivityCounters[i].reset(false);
5543                    mNetworkPacketActivityCounters[i].reset(false);
5544                }
5545                mMobileRadioActiveTime.reset(false);
5546                mMobileRadioActiveCount.reset(false);
5547            }
5548
5549            if (mWifiControllerActivity != null) {
5550                mWifiControllerActivity.reset(false);
5551            }
5552
5553            if (mBsi.mBluetoothActivity != null) {
5554                mBsi.mBluetoothActivity.reset(false);
5555            }
5556
5557            if (mBsi.mModemActivity != null) {
5558                mBsi.mModemActivity.reset(false);
5559            }
5560
5561            mUserCpuTime.reset(false);
5562            mSystemCpuTime.reset(false);
5563            mCpuPower.reset(false);
5564
5565            if (mCpuClusterSpeed != null) {
5566                for (LongSamplingCounter[] speeds : mCpuClusterSpeed) {
5567                    if (speeds != null) {
5568                        for (LongSamplingCounter speed : speeds) {
5569                            if (speed != null) {
5570                                speed.reset(false);
5571                            }
5572                        }
5573                    }
5574                }
5575            }
5576
5577            final ArrayMap<String, Wakelock> wakeStats = mWakelockStats.getMap();
5578            for (int iw=wakeStats.size()-1; iw>=0; iw--) {
5579                Wakelock wl = wakeStats.valueAt(iw);
5580                if (wl.reset()) {
5581                    wakeStats.removeAt(iw);
5582                } else {
5583                    active = true;
5584                }
5585            }
5586            mWakelockStats.cleanup();
5587            final ArrayMap<String, StopwatchTimer> syncStats = mSyncStats.getMap();
5588            for (int is=syncStats.size()-1; is>=0; is--) {
5589                StopwatchTimer timer = syncStats.valueAt(is);
5590                if (timer.reset(false)) {
5591                    syncStats.removeAt(is);
5592                    timer.detach();
5593                } else {
5594                    active = true;
5595                }
5596            }
5597            mSyncStats.cleanup();
5598            final ArrayMap<String, StopwatchTimer> jobStats = mJobStats.getMap();
5599            for (int ij=jobStats.size()-1; ij>=0; ij--) {
5600                StopwatchTimer timer = jobStats.valueAt(ij);
5601                if (timer.reset(false)) {
5602                    jobStats.removeAt(ij);
5603                    timer.detach();
5604                } else {
5605                    active = true;
5606                }
5607            }
5608            mJobStats.cleanup();
5609            for (int ise=mSensorStats.size()-1; ise>=0; ise--) {
5610                Sensor s = mSensorStats.valueAt(ise);
5611                if (s.reset()) {
5612                    mSensorStats.removeAt(ise);
5613                } else {
5614                    active = true;
5615                }
5616            }
5617            for (int ip=mProcessStats.size()-1; ip>=0; ip--) {
5618                Proc proc = mProcessStats.valueAt(ip);
5619                proc.detach();
5620            }
5621            mProcessStats.clear();
5622            if (mPids.size() > 0) {
5623                for (int i=mPids.size()-1; i>=0; i--) {
5624                    Pid pid = mPids.valueAt(i);
5625                    if (pid.mWakeNesting > 0) {
5626                        active = true;
5627                    } else {
5628                        mPids.removeAt(i);
5629                    }
5630                }
5631            }
5632            if (mPackageStats.size() > 0) {
5633                Iterator<Map.Entry<String, Pkg>> it = mPackageStats.entrySet().iterator();
5634                while (it.hasNext()) {
5635                    Map.Entry<String, Pkg> pkgEntry = it.next();
5636                    Pkg p = pkgEntry.getValue();
5637                    p.detach();
5638                    if (p.mServiceStats.size() > 0) {
5639                        Iterator<Map.Entry<String, Pkg.Serv>> it2
5640                                = p.mServiceStats.entrySet().iterator();
5641                        while (it2.hasNext()) {
5642                            Map.Entry<String, Pkg.Serv> servEntry = it2.next();
5643                            servEntry.getValue().detach();
5644                        }
5645                    }
5646                }
5647                mPackageStats.clear();
5648            }
5649
5650            mLastStepUserTime = mLastStepSystemTime = 0;
5651            mCurStepUserTime = mCurStepSystemTime = 0;
5652
5653            if (!active) {
5654                if (mWifiRunningTimer != null) {
5655                    mWifiRunningTimer.detach();
5656                }
5657                if (mFullWifiLockTimer != null) {
5658                    mFullWifiLockTimer.detach();
5659                }
5660                if (mWifiScanTimer != null) {
5661                    mWifiScanTimer.detach();
5662                }
5663                for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
5664                    if (mWifiBatchedScanTimer[i] != null) {
5665                        mWifiBatchedScanTimer[i].detach();
5666                    }
5667                }
5668                if (mWifiMulticastTimer != null) {
5669                    mWifiMulticastTimer.detach();
5670                }
5671                if (mAudioTurnedOnTimer != null) {
5672                    mAudioTurnedOnTimer.detach();
5673                    mAudioTurnedOnTimer = null;
5674                }
5675                if (mVideoTurnedOnTimer != null) {
5676                    mVideoTurnedOnTimer.detach();
5677                    mVideoTurnedOnTimer = null;
5678                }
5679                if (mFlashlightTurnedOnTimer != null) {
5680                    mFlashlightTurnedOnTimer.detach();
5681                    mFlashlightTurnedOnTimer = null;
5682                }
5683                if (mCameraTurnedOnTimer != null) {
5684                    mCameraTurnedOnTimer.detach();
5685                    mCameraTurnedOnTimer = null;
5686                }
5687                if (mForegroundActivityTimer != null) {
5688                    mForegroundActivityTimer.detach();
5689                    mForegroundActivityTimer = null;
5690                }
5691                if (mBluetoothScanTimer != null) {
5692                    mBluetoothScanTimer.detach();
5693                    mBluetoothScanTimer = null;
5694                }
5695                if (mUserActivityCounters != null) {
5696                    for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
5697                        mUserActivityCounters[i].detach();
5698                    }
5699                }
5700                if (mNetworkByteActivityCounters != null) {
5701                    for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
5702                        mNetworkByteActivityCounters[i].detach();
5703                        mNetworkPacketActivityCounters[i].detach();
5704                    }
5705                }
5706
5707                if (mWifiControllerActivity != null) {
5708                    mWifiControllerActivity.detach();
5709                }
5710
5711                if (mBluetoothControllerActivity != null) {
5712                    mBluetoothControllerActivity.detach();
5713                }
5714
5715                if (mModemControllerActivity != null) {
5716                    mModemControllerActivity.detach();
5717                }
5718
5719                mPids.clear();
5720
5721                mUserCpuTime.detach();
5722                mSystemCpuTime.detach();
5723                mCpuPower.detach();
5724
5725                if (mCpuClusterSpeed != null) {
5726                    for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeed) {
5727                        if (cpuSpeeds != null) {
5728                            for (LongSamplingCounter c : cpuSpeeds) {
5729                                if (c != null) {
5730                                    c.detach();
5731                                }
5732                            }
5733                        }
5734                    }
5735                }
5736            }
5737
5738            return !active;
5739        }
5740
5741        void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
5742            final ArrayMap<String, Wakelock> wakeStats = mWakelockStats.getMap();
5743            int NW = wakeStats.size();
5744            out.writeInt(NW);
5745            for (int iw=0; iw<NW; iw++) {
5746                out.writeString(wakeStats.keyAt(iw));
5747                Uid.Wakelock wakelock = wakeStats.valueAt(iw);
5748                wakelock.writeToParcelLocked(out, elapsedRealtimeUs);
5749            }
5750
5751            final ArrayMap<String, StopwatchTimer> syncStats = mSyncStats.getMap();
5752            int NS = syncStats.size();
5753            out.writeInt(NS);
5754            for (int is=0; is<NS; is++) {
5755                out.writeString(syncStats.keyAt(is));
5756                StopwatchTimer timer = syncStats.valueAt(is);
5757                Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs);
5758            }
5759
5760            final ArrayMap<String, StopwatchTimer> jobStats = mJobStats.getMap();
5761            int NJ = jobStats.size();
5762            out.writeInt(NJ);
5763            for (int ij=0; ij<NJ; ij++) {
5764                out.writeString(jobStats.keyAt(ij));
5765                StopwatchTimer timer = jobStats.valueAt(ij);
5766                Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs);
5767            }
5768
5769            int NSE = mSensorStats.size();
5770            out.writeInt(NSE);
5771            for (int ise=0; ise<NSE; ise++) {
5772                out.writeInt(mSensorStats.keyAt(ise));
5773                Uid.Sensor sensor = mSensorStats.valueAt(ise);
5774                sensor.writeToParcelLocked(out, elapsedRealtimeUs);
5775            }
5776
5777            int NP = mProcessStats.size();
5778            out.writeInt(NP);
5779            for (int ip=0; ip<NP; ip++) {
5780                out.writeString(mProcessStats.keyAt(ip));
5781                Uid.Proc proc = mProcessStats.valueAt(ip);
5782                proc.writeToParcelLocked(out);
5783            }
5784
5785            out.writeInt(mPackageStats.size());
5786            for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
5787                out.writeString(pkgEntry.getKey());
5788                Uid.Pkg pkg = pkgEntry.getValue();
5789                pkg.writeToParcelLocked(out);
5790            }
5791
5792            if (mWifiRunningTimer != null) {
5793                out.writeInt(1);
5794                mWifiRunningTimer.writeToParcel(out, elapsedRealtimeUs);
5795            } else {
5796                out.writeInt(0);
5797            }
5798            if (mFullWifiLockTimer != null) {
5799                out.writeInt(1);
5800                mFullWifiLockTimer.writeToParcel(out, elapsedRealtimeUs);
5801            } else {
5802                out.writeInt(0);
5803            }
5804            if (mWifiScanTimer != null) {
5805                out.writeInt(1);
5806                mWifiScanTimer.writeToParcel(out, elapsedRealtimeUs);
5807            } else {
5808                out.writeInt(0);
5809            }
5810            for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
5811                if (mWifiBatchedScanTimer[i] != null) {
5812                    out.writeInt(1);
5813                    mWifiBatchedScanTimer[i].writeToParcel(out, elapsedRealtimeUs);
5814                } else {
5815                    out.writeInt(0);
5816                }
5817            }
5818            if (mWifiMulticastTimer != null) {
5819                out.writeInt(1);
5820                mWifiMulticastTimer.writeToParcel(out, elapsedRealtimeUs);
5821            } else {
5822                out.writeInt(0);
5823            }
5824
5825            if (mAudioTurnedOnTimer != null) {
5826                out.writeInt(1);
5827                mAudioTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs);
5828            } else {
5829                out.writeInt(0);
5830            }
5831            if (mVideoTurnedOnTimer != null) {
5832                out.writeInt(1);
5833                mVideoTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs);
5834            } else {
5835                out.writeInt(0);
5836            }
5837            if (mFlashlightTurnedOnTimer != null) {
5838                out.writeInt(1);
5839                mFlashlightTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs);
5840            } else {
5841                out.writeInt(0);
5842            }
5843            if (mCameraTurnedOnTimer != null) {
5844                out.writeInt(1);
5845                mCameraTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs);
5846            } else {
5847                out.writeInt(0);
5848            }
5849            if (mForegroundActivityTimer != null) {
5850                out.writeInt(1);
5851                mForegroundActivityTimer.writeToParcel(out, elapsedRealtimeUs);
5852            } else {
5853                out.writeInt(0);
5854            }
5855            if (mBluetoothScanTimer != null) {
5856                out.writeInt(1);
5857                mBluetoothScanTimer.writeToParcel(out, elapsedRealtimeUs);
5858            } else {
5859                out.writeInt(0);
5860            }
5861            for (int i = 0; i < NUM_PROCESS_STATE; i++) {
5862                if (mProcessStateTimer[i] != null) {
5863                    out.writeInt(1);
5864                    mProcessStateTimer[i].writeToParcel(out, elapsedRealtimeUs);
5865                } else {
5866                    out.writeInt(0);
5867                }
5868            }
5869            if (mVibratorOnTimer != null) {
5870                out.writeInt(1);
5871                mVibratorOnTimer.writeToParcel(out, elapsedRealtimeUs);
5872            } else {
5873                out.writeInt(0);
5874            }
5875            if (mUserActivityCounters != null) {
5876                out.writeInt(1);
5877                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
5878                    mUserActivityCounters[i].writeToParcel(out);
5879                }
5880            } else {
5881                out.writeInt(0);
5882            }
5883            if (mNetworkByteActivityCounters != null) {
5884                out.writeInt(1);
5885                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
5886                    mNetworkByteActivityCounters[i].writeToParcel(out);
5887                    mNetworkPacketActivityCounters[i].writeToParcel(out);
5888                }
5889                mMobileRadioActiveTime.writeToParcel(out);
5890                mMobileRadioActiveCount.writeToParcel(out);
5891            } else {
5892                out.writeInt(0);
5893            }
5894
5895            if (mWifiControllerActivity != null) {
5896                out.writeInt(1);
5897                mWifiControllerActivity.writeToParcel(out, 0);
5898            } else {
5899                out.writeInt(0);
5900            }
5901
5902            if (mBluetoothControllerActivity != null) {
5903                out.writeInt(1);
5904                mBluetoothControllerActivity.writeToParcel(out, 0);
5905            } else {
5906                out.writeInt(0);
5907            }
5908
5909            if (mModemControllerActivity != null) {
5910                out.writeInt(1);
5911                mModemControllerActivity.writeToParcel(out, 0);
5912            } else {
5913                out.writeInt(0);
5914            }
5915
5916            mUserCpuTime.writeToParcel(out);
5917            mSystemCpuTime.writeToParcel(out);
5918            mCpuPower.writeToParcel(out);
5919
5920            if (mCpuClusterSpeed != null) {
5921                out.writeInt(1);
5922                out.writeInt(mCpuClusterSpeed.length);
5923                for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeed) {
5924                    if (cpuSpeeds != null) {
5925                        out.writeInt(1);
5926                        out.writeInt(cpuSpeeds.length);
5927                        for (LongSamplingCounter c : cpuSpeeds) {
5928                            if (c != null) {
5929                                out.writeInt(1);
5930                                c.writeToParcel(out);
5931                            } else {
5932                                out.writeInt(0);
5933                            }
5934                        }
5935                    } else {
5936                        out.writeInt(0);
5937                    }
5938                }
5939            } else {
5940                out.writeInt(0);
5941            }
5942        }
5943
5944        void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
5945            int numWakelocks = in.readInt();
5946            mWakelockStats.clear();
5947            for (int j = 0; j < numWakelocks; j++) {
5948                String wakelockName = in.readString();
5949                Uid.Wakelock wakelock = new Wakelock(mBsi, this);
5950                wakelock.readFromParcelLocked(timeBase, screenOffTimeBase, in);
5951                mWakelockStats.add(wakelockName, wakelock);
5952            }
5953
5954            int numSyncs = in.readInt();
5955            mSyncStats.clear();
5956            for (int j = 0; j < numSyncs; j++) {
5957                String syncName = in.readString();
5958                if (in.readInt() != 0) {
5959                    mSyncStats.add(syncName,
5960                            new StopwatchTimer(mBsi.mClocks, Uid.this, SYNC, null, timeBase, in));
5961                }
5962            }
5963
5964            int numJobs = in.readInt();
5965            mJobStats.clear();
5966            for (int j = 0; j < numJobs; j++) {
5967                String jobName = in.readString();
5968                if (in.readInt() != 0) {
5969                    mJobStats.add(jobName, new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null,
5970                                timeBase, in));
5971                }
5972            }
5973
5974            int numSensors = in.readInt();
5975            mSensorStats.clear();
5976            for (int k = 0; k < numSensors; k++) {
5977                int sensorNumber = in.readInt();
5978                Uid.Sensor sensor = new Sensor(mBsi, this, sensorNumber);
5979                sensor.readFromParcelLocked(mBsi.mOnBatteryTimeBase, in);
5980                mSensorStats.put(sensorNumber, sensor);
5981            }
5982
5983            int numProcs = in.readInt();
5984            mProcessStats.clear();
5985            for (int k = 0; k < numProcs; k++) {
5986                String processName = in.readString();
5987                Uid.Proc proc = new Proc(mBsi, processName);
5988                proc.readFromParcelLocked(in);
5989                mProcessStats.put(processName, proc);
5990            }
5991
5992            int numPkgs = in.readInt();
5993            mPackageStats.clear();
5994            for (int l = 0; l < numPkgs; l++) {
5995                String packageName = in.readString();
5996                Uid.Pkg pkg = new Pkg(mBsi);
5997                pkg.readFromParcelLocked(in);
5998                mPackageStats.put(packageName, pkg);
5999            }
6000
6001            mWifiRunning = false;
6002            if (in.readInt() != 0) {
6003                mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_RUNNING,
6004                        mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase, in);
6005            } else {
6006                mWifiRunningTimer = null;
6007            }
6008            mFullWifiLockOut = false;
6009            if (in.readInt() != 0) {
6010                mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, FULL_WIFI_LOCK,
6011                        mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase, in);
6012            } else {
6013                mFullWifiLockTimer = null;
6014            }
6015            mWifiScanStarted = false;
6016            if (in.readInt() != 0) {
6017                mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
6018                        mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase, in);
6019            } else {
6020                mWifiScanTimer = null;
6021            }
6022            mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
6023            for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
6024                if (in.readInt() != 0) {
6025                    makeWifiBatchedScanBin(i, in);
6026                } else {
6027                    mWifiBatchedScanTimer[i] = null;
6028                }
6029            }
6030            mWifiMulticastEnabled = false;
6031            if (in.readInt() != 0) {
6032                mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_MULTICAST_ENABLED,
6033                        mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase, in);
6034            } else {
6035                mWifiMulticastTimer = null;
6036            }
6037            if (in.readInt() != 0) {
6038                mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, AUDIO_TURNED_ON,
6039                        mBsi.mAudioTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
6040            } else {
6041                mAudioTurnedOnTimer = null;
6042            }
6043            if (in.readInt() != 0) {
6044                mVideoTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, VIDEO_TURNED_ON,
6045                        mBsi.mVideoTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
6046            } else {
6047                mVideoTurnedOnTimer = null;
6048            }
6049            if (in.readInt() != 0) {
6050                mFlashlightTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
6051                        FLASHLIGHT_TURNED_ON, mBsi.mFlashlightTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
6052            } else {
6053                mFlashlightTurnedOnTimer = null;
6054            }
6055            if (in.readInt() != 0) {
6056                mCameraTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, CAMERA_TURNED_ON,
6057                        mBsi.mCameraTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
6058            } else {
6059                mCameraTurnedOnTimer = null;
6060            }
6061            if (in.readInt() != 0) {
6062                mForegroundActivityTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
6063                        FOREGROUND_ACTIVITY, null, mBsi.mOnBatteryTimeBase, in);
6064            } else {
6065                mForegroundActivityTimer = null;
6066            }
6067            if (in.readInt() != 0) {
6068                mBluetoothScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
6069                        mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase, in);
6070            } else {
6071                mBluetoothScanTimer = null;
6072            }
6073            mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
6074            for (int i = 0; i < NUM_PROCESS_STATE; i++) {
6075                if (in.readInt() != 0) {
6076                    makeProcessState(i, in);
6077                } else {
6078                    mProcessStateTimer[i] = null;
6079                }
6080            }
6081            if (in.readInt() != 0) {
6082                mVibratorOnTimer = new BatchTimer(mBsi.mClocks, Uid.this, VIBRATOR_ON,
6083                        mBsi.mOnBatteryTimeBase, in);
6084            } else {
6085                mVibratorOnTimer = null;
6086            }
6087            if (in.readInt() != 0) {
6088                mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
6089                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
6090                    mUserActivityCounters[i] = new Counter(mBsi.mOnBatteryTimeBase, in);
6091                }
6092            } else {
6093                mUserActivityCounters = null;
6094            }
6095            if (in.readInt() != 0) {
6096                mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
6097                mNetworkPacketActivityCounters
6098                        = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
6099                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
6100                    mNetworkByteActivityCounters[i]
6101                            = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
6102                    mNetworkPacketActivityCounters[i]
6103                            = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
6104                }
6105                mMobileRadioActiveTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
6106                mMobileRadioActiveCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
6107            } else {
6108                mNetworkByteActivityCounters = null;
6109                mNetworkPacketActivityCounters = null;
6110            }
6111
6112            if (in.readInt() != 0) {
6113                mWifiControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
6114                        NUM_WIFI_TX_LEVELS, in);
6115            } else {
6116                mWifiControllerActivity = null;
6117            }
6118
6119            if (in.readInt() != 0) {
6120                mBluetoothControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
6121                        NUM_BT_TX_LEVELS, in);
6122            } else {
6123                mBluetoothControllerActivity = null;
6124            }
6125
6126            if (in.readInt() != 0) {
6127                mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
6128                        ModemActivityInfo.TX_POWER_LEVELS, in);
6129            } else {
6130                mModemControllerActivity = null;
6131            }
6132
6133            mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
6134            mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
6135            mCpuPower = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
6136
6137            if (in.readInt() != 0) {
6138                int numCpuClusters = in.readInt();
6139                if (mBsi.mPowerProfile != null && mBsi.mPowerProfile.getNumCpuClusters() != numCpuClusters) {
6140                    throw new ParcelFormatException("Incompatible number of cpu clusters");
6141                }
6142
6143                mCpuClusterSpeed = new LongSamplingCounter[numCpuClusters][];
6144                for (int cluster = 0; cluster < numCpuClusters; cluster++) {
6145                    if (in.readInt() != 0) {
6146                        int numSpeeds = in.readInt();
6147                        if (mBsi.mPowerProfile != null &&
6148                                mBsi.mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
6149                            throw new ParcelFormatException("Incompatible number of cpu speeds");
6150                        }
6151
6152                        final LongSamplingCounter[] cpuSpeeds = new LongSamplingCounter[numSpeeds];
6153                        mCpuClusterSpeed[cluster] = cpuSpeeds;
6154                        for (int speed = 0; speed < numSpeeds; speed++) {
6155                            if (in.readInt() != 0) {
6156                                cpuSpeeds[speed] = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
6157                            }
6158                        }
6159                    } else {
6160                        mCpuClusterSpeed[cluster] = null;
6161                    }
6162                }
6163            } else {
6164                mCpuClusterSpeed = null;
6165            }
6166        }
6167
6168        /**
6169         * The statistics associated with a particular wake lock.
6170         */
6171        public static class Wakelock extends BatteryStats.Uid.Wakelock {
6172            /**
6173             * BatteryStatsImpl that we are associated with.
6174             */
6175            protected BatteryStatsImpl mBsi;
6176
6177            /**
6178             * BatteryStatsImpl that we are associated with.
6179             */
6180            protected Uid mUid;
6181
6182            /**
6183             * How long (in ms) this uid has been keeping the device partially awake.
6184             */
6185            StopwatchTimer mTimerPartial;
6186
6187            /**
6188             * How long (in ms) this uid has been keeping the device fully awake.
6189             */
6190            StopwatchTimer mTimerFull;
6191
6192            /**
6193             * How long (in ms) this uid has had a window keeping the device awake.
6194             */
6195            StopwatchTimer mTimerWindow;
6196
6197            /**
6198             * How long (in ms) this uid has had a draw wake lock.
6199             */
6200            StopwatchTimer mTimerDraw;
6201
6202            public Wakelock(BatteryStatsImpl bsi, Uid uid) {
6203                mBsi = bsi;
6204                mUid = uid;
6205            }
6206
6207            /**
6208             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
6209             * proper timer pool from the given BatteryStatsImpl object.
6210             *
6211             * @param in the Parcel to be read from.
6212             * return a new Timer, or null.
6213             */
6214            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
6215                    TimeBase timeBase, Parcel in) {
6216                if (in.readInt() == 0) {
6217                    return null;
6218                }
6219
6220                return new StopwatchTimer(mBsi.mClocks, mUid, type, pool, timeBase, in);
6221            }
6222
6223            boolean reset() {
6224                boolean wlactive = false;
6225                if (mTimerFull != null) {
6226                    wlactive |= !mTimerFull.reset(false);
6227                }
6228                if (mTimerPartial != null) {
6229                    wlactive |= !mTimerPartial.reset(false);
6230                }
6231                if (mTimerWindow != null) {
6232                    wlactive |= !mTimerWindow.reset(false);
6233                }
6234                if (mTimerDraw != null) {
6235                    wlactive |= !mTimerDraw.reset(false);
6236                }
6237                if (!wlactive) {
6238                    if (mTimerFull != null) {
6239                        mTimerFull.detach();
6240                        mTimerFull = null;
6241                    }
6242                    if (mTimerPartial != null) {
6243                        mTimerPartial.detach();
6244                        mTimerPartial = null;
6245                    }
6246                    if (mTimerWindow != null) {
6247                        mTimerWindow.detach();
6248                        mTimerWindow = null;
6249                    }
6250                    if (mTimerDraw != null) {
6251                        mTimerDraw.detach();
6252                        mTimerDraw = null;
6253                    }
6254                }
6255                return !wlactive;
6256            }
6257
6258            void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
6259                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
6260                        mBsi.mPartialTimers, screenOffTimeBase, in);
6261                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL, mBsi.mFullTimers, timeBase, in);
6262                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW, mBsi.mWindowTimers, timeBase, in);
6263                mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mBsi.mDrawTimers, timeBase, in);
6264            }
6265
6266            void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
6267                Timer.writeTimerToParcel(out, mTimerPartial, elapsedRealtimeUs);
6268                Timer.writeTimerToParcel(out, mTimerFull, elapsedRealtimeUs);
6269                Timer.writeTimerToParcel(out, mTimerWindow, elapsedRealtimeUs);
6270                Timer.writeTimerToParcel(out, mTimerDraw, elapsedRealtimeUs);
6271            }
6272
6273            @Override
6274            public Timer getWakeTime(int type) {
6275                switch (type) {
6276                case WAKE_TYPE_FULL: return mTimerFull;
6277                case WAKE_TYPE_PARTIAL: return mTimerPartial;
6278                case WAKE_TYPE_WINDOW: return mTimerWindow;
6279                case WAKE_TYPE_DRAW: return mTimerDraw;
6280                default: throw new IllegalArgumentException("type = " + type);
6281                }
6282            }
6283
6284            public StopwatchTimer getStopwatchTimer(int type) {
6285                StopwatchTimer t;
6286                switch (type) {
6287                    case WAKE_TYPE_PARTIAL:
6288                        t = mTimerPartial;
6289                        if (t == null) {
6290                            t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL,
6291                                    mBsi.mPartialTimers, mBsi.mOnBatteryScreenOffTimeBase);
6292                            mTimerPartial = t;
6293                        }
6294                        return t;
6295                    case WAKE_TYPE_FULL:
6296                        t = mTimerFull;
6297                        if (t == null) {
6298                            t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_FULL,
6299                                    mBsi.mFullTimers, mBsi.mOnBatteryTimeBase);
6300                            mTimerFull = t;
6301                        }
6302                        return t;
6303                    case WAKE_TYPE_WINDOW:
6304                        t = mTimerWindow;
6305                        if (t == null) {
6306                            t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_WINDOW,
6307                                    mBsi.mWindowTimers, mBsi.mOnBatteryTimeBase);
6308                            mTimerWindow = t;
6309                        }
6310                        return t;
6311                    case WAKE_TYPE_DRAW:
6312                        t = mTimerDraw;
6313                        if (t == null) {
6314                            t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_DRAW,
6315                                    mBsi.mDrawTimers, mBsi.mOnBatteryTimeBase);
6316                            mTimerDraw = t;
6317                        }
6318                        return t;
6319                    default:
6320                        throw new IllegalArgumentException("type=" + type);
6321                }
6322            }
6323        }
6324
6325        public static class Sensor extends BatteryStats.Uid.Sensor {
6326            /**
6327             * BatteryStatsImpl that we are associated with.
6328             */
6329            protected BatteryStatsImpl mBsi;
6330
6331            /**
6332             * BatteryStatsImpl that we are associated with.
6333             */
6334            protected Uid mUid;
6335
6336            final int mHandle;
6337            StopwatchTimer mTimer;
6338
6339            public Sensor(BatteryStatsImpl bsi, Uid uid, int handle) {
6340                mBsi = bsi;
6341                mUid = uid;
6342                mHandle = handle;
6343            }
6344
6345            private StopwatchTimer readTimerFromParcel(TimeBase timeBase, Parcel in) {
6346                if (in.readInt() == 0) {
6347                    return null;
6348                }
6349
6350                ArrayList<StopwatchTimer> pool = mBsi.mSensorTimers.get(mHandle);
6351                if (pool == null) {
6352                    pool = new ArrayList<StopwatchTimer>();
6353                    mBsi.mSensorTimers.put(mHandle, pool);
6354                }
6355                return new StopwatchTimer(mBsi.mClocks, mUid, 0, pool, timeBase, in);
6356            }
6357
6358            boolean reset() {
6359                if (mTimer.reset(true)) {
6360                    mTimer = null;
6361                    return true;
6362                }
6363                return false;
6364            }
6365
6366            void readFromParcelLocked(TimeBase timeBase, Parcel in) {
6367                mTimer = readTimerFromParcel(timeBase, in);
6368            }
6369
6370            void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
6371                Timer.writeTimerToParcel(out, mTimer, elapsedRealtimeUs);
6372            }
6373
6374            @Override
6375            public Timer getSensorTime() {
6376                return mTimer;
6377            }
6378
6379            @Override
6380            public int getHandle() {
6381                return mHandle;
6382            }
6383        }
6384
6385        /**
6386         * The statistics associated with a particular process.
6387         */
6388        public static class Proc extends BatteryStats.Uid.Proc implements TimeBaseObs {
6389            /**
6390             * BatteryStatsImpl that we are associated with.
6391             */
6392            protected BatteryStatsImpl mBsi;
6393
6394            /**
6395             * The name of this process.
6396             */
6397            final String mName;
6398
6399            /**
6400             * Remains true until removed from the stats.
6401             */
6402            boolean mActive = true;
6403
6404            /**
6405             * Total time (in ms) spent executing in user code.
6406             */
6407            long mUserTime;
6408
6409            /**
6410             * Total time (in ms) spent executing in kernel code.
6411             */
6412            long mSystemTime;
6413
6414            /**
6415             * Amount of time (in ms) the process was running in the foreground.
6416             */
6417            long mForegroundTime;
6418
6419            /**
6420             * Number of times the process has been started.
6421             */
6422            int mStarts;
6423
6424            /**
6425             * Number of times the process has crashed.
6426             */
6427            int mNumCrashes;
6428
6429            /**
6430             * Number of times the process has had an ANR.
6431             */
6432            int mNumAnrs;
6433
6434            /**
6435             * The amount of user time loaded from a previous save.
6436             */
6437            long mLoadedUserTime;
6438
6439            /**
6440             * The amount of system time loaded from a previous save.
6441             */
6442            long mLoadedSystemTime;
6443
6444            /**
6445             * The amount of foreground time loaded from a previous save.
6446             */
6447            long mLoadedForegroundTime;
6448
6449            /**
6450             * The number of times the process has started from a previous save.
6451             */
6452            int mLoadedStarts;
6453
6454            /**
6455             * Number of times the process has crashed from a previous save.
6456             */
6457            int mLoadedNumCrashes;
6458
6459            /**
6460             * Number of times the process has had an ANR from a previous save.
6461             */
6462            int mLoadedNumAnrs;
6463
6464            /**
6465             * The amount of user time when last unplugged.
6466             */
6467            long mUnpluggedUserTime;
6468
6469            /**
6470             * The amount of system time when last unplugged.
6471             */
6472            long mUnpluggedSystemTime;
6473
6474            /**
6475             * The amount of foreground time since unplugged.
6476             */
6477            long mUnpluggedForegroundTime;
6478
6479            /**
6480             * The number of times the process has started before unplugged.
6481             */
6482            int mUnpluggedStarts;
6483
6484            /**
6485             * Number of times the process has crashed before unplugged.
6486             */
6487            int mUnpluggedNumCrashes;
6488
6489            /**
6490             * Number of times the process has had an ANR before unplugged.
6491             */
6492            int mUnpluggedNumAnrs;
6493
6494            ArrayList<ExcessivePower> mExcessivePower;
6495
6496            public Proc(BatteryStatsImpl bsi, String name) {
6497                mBsi = bsi;
6498                mName = name;
6499                mBsi.mOnBatteryTimeBase.add(this);
6500            }
6501
6502            public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
6503                mUnpluggedUserTime = mUserTime;
6504                mUnpluggedSystemTime = mSystemTime;
6505                mUnpluggedForegroundTime = mForegroundTime;
6506                mUnpluggedStarts = mStarts;
6507                mUnpluggedNumCrashes = mNumCrashes;
6508                mUnpluggedNumAnrs = mNumAnrs;
6509            }
6510
6511            public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
6512            }
6513
6514            void detach() {
6515                mActive = false;
6516                mBsi.mOnBatteryTimeBase.remove(this);
6517            }
6518
6519            public int countExcessivePowers() {
6520                return mExcessivePower != null ? mExcessivePower.size() : 0;
6521            }
6522
6523            public ExcessivePower getExcessivePower(int i) {
6524                if (mExcessivePower != null) {
6525                    return mExcessivePower.get(i);
6526                }
6527                return null;
6528            }
6529
6530            public void addExcessiveWake(long overTime, long usedTime) {
6531                if (mExcessivePower == null) {
6532                    mExcessivePower = new ArrayList<ExcessivePower>();
6533                }
6534                ExcessivePower ew = new ExcessivePower();
6535                ew.type = ExcessivePower.TYPE_WAKE;
6536                ew.overTime = overTime;
6537                ew.usedTime = usedTime;
6538                mExcessivePower.add(ew);
6539            }
6540
6541            public void addExcessiveCpu(long overTime, long usedTime) {
6542                if (mExcessivePower == null) {
6543                    mExcessivePower = new ArrayList<ExcessivePower>();
6544                }
6545                ExcessivePower ew = new ExcessivePower();
6546                ew.type = ExcessivePower.TYPE_CPU;
6547                ew.overTime = overTime;
6548                ew.usedTime = usedTime;
6549                mExcessivePower.add(ew);
6550            }
6551
6552            void writeExcessivePowerToParcelLocked(Parcel out) {
6553                if (mExcessivePower == null) {
6554                    out.writeInt(0);
6555                    return;
6556                }
6557
6558                final int N = mExcessivePower.size();
6559                out.writeInt(N);
6560                for (int i=0; i<N; i++) {
6561                    ExcessivePower ew = mExcessivePower.get(i);
6562                    out.writeInt(ew.type);
6563                    out.writeLong(ew.overTime);
6564                    out.writeLong(ew.usedTime);
6565                }
6566            }
6567
6568            void readExcessivePowerFromParcelLocked(Parcel in) {
6569                final int N = in.readInt();
6570                if (N == 0) {
6571                    mExcessivePower = null;
6572                    return;
6573                }
6574
6575                if (N > 10000) {
6576                    throw new ParcelFormatException(
6577                            "File corrupt: too many excessive power entries " + N);
6578                }
6579
6580                mExcessivePower = new ArrayList<>();
6581                for (int i=0; i<N; i++) {
6582                    ExcessivePower ew = new ExcessivePower();
6583                    ew.type = in.readInt();
6584                    ew.overTime = in.readLong();
6585                    ew.usedTime = in.readLong();
6586                    mExcessivePower.add(ew);
6587                }
6588            }
6589
6590            void writeToParcelLocked(Parcel out) {
6591                out.writeLong(mUserTime);
6592                out.writeLong(mSystemTime);
6593                out.writeLong(mForegroundTime);
6594                out.writeInt(mStarts);
6595                out.writeInt(mNumCrashes);
6596                out.writeInt(mNumAnrs);
6597                out.writeLong(mLoadedUserTime);
6598                out.writeLong(mLoadedSystemTime);
6599                out.writeLong(mLoadedForegroundTime);
6600                out.writeInt(mLoadedStarts);
6601                out.writeInt(mLoadedNumCrashes);
6602                out.writeInt(mLoadedNumAnrs);
6603                out.writeLong(mUnpluggedUserTime);
6604                out.writeLong(mUnpluggedSystemTime);
6605                out.writeLong(mUnpluggedForegroundTime);
6606                out.writeInt(mUnpluggedStarts);
6607                out.writeInt(mUnpluggedNumCrashes);
6608                out.writeInt(mUnpluggedNumAnrs);
6609                writeExcessivePowerToParcelLocked(out);
6610            }
6611
6612            void readFromParcelLocked(Parcel in) {
6613                mUserTime = in.readLong();
6614                mSystemTime = in.readLong();
6615                mForegroundTime = in.readLong();
6616                mStarts = in.readInt();
6617                mNumCrashes = in.readInt();
6618                mNumAnrs = in.readInt();
6619                mLoadedUserTime = in.readLong();
6620                mLoadedSystemTime = in.readLong();
6621                mLoadedForegroundTime = in.readLong();
6622                mLoadedStarts = in.readInt();
6623                mLoadedNumCrashes = in.readInt();
6624                mLoadedNumAnrs = in.readInt();
6625                mUnpluggedUserTime = in.readLong();
6626                mUnpluggedSystemTime = in.readLong();
6627                mUnpluggedForegroundTime = in.readLong();
6628                mUnpluggedStarts = in.readInt();
6629                mUnpluggedNumCrashes = in.readInt();
6630                mUnpluggedNumAnrs = in.readInt();
6631                readExcessivePowerFromParcelLocked(in);
6632            }
6633
6634            public void addCpuTimeLocked(int utime, int stime) {
6635                mUserTime += utime;
6636                mSystemTime += stime;
6637            }
6638
6639            public void addForegroundTimeLocked(long ttime) {
6640                mForegroundTime += ttime;
6641            }
6642
6643            public void incStartsLocked() {
6644                mStarts++;
6645            }
6646
6647            public void incNumCrashesLocked() {
6648                mNumCrashes++;
6649            }
6650
6651            public void incNumAnrsLocked() {
6652                mNumAnrs++;
6653            }
6654
6655            @Override
6656            public boolean isActive() {
6657                return mActive;
6658            }
6659
6660            @Override
6661            public long getUserTime(int which) {
6662                long val = mUserTime;
6663                if (which == STATS_CURRENT) {
6664                    val -= mLoadedUserTime;
6665                } else if (which == STATS_SINCE_UNPLUGGED) {
6666                    val -= mUnpluggedUserTime;
6667                }
6668                return val;
6669            }
6670
6671            @Override
6672            public long getSystemTime(int which) {
6673                long val = mSystemTime;
6674                if (which == STATS_CURRENT) {
6675                    val -= mLoadedSystemTime;
6676                } else if (which == STATS_SINCE_UNPLUGGED) {
6677                    val -= mUnpluggedSystemTime;
6678                }
6679                return val;
6680            }
6681
6682            @Override
6683            public long getForegroundTime(int which) {
6684                long val = mForegroundTime;
6685                if (which == STATS_CURRENT) {
6686                    val -= mLoadedForegroundTime;
6687                } else if (which == STATS_SINCE_UNPLUGGED) {
6688                    val -= mUnpluggedForegroundTime;
6689                }
6690                return val;
6691            }
6692
6693            @Override
6694            public int getStarts(int which) {
6695                int val = mStarts;
6696                if (which == STATS_CURRENT) {
6697                    val -= mLoadedStarts;
6698                } else if (which == STATS_SINCE_UNPLUGGED) {
6699                    val -= mUnpluggedStarts;
6700                }
6701                return val;
6702            }
6703
6704            @Override
6705            public int getNumCrashes(int which) {
6706                int val = mNumCrashes;
6707                if (which == STATS_CURRENT) {
6708                    val -= mLoadedNumCrashes;
6709                } else if (which == STATS_SINCE_UNPLUGGED) {
6710                    val -= mUnpluggedNumCrashes;
6711                }
6712                return val;
6713            }
6714
6715            @Override
6716            public int getNumAnrs(int which) {
6717                int val = mNumAnrs;
6718                if (which == STATS_CURRENT) {
6719                    val -= mLoadedNumAnrs;
6720                } else if (which == STATS_SINCE_UNPLUGGED) {
6721                    val -= mUnpluggedNumAnrs;
6722                }
6723                return val;
6724            }
6725        }
6726
6727        /**
6728         * The statistics associated with a particular package.
6729         */
6730        public static class Pkg extends BatteryStats.Uid.Pkg implements TimeBaseObs {
6731            /**
6732             * BatteryStatsImpl that we are associated with.
6733             */
6734            protected BatteryStatsImpl mBsi;
6735
6736            /**
6737             * Number of times wakeup alarms have occurred for this app.
6738             */
6739            ArrayMap<String, Counter> mWakeupAlarms = new ArrayMap<>();
6740
6741            /**
6742             * The statics we have collected for this package's services.
6743             */
6744            final ArrayMap<String, Serv> mServiceStats = new ArrayMap<>();
6745
6746            public Pkg(BatteryStatsImpl bsi) {
6747                mBsi = bsi;
6748                mBsi.mOnBatteryScreenOffTimeBase.add(this);
6749            }
6750
6751            public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
6752            }
6753
6754            public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
6755            }
6756
6757            void detach() {
6758                mBsi.mOnBatteryScreenOffTimeBase.remove(this);
6759            }
6760
6761            void readFromParcelLocked(Parcel in) {
6762                int numWA = in.readInt();
6763                mWakeupAlarms.clear();
6764                for (int i=0; i<numWA; i++) {
6765                    String tag = in.readString();
6766                    mWakeupAlarms.put(tag, new Counter(mBsi.mOnBatteryTimeBase, in));
6767                }
6768
6769                int numServs = in.readInt();
6770                mServiceStats.clear();
6771                for (int m = 0; m < numServs; m++) {
6772                    String serviceName = in.readString();
6773                    Uid.Pkg.Serv serv = new Serv(mBsi);
6774                    mServiceStats.put(serviceName, serv);
6775
6776                    serv.readFromParcelLocked(in);
6777                }
6778            }
6779
6780            void writeToParcelLocked(Parcel out) {
6781                int numWA = mWakeupAlarms.size();
6782                out.writeInt(numWA);
6783                for (int i=0; i<numWA; i++) {
6784                    out.writeString(mWakeupAlarms.keyAt(i));
6785                    mWakeupAlarms.valueAt(i).writeToParcel(out);
6786                }
6787
6788                final int NS = mServiceStats.size();
6789                out.writeInt(NS);
6790                for (int i=0; i<NS; i++) {
6791                    out.writeString(mServiceStats.keyAt(i));
6792                    Uid.Pkg.Serv serv = mServiceStats.valueAt(i);
6793                    serv.writeToParcelLocked(out);
6794                }
6795            }
6796
6797            @Override
6798            public ArrayMap<String, ? extends BatteryStats.Counter> getWakeupAlarmStats() {
6799                return mWakeupAlarms;
6800            }
6801
6802            public void noteWakeupAlarmLocked(String tag) {
6803                Counter c = mWakeupAlarms.get(tag);
6804                if (c == null) {
6805                    c = new Counter(mBsi.mOnBatteryTimeBase);
6806                    mWakeupAlarms.put(tag, c);
6807                }
6808                c.stepAtomic();
6809            }
6810
6811            @Override
6812            public ArrayMap<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
6813                return mServiceStats;
6814            }
6815
6816            /**
6817             * The statistics associated with a particular service.
6818             */
6819            public static class Serv extends BatteryStats.Uid.Pkg.Serv implements TimeBaseObs {
6820                /**
6821                 * BatteryStatsImpl that we are associated with.
6822                 */
6823                protected BatteryStatsImpl mBsi;
6824
6825                /**
6826                 * The android package in which this service resides.
6827                 */
6828                protected Pkg mPkg;
6829
6830                /**
6831                 * Total time (ms in battery uptime) the service has been left started.
6832                 */
6833                protected long mStartTime;
6834
6835                /**
6836                 * If service has been started and not yet stopped, this is
6837                 * when it was started.
6838                 */
6839                protected long mRunningSince;
6840
6841                /**
6842                 * True if we are currently running.
6843                 */
6844                protected boolean mRunning;
6845
6846                /**
6847                 * Total number of times startService() has been called.
6848                 */
6849                protected int mStarts;
6850
6851                /**
6852                 * Total time (ms in battery uptime) the service has been left launched.
6853                 */
6854                protected long mLaunchedTime;
6855
6856                /**
6857                 * If service has been launched and not yet exited, this is
6858                 * when it was launched (ms in battery uptime).
6859                 */
6860                protected long mLaunchedSince;
6861
6862                /**
6863                 * True if we are currently launched.
6864                 */
6865                protected boolean mLaunched;
6866
6867                /**
6868                 * Total number times the service has been launched.
6869                 */
6870                protected int mLaunches;
6871
6872                /**
6873                 * The amount of time spent started loaded from a previous save
6874                 * (ms in battery uptime).
6875                 */
6876                protected long mLoadedStartTime;
6877
6878                /**
6879                 * The number of starts loaded from a previous save.
6880                 */
6881                protected int mLoadedStarts;
6882
6883                /**
6884                 * The number of launches loaded from a previous save.
6885                 */
6886                protected int mLoadedLaunches;
6887
6888                /**
6889                 * The amount of time spent started as of the last run (ms
6890                 * in battery uptime).
6891                 */
6892                protected long mLastStartTime;
6893
6894                /**
6895                 * The number of starts as of the last run.
6896                 */
6897                protected int mLastStarts;
6898
6899                /**
6900                 * The number of launches as of the last run.
6901                 */
6902                protected int mLastLaunches;
6903
6904                /**
6905                 * The amount of time spent started when last unplugged (ms
6906                 * in battery uptime).
6907                 */
6908                protected long mUnpluggedStartTime;
6909
6910                /**
6911                 * The number of starts when last unplugged.
6912                 */
6913                protected int mUnpluggedStarts;
6914
6915                /**
6916                 * The number of launches when last unplugged.
6917                 */
6918                protected int mUnpluggedLaunches;
6919
6920                /**
6921                 * Construct a Serv. Also adds it to the on-battery time base as a listener.
6922                 */
6923                public Serv(BatteryStatsImpl bsi) {
6924                    mBsi = bsi;
6925                    mBsi.mOnBatteryTimeBase.add(this);
6926                }
6927
6928                public void onTimeStarted(long elapsedRealtime, long baseUptime,
6929                        long baseRealtime) {
6930                    mUnpluggedStartTime = getStartTimeToNowLocked(baseUptime);
6931                    mUnpluggedStarts = mStarts;
6932                    mUnpluggedLaunches = mLaunches;
6933                }
6934
6935                public void onTimeStopped(long elapsedRealtime, long baseUptime,
6936                        long baseRealtime) {
6937                }
6938
6939                /**
6940                 * Remove this Serv as a listener from the time base.
6941                 */
6942                public void detach() {
6943                    mBsi.mOnBatteryTimeBase.remove(this);
6944                }
6945
6946                public void readFromParcelLocked(Parcel in) {
6947                    mStartTime = in.readLong();
6948                    mRunningSince = in.readLong();
6949                    mRunning = in.readInt() != 0;
6950                    mStarts = in.readInt();
6951                    mLaunchedTime = in.readLong();
6952                    mLaunchedSince = in.readLong();
6953                    mLaunched = in.readInt() != 0;
6954                    mLaunches = in.readInt();
6955                    mLoadedStartTime = in.readLong();
6956                    mLoadedStarts = in.readInt();
6957                    mLoadedLaunches = in.readInt();
6958                    mLastStartTime = 0;
6959                    mLastStarts = 0;
6960                    mLastLaunches = 0;
6961                    mUnpluggedStartTime = in.readLong();
6962                    mUnpluggedStarts = in.readInt();
6963                    mUnpluggedLaunches = in.readInt();
6964                }
6965
6966                public void writeToParcelLocked(Parcel out) {
6967                    out.writeLong(mStartTime);
6968                    out.writeLong(mRunningSince);
6969                    out.writeInt(mRunning ? 1 : 0);
6970                    out.writeInt(mStarts);
6971                    out.writeLong(mLaunchedTime);
6972                    out.writeLong(mLaunchedSince);
6973                    out.writeInt(mLaunched ? 1 : 0);
6974                    out.writeInt(mLaunches);
6975                    out.writeLong(mLoadedStartTime);
6976                    out.writeInt(mLoadedStarts);
6977                    out.writeInt(mLoadedLaunches);
6978                    out.writeLong(mUnpluggedStartTime);
6979                    out.writeInt(mUnpluggedStarts);
6980                    out.writeInt(mUnpluggedLaunches);
6981                }
6982
6983                public long getLaunchTimeToNowLocked(long batteryUptime) {
6984                    if (!mLaunched) return mLaunchedTime;
6985                    return mLaunchedTime + batteryUptime - mLaunchedSince;
6986                }
6987
6988                public long getStartTimeToNowLocked(long batteryUptime) {
6989                    if (!mRunning) return mStartTime;
6990                    return mStartTime + batteryUptime - mRunningSince;
6991                }
6992
6993                public void startLaunchedLocked() {
6994                    if (!mLaunched) {
6995                        mLaunches++;
6996                        mLaunchedSince = mBsi.getBatteryUptimeLocked();
6997                        mLaunched = true;
6998                    }
6999                }
7000
7001                public void stopLaunchedLocked() {
7002                    if (mLaunched) {
7003                        long time = mBsi.getBatteryUptimeLocked() - mLaunchedSince;
7004                        if (time > 0) {
7005                            mLaunchedTime += time;
7006                        } else {
7007                            mLaunches--;
7008                        }
7009                        mLaunched = false;
7010                    }
7011                }
7012
7013                public void startRunningLocked() {
7014                    if (!mRunning) {
7015                        mStarts++;
7016                        mRunningSince = mBsi.getBatteryUptimeLocked();
7017                        mRunning = true;
7018                    }
7019                }
7020
7021                public void stopRunningLocked() {
7022                    if (mRunning) {
7023                        long time = mBsi.getBatteryUptimeLocked() - mRunningSince;
7024                        if (time > 0) {
7025                            mStartTime += time;
7026                        } else {
7027                            mStarts--;
7028                        }
7029                        mRunning = false;
7030                    }
7031                }
7032
7033                public BatteryStatsImpl getBatteryStats() {
7034                    return mBsi;
7035                }
7036
7037                @Override
7038                public int getLaunches(int which) {
7039                    int val = mLaunches;
7040                    if (which == STATS_CURRENT) {
7041                        val -= mLoadedLaunches;
7042                    } else if (which == STATS_SINCE_UNPLUGGED) {
7043                        val -= mUnpluggedLaunches;
7044                    }
7045                    return val;
7046                }
7047
7048                @Override
7049                public long getStartTime(long now, int which) {
7050                    long val = getStartTimeToNowLocked(now);
7051                    if (which == STATS_CURRENT) {
7052                        val -= mLoadedStartTime;
7053                    } else if (which == STATS_SINCE_UNPLUGGED) {
7054                        val -= mUnpluggedStartTime;
7055                    }
7056                    return val;
7057                }
7058
7059                @Override
7060                public int getStarts(int which) {
7061                    int val = mStarts;
7062                    if (which == STATS_CURRENT) {
7063                        val -= mLoadedStarts;
7064                    } else if (which == STATS_SINCE_UNPLUGGED) {
7065                        val -= mUnpluggedStarts;
7066                    }
7067
7068                    return val;
7069                }
7070            }
7071
7072            final Serv newServiceStatsLocked() {
7073                return new Serv(mBsi);
7074            }
7075        }
7076
7077        /**
7078         * Retrieve the statistics object for a particular process, creating
7079         * if needed.
7080         */
7081        public Proc getProcessStatsLocked(String name) {
7082            Proc ps = mProcessStats.get(name);
7083            if (ps == null) {
7084                ps = new Proc(mBsi, name);
7085                mProcessStats.put(name, ps);
7086            }
7087
7088            return ps;
7089        }
7090
7091        public void updateUidProcessStateLocked(int procState) {
7092            int uidRunningState;
7093            if (procState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
7094                uidRunningState = ActivityManager.PROCESS_STATE_NONEXISTENT;
7095            } else if (procState == ActivityManager.PROCESS_STATE_TOP) {
7096                uidRunningState = PROCESS_STATE_TOP;
7097            } else if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
7098                // Persistent and other foreground states go here.
7099                uidRunningState = PROCESS_STATE_FOREGROUND_SERVICE;
7100            } else if (procState <= ActivityManager.PROCESS_STATE_TOP_SLEEPING) {
7101                uidRunningState = PROCESS_STATE_TOP_SLEEPING;
7102            } else if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
7103                // Persistent and other foreground states go here.
7104                uidRunningState = PROCESS_STATE_FOREGROUND;
7105            } else if (procState <= ActivityManager.PROCESS_STATE_RECEIVER) {
7106                uidRunningState = PROCESS_STATE_BACKGROUND;
7107            } else {
7108                uidRunningState = PROCESS_STATE_CACHED;
7109            }
7110
7111            if (mProcessState == uidRunningState) return;
7112
7113            final long elapsedRealtime = mBsi.mClocks.elapsedRealtime();
7114
7115            if (mProcessState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
7116                mProcessStateTimer[mProcessState].stopRunningLocked(elapsedRealtime);
7117            }
7118            mProcessState = uidRunningState;
7119            if (uidRunningState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
7120                if (mProcessStateTimer[uidRunningState] == null) {
7121                    makeProcessState(uidRunningState, null);
7122                }
7123                mProcessStateTimer[uidRunningState].startRunningLocked(elapsedRealtime);
7124            }
7125        }
7126
7127        public SparseArray<? extends Pid> getPidStats() {
7128            return mPids;
7129        }
7130
7131        public Pid getPidStatsLocked(int pid) {
7132            Pid p = mPids.get(pid);
7133            if (p == null) {
7134                p = new Pid();
7135                mPids.put(pid, p);
7136            }
7137            return p;
7138        }
7139
7140        /**
7141         * Retrieve the statistics object for a particular service, creating
7142         * if needed.
7143         */
7144        public Pkg getPackageStatsLocked(String name) {
7145            Pkg ps = mPackageStats.get(name);
7146            if (ps == null) {
7147                ps = new Pkg(mBsi);
7148                mPackageStats.put(name, ps);
7149            }
7150
7151            return ps;
7152        }
7153
7154        /**
7155         * Retrieve the statistics object for a particular service, creating
7156         * if needed.
7157         */
7158        public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
7159            Pkg ps = getPackageStatsLocked(pkg);
7160            Pkg.Serv ss = ps.mServiceStats.get(serv);
7161            if (ss == null) {
7162                ss = ps.newServiceStatsLocked();
7163                ps.mServiceStats.put(serv, ss);
7164            }
7165
7166            return ss;
7167        }
7168
7169        public void readSyncSummaryFromParcelLocked(String name, Parcel in) {
7170            StopwatchTimer timer = mSyncStats.instantiateObject();
7171            timer.readSummaryFromParcelLocked(in);
7172            mSyncStats.add(name, timer);
7173        }
7174
7175        public void readJobSummaryFromParcelLocked(String name, Parcel in) {
7176            StopwatchTimer timer = mJobStats.instantiateObject();
7177            timer.readSummaryFromParcelLocked(in);
7178            mJobStats.add(name, timer);
7179        }
7180
7181        public void readWakeSummaryFromParcelLocked(String wlName, Parcel in) {
7182            Wakelock wl = new Wakelock(mBsi, this);
7183            mWakelockStats.add(wlName, wl);
7184            if (in.readInt() != 0) {
7185                wl.getStopwatchTimer(WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
7186            }
7187            if (in.readInt() != 0) {
7188                wl.getStopwatchTimer(WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
7189            }
7190            if (in.readInt() != 0) {
7191                wl.getStopwatchTimer(WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
7192            }
7193            if (in.readInt() != 0) {
7194                wl.getStopwatchTimer(WAKE_TYPE_DRAW).readSummaryFromParcelLocked(in);
7195            }
7196        }
7197
7198        public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
7199            Sensor se = mSensorStats.get(sensor);
7200            if (se == null) {
7201                if (!create) {
7202                    return null;
7203                }
7204                se = new Sensor(mBsi, this, sensor);
7205                mSensorStats.put(sensor, se);
7206            }
7207            StopwatchTimer t = se.mTimer;
7208            if (t != null) {
7209                return t;
7210            }
7211            ArrayList<StopwatchTimer> timers = mBsi.mSensorTimers.get(sensor);
7212            if (timers == null) {
7213                timers = new ArrayList<StopwatchTimer>();
7214                mBsi.mSensorTimers.put(sensor, timers);
7215            }
7216            t = new StopwatchTimer(mBsi.mClocks, this, BatteryStats.SENSOR, timers,
7217                    mBsi.mOnBatteryTimeBase);
7218            se.mTimer = t;
7219            return t;
7220        }
7221
7222        public void noteStartSyncLocked(String name, long elapsedRealtimeMs) {
7223            StopwatchTimer t = mSyncStats.startObject(name);
7224            if (t != null) {
7225                t.startRunningLocked(elapsedRealtimeMs);
7226            }
7227        }
7228
7229        public void noteStopSyncLocked(String name, long elapsedRealtimeMs) {
7230            StopwatchTimer t = mSyncStats.stopObject(name);
7231            if (t != null) {
7232                t.stopRunningLocked(elapsedRealtimeMs);
7233            }
7234        }
7235
7236        public void noteStartJobLocked(String name, long elapsedRealtimeMs) {
7237            StopwatchTimer t = mJobStats.startObject(name);
7238            if (t != null) {
7239                t.startRunningLocked(elapsedRealtimeMs);
7240            }
7241        }
7242
7243        public void noteStopJobLocked(String name, long elapsedRealtimeMs) {
7244            StopwatchTimer t = mJobStats.stopObject(name);
7245            if (t != null) {
7246                t.stopRunningLocked(elapsedRealtimeMs);
7247            }
7248        }
7249
7250        public void noteStartWakeLocked(int pid, String name, int type, long elapsedRealtimeMs) {
7251            Wakelock wl = mWakelockStats.startObject(name);
7252            if (wl != null) {
7253                wl.getStopwatchTimer(type).startRunningLocked(elapsedRealtimeMs);
7254            }
7255            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
7256                Pid p = getPidStatsLocked(pid);
7257                if (p.mWakeNesting++ == 0) {
7258                    p.mWakeStartMs = elapsedRealtimeMs;
7259                }
7260            }
7261        }
7262
7263        public void noteStopWakeLocked(int pid, String name, int type, long elapsedRealtimeMs) {
7264            Wakelock wl = mWakelockStats.stopObject(name);
7265            if (wl != null) {
7266                wl.getStopwatchTimer(type).stopRunningLocked(elapsedRealtimeMs);
7267            }
7268            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
7269                Pid p = mPids.get(pid);
7270                if (p != null && p.mWakeNesting > 0) {
7271                    if (p.mWakeNesting-- == 1) {
7272                        p.mWakeSumMs += elapsedRealtimeMs - p.mWakeStartMs;
7273                        p.mWakeStartMs = 0;
7274                    }
7275                }
7276            }
7277        }
7278
7279        public void reportExcessiveWakeLocked(String proc, long overTime, long usedTime) {
7280            Proc p = getProcessStatsLocked(proc);
7281            if (p != null) {
7282                p.addExcessiveWake(overTime, usedTime);
7283            }
7284        }
7285
7286        public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) {
7287            Proc p = getProcessStatsLocked(proc);
7288            if (p != null) {
7289                p.addExcessiveCpu(overTime, usedTime);
7290            }
7291        }
7292
7293        public void noteStartSensor(int sensor, long elapsedRealtimeMs) {
7294            StopwatchTimer t = getSensorTimerLocked(sensor, true);
7295            if (t != null) {
7296                t.startRunningLocked(elapsedRealtimeMs);
7297            }
7298        }
7299
7300        public void noteStopSensor(int sensor, long elapsedRealtimeMs) {
7301            // Don't create a timer if one doesn't already exist
7302            StopwatchTimer t = getSensorTimerLocked(sensor, false);
7303            if (t != null) {
7304                t.stopRunningLocked(elapsedRealtimeMs);
7305            }
7306        }
7307
7308        public void noteStartGps(long elapsedRealtimeMs) {
7309            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
7310            if (t != null) {
7311                t.startRunningLocked(elapsedRealtimeMs);
7312            }
7313        }
7314
7315        public void noteStopGps(long elapsedRealtimeMs) {
7316            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
7317            if (t != null) {
7318                t.stopRunningLocked(elapsedRealtimeMs);
7319            }
7320        }
7321
7322        public BatteryStatsImpl getBatteryStats() {
7323            return mBsi;
7324        }
7325    }
7326
7327    public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) {
7328        this(new SystemClocks(), systemDir, handler, externalSync);
7329    }
7330
7331    public BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
7332            ExternalStatsSync externalSync) {
7333        init(clocks);
7334
7335        if (systemDir != null) {
7336            mFile = new JournaledFile(new File(systemDir, "batterystats.bin"),
7337                    new File(systemDir, "batterystats.bin.tmp"));
7338        } else {
7339            mFile = null;
7340        }
7341        mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
7342        mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml"));
7343        mExternalSync = externalSync;
7344        mHandler = new MyHandler(handler.getLooper());
7345        mStartCount++;
7346        mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
7347        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
7348            mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
7349                    mOnBatteryTimeBase);
7350        }
7351        mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase);
7352        mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
7353                mOnBatteryTimeBase);
7354        mDeviceIdleModeLightTimer = new StopwatchTimer(mClocks, null, -11, null,
7355                mOnBatteryTimeBase);
7356        mDeviceIdleModeFullTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
7357        mDeviceLightIdlingTimer = new StopwatchTimer(mClocks, null, -15, null, mOnBatteryTimeBase);
7358        mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase);
7359        mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase);
7360        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
7361            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i, null,
7362                    mOnBatteryTimeBase);
7363        }
7364        mPhoneSignalScanningTimer = new StopwatchTimer(mClocks, null, -200+1, null,
7365                mOnBatteryTimeBase);
7366        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
7367            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClocks, null, -300-i, null,
7368                    mOnBatteryTimeBase);
7369        }
7370        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
7371            mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
7372            mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
7373        }
7374        mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase, NUM_WIFI_TX_LEVELS);
7375        mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
7376                NUM_BT_TX_LEVELS);
7377        mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
7378                ModemActivityInfo.TX_POWER_LEVELS);
7379
7380        mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null, mOnBatteryTimeBase);
7381        mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
7382                mOnBatteryTimeBase);
7383        mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
7384        mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase);
7385        mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase);
7386        mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase);
7387        mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null, mOnBatteryTimeBase);
7388        for (int i=0; i<NUM_WIFI_STATES; i++) {
7389            mWifiStateTimer[i] = new StopwatchTimer(mClocks, null, -600-i, null,
7390                    mOnBatteryTimeBase);
7391        }
7392        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
7393            mWifiSupplStateTimer[i] = new StopwatchTimer(mClocks, null, -700-i, null,
7394                    mOnBatteryTimeBase);
7395        }
7396        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
7397            mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i, null,
7398                    mOnBatteryTimeBase);
7399        }
7400        mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
7401        mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
7402        mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase);
7403        mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase);
7404        mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
7405        mOnBattery = mOnBatteryInternal = false;
7406        long uptime = mClocks.uptimeMillis() * 1000;
7407        long realtime = mClocks.elapsedRealtime() * 1000;
7408        initTimes(uptime, realtime);
7409        mStartPlatformVersion = mEndPlatformVersion = Build.ID;
7410        mDischargeStartLevel = 0;
7411        mDischargeUnplugLevel = 0;
7412        mDischargePlugLevel = -1;
7413        mDischargeCurrentLevel = 0;
7414        mCurrentBatteryLevel = 0;
7415        initDischarge();
7416        clearHistoryLocked();
7417        updateDailyDeadlineLocked();
7418    }
7419
7420    public BatteryStatsImpl(Parcel p) {
7421        this(new SystemClocks(), p);
7422    }
7423
7424    public BatteryStatsImpl(Clocks clocks, Parcel p) {
7425        init(clocks);
7426        mFile = null;
7427        mCheckinFile = null;
7428        mDailyFile = null;
7429        mHandler = null;
7430        mExternalSync = null;
7431        clearHistoryLocked();
7432        readFromParcel(p);
7433    }
7434
7435    public void setPowerProfile(PowerProfile profile) {
7436        synchronized (this) {
7437            mPowerProfile = profile;
7438
7439            // We need to initialize the KernelCpuSpeedReaders to read from
7440            // the first cpu of each core. Once we have the PowerProfile, we have access to this
7441            // information.
7442            final int numClusters = mPowerProfile.getNumCpuClusters();
7443            mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters];
7444            int firstCpuOfCluster = 0;
7445            for (int i = 0; i < numClusters; i++) {
7446                final int numSpeedSteps = mPowerProfile.getNumSpeedStepsInCpuCluster(i);
7447                mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster,
7448                        numSpeedSteps);
7449                firstCpuOfCluster += mPowerProfile.getNumCoresInCpuCluster(i);
7450            }
7451        }
7452    }
7453
7454    public void setCallback(BatteryCallback cb) {
7455        mCallback = cb;
7456    }
7457
7458    public void setRadioScanningTimeout(long timeout) {
7459        if (mPhoneSignalScanningTimer != null) {
7460            mPhoneSignalScanningTimer.setTimeout(timeout);
7461        }
7462    }
7463
7464    public void updateDailyDeadlineLocked() {
7465        // Get the current time.
7466        long currentTime = mDailyStartTime = System.currentTimeMillis();
7467        Calendar calDeadline = Calendar.getInstance();
7468        calDeadline.setTimeInMillis(currentTime);
7469
7470        // Move time up to the next day, ranging from 1am to 3pm.
7471        calDeadline.set(Calendar.DAY_OF_YEAR, calDeadline.get(Calendar.DAY_OF_YEAR) + 1);
7472        calDeadline.set(Calendar.MILLISECOND, 0);
7473        calDeadline.set(Calendar.SECOND, 0);
7474        calDeadline.set(Calendar.MINUTE, 0);
7475        calDeadline.set(Calendar.HOUR_OF_DAY, 1);
7476        mNextMinDailyDeadline = calDeadline.getTimeInMillis();
7477        calDeadline.set(Calendar.HOUR_OF_DAY, 3);
7478        mNextMaxDailyDeadline = calDeadline.getTimeInMillis();
7479    }
7480
7481    public void recordDailyStatsIfNeededLocked(boolean settled) {
7482        long currentTime = System.currentTimeMillis();
7483        if (currentTime >= mNextMaxDailyDeadline) {
7484            recordDailyStatsLocked();
7485        } else if (settled && currentTime >= mNextMinDailyDeadline) {
7486            recordDailyStatsLocked();
7487        } else if (currentTime < (mDailyStartTime-(1000*60*60*24))) {
7488            recordDailyStatsLocked();
7489        }
7490    }
7491
7492    public void recordDailyStatsLocked() {
7493        DailyItem item = new DailyItem();
7494        item.mStartTime = mDailyStartTime;
7495        item.mEndTime = System.currentTimeMillis();
7496        boolean hasData = false;
7497        if (mDailyDischargeStepTracker.mNumStepDurations > 0) {
7498            hasData = true;
7499            item.mDischargeSteps = new LevelStepTracker(
7500                    mDailyDischargeStepTracker.mNumStepDurations,
7501                    mDailyDischargeStepTracker.mStepDurations);
7502        }
7503        if (mDailyChargeStepTracker.mNumStepDurations > 0) {
7504            hasData = true;
7505            item.mChargeSteps = new LevelStepTracker(
7506                    mDailyChargeStepTracker.mNumStepDurations,
7507                    mDailyChargeStepTracker.mStepDurations);
7508        }
7509        if (mDailyPackageChanges != null) {
7510            hasData = true;
7511            item.mPackageChanges = mDailyPackageChanges;
7512            mDailyPackageChanges = null;
7513        }
7514        mDailyDischargeStepTracker.init();
7515        mDailyChargeStepTracker.init();
7516        updateDailyDeadlineLocked();
7517
7518        if (hasData) {
7519            mDailyItems.add(item);
7520            while (mDailyItems.size() > MAX_DAILY_ITEMS) {
7521                mDailyItems.remove(0);
7522            }
7523            final ByteArrayOutputStream memStream = new ByteArrayOutputStream();
7524            try {
7525                XmlSerializer out = new FastXmlSerializer();
7526                out.setOutput(memStream, StandardCharsets.UTF_8.name());
7527                writeDailyItemsLocked(out);
7528                BackgroundThread.getHandler().post(new Runnable() {
7529                    @Override
7530                    public void run() {
7531                        synchronized (mCheckinFile) {
7532                            FileOutputStream stream = null;
7533                            try {
7534                                stream = mDailyFile.startWrite();
7535                                memStream.writeTo(stream);
7536                                stream.flush();
7537                                FileUtils.sync(stream);
7538                                stream.close();
7539                                mDailyFile.finishWrite(stream);
7540                            } catch (IOException e) {
7541                                Slog.w("BatteryStats",
7542                                        "Error writing battery daily items", e);
7543                                mDailyFile.failWrite(stream);
7544                            }
7545                        }
7546                    }
7547                });
7548            } catch (IOException e) {
7549            }
7550        }
7551    }
7552
7553    private void writeDailyItemsLocked(XmlSerializer out) throws IOException {
7554        StringBuilder sb = new StringBuilder(64);
7555        out.startDocument(null, true);
7556        out.startTag(null, "daily-items");
7557        for (int i=0; i<mDailyItems.size(); i++) {
7558            final DailyItem dit = mDailyItems.get(i);
7559            out.startTag(null, "item");
7560            out.attribute(null, "start", Long.toString(dit.mStartTime));
7561            out.attribute(null, "end", Long.toString(dit.mEndTime));
7562            writeDailyLevelSteps(out, "dis", dit.mDischargeSteps, sb);
7563            writeDailyLevelSteps(out, "chg", dit.mChargeSteps, sb);
7564            if (dit.mPackageChanges != null) {
7565                for (int j=0; j<dit.mPackageChanges.size(); j++) {
7566                    PackageChange pc = dit.mPackageChanges.get(j);
7567                    if (pc.mUpdate) {
7568                        out.startTag(null, "upd");
7569                        out.attribute(null, "pkg", pc.mPackageName);
7570                        out.attribute(null, "ver", Integer.toString(pc.mVersionCode));
7571                        out.endTag(null, "upd");
7572                    } else {
7573                        out.startTag(null, "rem");
7574                        out.attribute(null, "pkg", pc.mPackageName);
7575                        out.endTag(null, "rem");
7576                    }
7577                }
7578            }
7579            out.endTag(null, "item");
7580        }
7581        out.endTag(null, "daily-items");
7582        out.endDocument();
7583    }
7584
7585    private void writeDailyLevelSteps(XmlSerializer out, String tag, LevelStepTracker steps,
7586            StringBuilder tmpBuilder) throws IOException {
7587        if (steps != null) {
7588            out.startTag(null, tag);
7589            out.attribute(null, "n", Integer.toString(steps.mNumStepDurations));
7590            for (int i=0; i<steps.mNumStepDurations; i++) {
7591                out.startTag(null, "s");
7592                tmpBuilder.setLength(0);
7593                steps.encodeEntryAt(i, tmpBuilder);
7594                out.attribute(null, "v", tmpBuilder.toString());
7595                out.endTag(null, "s");
7596            }
7597            out.endTag(null, tag);
7598        }
7599    }
7600
7601    public void readDailyStatsLocked() {
7602        Slog.d(TAG, "Reading daily items from " + mDailyFile.getBaseFile());
7603        mDailyItems.clear();
7604        FileInputStream stream;
7605        try {
7606            stream = mDailyFile.openRead();
7607        } catch (FileNotFoundException e) {
7608            return;
7609        }
7610        try {
7611            XmlPullParser parser = Xml.newPullParser();
7612            parser.setInput(stream, StandardCharsets.UTF_8.name());
7613            readDailyItemsLocked(parser);
7614        } catch (XmlPullParserException e) {
7615        } finally {
7616            try {
7617                stream.close();
7618            } catch (IOException e) {
7619            }
7620        }
7621    }
7622
7623    private void readDailyItemsLocked(XmlPullParser parser) {
7624        try {
7625            int type;
7626            while ((type = parser.next()) != XmlPullParser.START_TAG
7627                    && type != XmlPullParser.END_DOCUMENT) {
7628                ;
7629            }
7630
7631            if (type != XmlPullParser.START_TAG) {
7632                throw new IllegalStateException("no start tag found");
7633            }
7634
7635            int outerDepth = parser.getDepth();
7636            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
7637                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
7638                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
7639                    continue;
7640                }
7641
7642                String tagName = parser.getName();
7643                if (tagName.equals("item")) {
7644                    readDailyItemTagLocked(parser);
7645                } else {
7646                    Slog.w(TAG, "Unknown element under <daily-items>: "
7647                            + parser.getName());
7648                    XmlUtils.skipCurrentTag(parser);
7649                }
7650            }
7651
7652        } catch (IllegalStateException e) {
7653            Slog.w(TAG, "Failed parsing daily " + e);
7654        } catch (NullPointerException e) {
7655            Slog.w(TAG, "Failed parsing daily " + e);
7656        } catch (NumberFormatException e) {
7657            Slog.w(TAG, "Failed parsing daily " + e);
7658        } catch (XmlPullParserException e) {
7659            Slog.w(TAG, "Failed parsing daily " + e);
7660        } catch (IOException e) {
7661            Slog.w(TAG, "Failed parsing daily " + e);
7662        } catch (IndexOutOfBoundsException e) {
7663            Slog.w(TAG, "Failed parsing daily " + e);
7664        }
7665    }
7666
7667    void readDailyItemTagLocked(XmlPullParser parser) throws NumberFormatException,
7668            XmlPullParserException, IOException {
7669        DailyItem dit = new DailyItem();
7670        String attr = parser.getAttributeValue(null, "start");
7671        if (attr != null) {
7672            dit.mStartTime = Long.parseLong(attr);
7673        }
7674        attr = parser.getAttributeValue(null, "end");
7675        if (attr != null) {
7676            dit.mEndTime = Long.parseLong(attr);
7677        }
7678        int outerDepth = parser.getDepth();
7679        int type;
7680        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
7681                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
7682            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
7683                continue;
7684            }
7685
7686            String tagName = parser.getName();
7687            if (tagName.equals("dis")) {
7688                readDailyItemTagDetailsLocked(parser, dit, false, "dis");
7689            } else if (tagName.equals("chg")) {
7690                readDailyItemTagDetailsLocked(parser, dit, true, "chg");
7691            } else if (tagName.equals("upd")) {
7692                if (dit.mPackageChanges == null) {
7693                    dit.mPackageChanges = new ArrayList<>();
7694                }
7695                PackageChange pc = new PackageChange();
7696                pc.mUpdate = true;
7697                pc.mPackageName = parser.getAttributeValue(null, "pkg");
7698                String verStr = parser.getAttributeValue(null, "ver");
7699                pc.mVersionCode = verStr != null ? Integer.parseInt(verStr) : 0;
7700                dit.mPackageChanges.add(pc);
7701                XmlUtils.skipCurrentTag(parser);
7702            } else if (tagName.equals("rem")) {
7703                if (dit.mPackageChanges == null) {
7704                    dit.mPackageChanges = new ArrayList<>();
7705                }
7706                PackageChange pc = new PackageChange();
7707                pc.mUpdate = false;
7708                pc.mPackageName = parser.getAttributeValue(null, "pkg");
7709                dit.mPackageChanges.add(pc);
7710                XmlUtils.skipCurrentTag(parser);
7711            } else {
7712                Slog.w(TAG, "Unknown element under <item>: "
7713                        + parser.getName());
7714                XmlUtils.skipCurrentTag(parser);
7715            }
7716        }
7717        mDailyItems.add(dit);
7718    }
7719
7720    void readDailyItemTagDetailsLocked(XmlPullParser parser, DailyItem dit, boolean isCharge,
7721            String tag)
7722            throws NumberFormatException, XmlPullParserException, IOException {
7723        final String numAttr = parser.getAttributeValue(null, "n");
7724        if (numAttr == null) {
7725            Slog.w(TAG, "Missing 'n' attribute at " + parser.getPositionDescription());
7726            XmlUtils.skipCurrentTag(parser);
7727            return;
7728        }
7729        final int num = Integer.parseInt(numAttr);
7730        LevelStepTracker steps = new LevelStepTracker(num);
7731        if (isCharge) {
7732            dit.mChargeSteps = steps;
7733        } else {
7734            dit.mDischargeSteps = steps;
7735        }
7736        int i = 0;
7737        int outerDepth = parser.getDepth();
7738        int type;
7739        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
7740                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
7741            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
7742                continue;
7743            }
7744
7745            String tagName = parser.getName();
7746            if ("s".equals(tagName)) {
7747                if (i < num) {
7748                    String valueAttr = parser.getAttributeValue(null, "v");
7749                    if (valueAttr != null) {
7750                        steps.decodeEntryAt(i, valueAttr);
7751                        i++;
7752                    }
7753                }
7754            } else {
7755                Slog.w(TAG, "Unknown element under <" + tag + ">: "
7756                        + parser.getName());
7757                XmlUtils.skipCurrentTag(parser);
7758            }
7759        }
7760        steps.mNumStepDurations = i;
7761    }
7762
7763    @Override
7764    public DailyItem getDailyItemLocked(int daysAgo) {
7765        int index = mDailyItems.size()-1-daysAgo;
7766        return index >= 0 ? mDailyItems.get(index) : null;
7767    }
7768
7769    @Override
7770    public long getCurrentDailyStartTime() {
7771        return mDailyStartTime;
7772    }
7773
7774    @Override
7775    public long getNextMinDailyDeadline() {
7776        return mNextMinDailyDeadline;
7777    }
7778
7779    @Override
7780    public long getNextMaxDailyDeadline() {
7781        return mNextMaxDailyDeadline;
7782    }
7783
7784    @Override
7785    public boolean startIteratingOldHistoryLocked() {
7786        if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
7787                + " pos=" + mHistoryBuffer.dataPosition());
7788        if ((mHistoryIterator = mHistory) == null) {
7789            return false;
7790        }
7791        mHistoryBuffer.setDataPosition(0);
7792        mHistoryReadTmp.clear();
7793        mReadOverflow = false;
7794        mIteratingHistory = true;
7795        return true;
7796    }
7797
7798    @Override
7799    public boolean getNextOldHistoryLocked(HistoryItem out) {
7800        boolean end = mHistoryBuffer.dataPosition() >= mHistoryBuffer.dataSize();
7801        if (!end) {
7802            readHistoryDelta(mHistoryBuffer, mHistoryReadTmp);
7803            mReadOverflow |= mHistoryReadTmp.cmd == HistoryItem.CMD_OVERFLOW;
7804        }
7805        HistoryItem cur = mHistoryIterator;
7806        if (cur == null) {
7807            if (!mReadOverflow && !end) {
7808                Slog.w(TAG, "Old history ends before new history!");
7809            }
7810            return false;
7811        }
7812        out.setTo(cur);
7813        mHistoryIterator = cur.next;
7814        if (!mReadOverflow) {
7815            if (end) {
7816                Slog.w(TAG, "New history ends before old history!");
7817            } else if (!out.same(mHistoryReadTmp)) {
7818                PrintWriter pw = new FastPrintWriter(new LogWriter(android.util.Log.WARN, TAG));
7819                pw.println("Histories differ!");
7820                pw.println("Old history:");
7821                (new HistoryPrinter()).printNextItem(pw, out, 0, false, true);
7822                pw.println("New history:");
7823                (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, 0, false,
7824                        true);
7825                pw.flush();
7826            }
7827        }
7828        return true;
7829    }
7830
7831    @Override
7832    public void finishIteratingOldHistoryLocked() {
7833        mIteratingHistory = false;
7834        mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
7835        mHistoryIterator = null;
7836    }
7837
7838    public int getHistoryTotalSize() {
7839        return MAX_HISTORY_BUFFER;
7840    }
7841
7842    public int getHistoryUsedSize() {
7843        return mHistoryBuffer.dataSize();
7844    }
7845
7846    @Override
7847    public boolean startIteratingHistoryLocked() {
7848        if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
7849                + " pos=" + mHistoryBuffer.dataPosition());
7850        if (mHistoryBuffer.dataSize() <= 0) {
7851            return false;
7852        }
7853        mHistoryBuffer.setDataPosition(0);
7854        mReadOverflow = false;
7855        mIteratingHistory = true;
7856        mReadHistoryStrings = new String[mHistoryTagPool.size()];
7857        mReadHistoryUids = new int[mHistoryTagPool.size()];
7858        mReadHistoryChars = 0;
7859        for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
7860            final HistoryTag tag = ent.getKey();
7861            final int idx = ent.getValue();
7862            mReadHistoryStrings[idx] = tag.string;
7863            mReadHistoryUids[idx] = tag.uid;
7864            mReadHistoryChars += tag.string.length() + 1;
7865        }
7866        return true;
7867    }
7868
7869    @Override
7870    public int getHistoryStringPoolSize() {
7871        return mReadHistoryStrings.length;
7872    }
7873
7874    @Override
7875    public int getHistoryStringPoolBytes() {
7876        // Each entry is a fixed 12 bytes: 4 for index, 4 for uid, 4 for string size
7877        // Each string character is 2 bytes.
7878        return (mReadHistoryStrings.length * 12) + (mReadHistoryChars * 2);
7879    }
7880
7881    @Override
7882    public String getHistoryTagPoolString(int index) {
7883        return mReadHistoryStrings[index];
7884    }
7885
7886    @Override
7887    public int getHistoryTagPoolUid(int index) {
7888        return mReadHistoryUids[index];
7889    }
7890
7891    @Override
7892    public boolean getNextHistoryLocked(HistoryItem out) {
7893        final int pos = mHistoryBuffer.dataPosition();
7894        if (pos == 0) {
7895            out.clear();
7896        }
7897        boolean end = pos >= mHistoryBuffer.dataSize();
7898        if (end) {
7899            return false;
7900        }
7901
7902        final long lastRealtime = out.time;
7903        final long lastWalltime = out.currentTime;
7904        readHistoryDelta(mHistoryBuffer, out);
7905        if (out.cmd != HistoryItem.CMD_CURRENT_TIME
7906                && out.cmd != HistoryItem.CMD_RESET && lastWalltime != 0) {
7907            out.currentTime = lastWalltime + (out.time - lastRealtime);
7908        }
7909        return true;
7910    }
7911
7912    @Override
7913    public void finishIteratingHistoryLocked() {
7914        mIteratingHistory = false;
7915        mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
7916        mReadHistoryStrings = null;
7917    }
7918
7919    @Override
7920    public long getHistoryBaseTime() {
7921        return mHistoryBaseTime;
7922    }
7923
7924    @Override
7925    public int getStartCount() {
7926        return mStartCount;
7927    }
7928
7929    public boolean isOnBattery() {
7930        return mOnBattery;
7931    }
7932
7933    public boolean isCharging() {
7934        return mCharging;
7935    }
7936
7937    public boolean isScreenOn() {
7938        return mScreenState == Display.STATE_ON;
7939    }
7940
7941    void initTimes(long uptime, long realtime) {
7942        mStartClockTime = System.currentTimeMillis();
7943        mOnBatteryTimeBase.init(uptime, realtime);
7944        mOnBatteryScreenOffTimeBase.init(uptime, realtime);
7945        mRealtime = 0;
7946        mUptime = 0;
7947        mRealtimeStart = realtime;
7948        mUptimeStart = uptime;
7949    }
7950
7951    void initDischarge() {
7952        mLowDischargeAmountSinceCharge = 0;
7953        mHighDischargeAmountSinceCharge = 0;
7954        mDischargeAmountScreenOn = 0;
7955        mDischargeAmountScreenOnSinceCharge = 0;
7956        mDischargeAmountScreenOff = 0;
7957        mDischargeAmountScreenOffSinceCharge = 0;
7958        mDischargeStepTracker.init();
7959        mChargeStepTracker.init();
7960    }
7961
7962    public void resetAllStatsCmdLocked() {
7963        resetAllStatsLocked();
7964        final long mSecUptime = mClocks.uptimeMillis();
7965        long uptime = mSecUptime * 1000;
7966        long mSecRealtime = mClocks.elapsedRealtime();
7967        long realtime = mSecRealtime * 1000;
7968        mDischargeStartLevel = mHistoryCur.batteryLevel;
7969        pullPendingStateUpdatesLocked();
7970        addHistoryRecordLocked(mSecRealtime, mSecUptime);
7971        mDischargeCurrentLevel = mDischargeUnplugLevel = mDischargePlugLevel
7972                = mCurrentBatteryLevel = mHistoryCur.batteryLevel;
7973        mOnBatteryTimeBase.reset(uptime, realtime);
7974        mOnBatteryScreenOffTimeBase.reset(uptime, realtime);
7975        if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) {
7976            if (mScreenState == Display.STATE_ON) {
7977                mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel;
7978                mDischargeScreenOffUnplugLevel = 0;
7979            } else {
7980                mDischargeScreenOnUnplugLevel = 0;
7981                mDischargeScreenOffUnplugLevel = mHistoryCur.batteryLevel;
7982            }
7983            mDischargeAmountScreenOn = 0;
7984            mDischargeAmountScreenOff = 0;
7985        }
7986        initActiveHistoryEventsLocked(mSecRealtime, mSecUptime);
7987    }
7988
7989    private void resetAllStatsLocked() {
7990        mStartCount = 0;
7991        initTimes(mClocks.uptimeMillis() * 1000, mClocks.elapsedRealtime() * 1000);
7992        mScreenOnTimer.reset(false);
7993        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
7994            mScreenBrightnessTimer[i].reset(false);
7995        }
7996        mInteractiveTimer.reset(false);
7997        mPowerSaveModeEnabledTimer.reset(false);
7998        mLongestLightIdleTime = 0;
7999        mLongestFullIdleTime = 0;
8000        mDeviceIdleModeLightTimer.reset(false);
8001        mDeviceIdleModeFullTimer.reset(false);
8002        mDeviceLightIdlingTimer.reset(false);
8003        mDeviceIdlingTimer.reset(false);
8004        mPhoneOnTimer.reset(false);
8005        mAudioOnTimer.reset(false);
8006        mVideoOnTimer.reset(false);
8007        mFlashlightOnTimer.reset(false);
8008        mCameraOnTimer.reset(false);
8009        mBluetoothScanTimer.reset(false);
8010        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
8011            mPhoneSignalStrengthsTimer[i].reset(false);
8012        }
8013        mPhoneSignalScanningTimer.reset(false);
8014        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
8015            mPhoneDataConnectionsTimer[i].reset(false);
8016        }
8017        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
8018            mNetworkByteActivityCounters[i].reset(false);
8019            mNetworkPacketActivityCounters[i].reset(false);
8020        }
8021        mMobileRadioActiveTimer.reset(false);
8022        mMobileRadioActivePerAppTimer.reset(false);
8023        mMobileRadioActiveAdjustedTime.reset(false);
8024        mMobileRadioActiveUnknownTime.reset(false);
8025        mMobileRadioActiveUnknownCount.reset(false);
8026        mWifiOnTimer.reset(false);
8027        mGlobalWifiRunningTimer.reset(false);
8028        for (int i=0; i<NUM_WIFI_STATES; i++) {
8029            mWifiStateTimer[i].reset(false);
8030        }
8031        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
8032            mWifiSupplStateTimer[i].reset(false);
8033        }
8034        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
8035            mWifiSignalStrengthsTimer[i].reset(false);
8036        }
8037        mWifiActivity.reset(false);
8038        mBluetoothActivity.reset(false);
8039        mModemActivity.reset(false);
8040        mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0;
8041
8042        for (int i=0; i<mUidStats.size(); i++) {
8043            if (mUidStats.valueAt(i).reset()) {
8044                mUidStats.remove(mUidStats.keyAt(i));
8045                i--;
8046            }
8047        }
8048
8049        if (mKernelWakelockStats.size() > 0) {
8050            for (SamplingTimer timer : mKernelWakelockStats.values()) {
8051                mOnBatteryScreenOffTimeBase.remove(timer);
8052            }
8053            mKernelWakelockStats.clear();
8054        }
8055
8056        if (mWakeupReasonStats.size() > 0) {
8057            for (SamplingTimer timer : mWakeupReasonStats.values()) {
8058                mOnBatteryTimeBase.remove(timer);
8059            }
8060            mWakeupReasonStats.clear();
8061        }
8062
8063        mLastHistoryStepDetails = null;
8064        mLastStepCpuUserTime = mLastStepCpuSystemTime = 0;
8065        mCurStepCpuUserTime = mCurStepCpuSystemTime = 0;
8066        mLastStepCpuUserTime = mCurStepCpuUserTime = 0;
8067        mLastStepCpuSystemTime = mCurStepCpuSystemTime = 0;
8068        mLastStepStatUserTime = mCurStepStatUserTime = 0;
8069        mLastStepStatSystemTime = mCurStepStatSystemTime = 0;
8070        mLastStepStatIOWaitTime = mCurStepStatIOWaitTime = 0;
8071        mLastStepStatIrqTime = mCurStepStatIrqTime = 0;
8072        mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime = 0;
8073        mLastStepStatIdleTime = mCurStepStatIdleTime = 0;
8074
8075        initDischarge();
8076
8077        clearHistoryLocked();
8078    }
8079
8080    private void initActiveHistoryEventsLocked(long elapsedRealtimeMs, long uptimeMs) {
8081        for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
8082            if (!mRecordAllHistory && i == HistoryItem.EVENT_PROC) {
8083                // Not recording process starts/stops.
8084                continue;
8085            }
8086            HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(i);
8087            if (active == null) {
8088                continue;
8089            }
8090            for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
8091                SparseIntArray uids = ent.getValue();
8092                for (int j=0; j<uids.size(); j++) {
8093                    addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, i, ent.getKey(),
8094                            uids.keyAt(j));
8095                }
8096            }
8097        }
8098    }
8099
8100    void updateDischargeScreenLevelsLocked(boolean oldScreenOn, boolean newScreenOn) {
8101        if (oldScreenOn) {
8102            int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
8103            if (diff > 0) {
8104                mDischargeAmountScreenOn += diff;
8105                mDischargeAmountScreenOnSinceCharge += diff;
8106            }
8107        } else {
8108            int diff = mDischargeScreenOffUnplugLevel - mDischargeCurrentLevel;
8109            if (diff > 0) {
8110                mDischargeAmountScreenOff += diff;
8111                mDischargeAmountScreenOffSinceCharge += diff;
8112            }
8113        }
8114        if (newScreenOn) {
8115            mDischargeScreenOnUnplugLevel = mDischargeCurrentLevel;
8116            mDischargeScreenOffUnplugLevel = 0;
8117        } else {
8118            mDischargeScreenOnUnplugLevel = 0;
8119            mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
8120        }
8121    }
8122
8123    public void pullPendingStateUpdatesLocked() {
8124        if (mOnBatteryInternal) {
8125            final boolean screenOn = mScreenState == Display.STATE_ON;
8126            updateDischargeScreenLevelsLocked(screenOn, screenOn);
8127        }
8128    }
8129
8130    private String[] mMobileIfaces = EmptyArray.STRING;
8131    private String[] mWifiIfaces = EmptyArray.STRING;
8132
8133    private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
8134
8135    private static final int NETWORK_STATS_LAST = 0;
8136    private static final int NETWORK_STATS_NEXT = 1;
8137    private static final int NETWORK_STATS_DELTA = 2;
8138
8139    private NetworkStats[] mMobileNetworkStats;
8140    private NetworkStats[] mWifiNetworkStats;
8141
8142    /**
8143     * Retrieves the delta of network stats for the given network ifaces. Uses networkStatsBuffer
8144     * as a buffer of NetworkStats objects to cycle through when computing deltas.
8145     */
8146    private NetworkStats getNetworkStatsDeltaLocked(String[] ifaces,
8147                                                    NetworkStats[] networkStatsBuffer)
8148            throws IOException {
8149        if (!SystemProperties.getBoolean(NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED,
8150                false)) {
8151            return null;
8152        }
8153
8154        final NetworkStats stats = mNetworkStatsFactory.readNetworkStatsDetail(NetworkStats.UID_ALL,
8155                ifaces, NetworkStats.TAG_NONE, networkStatsBuffer[NETWORK_STATS_NEXT]);
8156        networkStatsBuffer[NETWORK_STATS_DELTA] = NetworkStats.subtract(stats,
8157                networkStatsBuffer[NETWORK_STATS_LAST], null, null,
8158                networkStatsBuffer[NETWORK_STATS_DELTA]);
8159        networkStatsBuffer[NETWORK_STATS_NEXT] = networkStatsBuffer[NETWORK_STATS_LAST];
8160        networkStatsBuffer[NETWORK_STATS_LAST] = stats;
8161        return networkStatsBuffer[NETWORK_STATS_DELTA];
8162    }
8163
8164    /**
8165     * Distribute WiFi energy info and network traffic to apps.
8166     * @param info The energy information from the WiFi controller.
8167     */
8168    public void updateWifiStateLocked(@Nullable final WifiActivityEnergyInfo info) {
8169        if (DEBUG_ENERGY) {
8170            Slog.d(TAG, "Updating wifi stats");
8171        }
8172
8173        final long elapsedRealtimeMs = mClocks.elapsedRealtime();
8174        NetworkStats delta = null;
8175        try {
8176            if (!ArrayUtils.isEmpty(mWifiIfaces)) {
8177                delta = getNetworkStatsDeltaLocked(mWifiIfaces, mWifiNetworkStats);
8178            }
8179        } catch (IOException e) {
8180            Slog.wtf(TAG, "Failed to get wifi network stats", e);
8181            return;
8182        }
8183
8184        if (!mOnBatteryInternal) {
8185            return;
8186        }
8187
8188        SparseLongArray rxPackets = new SparseLongArray();
8189        SparseLongArray txPackets = new SparseLongArray();
8190        long totalTxPackets = 0;
8191        long totalRxPackets = 0;
8192        if (delta != null) {
8193            final int size = delta.size();
8194            for (int i = 0; i < size; i++) {
8195                final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
8196
8197                if (DEBUG_ENERGY) {
8198                    Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes
8199                            + " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets
8200                            + " txPackets=" + entry.txPackets);
8201                }
8202
8203                if (entry.rxBytes == 0 && entry.txBytes == 0) {
8204                    // Skip the lookup below since there is no work to do.
8205                    continue;
8206                }
8207
8208                final Uid u = getUidStatsLocked(mapUid(entry.uid));
8209                if (entry.rxBytes != 0) {
8210                    u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
8211                            entry.rxPackets);
8212                    mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
8213                            entry.rxBytes);
8214                    mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
8215                            entry.rxPackets);
8216
8217                    rxPackets.put(u.getUid(), entry.rxPackets);
8218
8219                    // Sum the total number of packets so that the Rx Power can
8220                    // be evenly distributed amongst the apps.
8221                    totalRxPackets += entry.rxPackets;
8222                }
8223
8224                if (entry.txBytes != 0) {
8225                    u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes,
8226                            entry.txPackets);
8227                    mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
8228                            entry.txBytes);
8229                    mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
8230                            entry.txPackets);
8231
8232                    txPackets.put(u.getUid(), entry.txPackets);
8233
8234                    // Sum the total number of packets so that the Tx Power can
8235                    // be evenly distributed amongst the apps.
8236                    totalTxPackets += entry.txPackets;
8237                }
8238            }
8239        }
8240
8241        if (info != null) {
8242            mHasWifiReporting = true;
8243
8244            // Measured in mAms
8245            final long txTimeMs = info.getControllerTxTimeMillis();
8246            final long rxTimeMs = info.getControllerRxTimeMillis();
8247            final long idleTimeMs = info.getControllerIdleTimeMillis();
8248            final long totalTimeMs = txTimeMs + rxTimeMs + idleTimeMs;
8249
8250            long leftOverRxTimeMs = rxTimeMs;
8251            long leftOverTxTimeMs = txTimeMs;
8252
8253            if (DEBUG_ENERGY) {
8254                Slog.d(TAG, "------ BEGIN WiFi power blaming ------");
8255                Slog.d(TAG, "  Tx Time:    " + txTimeMs + " ms");
8256                Slog.d(TAG, "  Rx Time:    " + rxTimeMs + " ms");
8257                Slog.d(TAG, "  Idle Time:  " + idleTimeMs + " ms");
8258                Slog.d(TAG, "  Total Time: " + totalTimeMs + " ms");
8259            }
8260
8261            long totalWifiLockTimeMs = 0;
8262            long totalScanTimeMs = 0;
8263
8264            // On the first pass, collect some totals so that we can normalize power
8265            // calculations if we need to.
8266            final int uidStatsSize = mUidStats.size();
8267            for (int i = 0; i < uidStatsSize; i++) {
8268                final Uid uid = mUidStats.valueAt(i);
8269
8270                // Sum the total scan power for all apps.
8271                totalScanTimeMs += uid.mWifiScanTimer.getTimeSinceMarkLocked(
8272                        elapsedRealtimeMs * 1000) / 1000;
8273
8274                // Sum the total time holding wifi lock for all apps.
8275                totalWifiLockTimeMs += uid.mFullWifiLockTimer.getTimeSinceMarkLocked(
8276                        elapsedRealtimeMs * 1000) / 1000;
8277            }
8278
8279            if (DEBUG_ENERGY && totalScanTimeMs > rxTimeMs) {
8280                Slog.d(TAG, "  !Estimated scan time > Actual rx time (" + totalScanTimeMs + " ms > "
8281                        + rxTimeMs + " ms). Normalizing scan time.");
8282            }
8283            if (DEBUG_ENERGY && totalScanTimeMs > txTimeMs) {
8284                Slog.d(TAG, "  !Estimated scan time > Actual tx time (" + totalScanTimeMs + " ms > "
8285                        + txTimeMs + " ms). Normalizing scan time.");
8286            }
8287
8288            // Actually assign and distribute power usage to apps.
8289            for (int i = 0; i < uidStatsSize; i++) {
8290                final Uid uid = mUidStats.valueAt(i);
8291
8292                long scanTimeSinceMarkMs = uid.mWifiScanTimer.getTimeSinceMarkLocked(
8293                        elapsedRealtimeMs * 1000) / 1000;
8294                if (scanTimeSinceMarkMs > 0) {
8295                    // Set the new mark so that next time we get new data since this point.
8296                    uid.mWifiScanTimer.setMark(elapsedRealtimeMs);
8297
8298                    long scanRxTimeSinceMarkMs = scanTimeSinceMarkMs;
8299                    long scanTxTimeSinceMarkMs = scanTimeSinceMarkMs;
8300
8301                    // Our total scan time is more than the reported Tx/Rx time.
8302                    // This is possible because the cost of a scan is approximate.
8303                    // Let's normalize the result so that we evenly blame each app
8304                    // scanning.
8305                    //
8306                    // This means that we may have apps that transmitted/received packets not be
8307                    // blamed for this, but this is fine as scans are relatively more expensive.
8308                    if (totalScanTimeMs > rxTimeMs) {
8309                        scanRxTimeSinceMarkMs = (rxTimeMs * scanRxTimeSinceMarkMs) /
8310                                totalScanTimeMs;
8311                    }
8312                    if (totalScanTimeMs > txTimeMs) {
8313                        scanTxTimeSinceMarkMs = (txTimeMs * scanTxTimeSinceMarkMs) /
8314                                totalScanTimeMs;
8315                    }
8316
8317                    if (DEBUG_ENERGY) {
8318                        Slog.d(TAG, "  ScanTime for UID " + uid.getUid() + ": Rx:"
8319                                + scanRxTimeSinceMarkMs + " ms  Tx:"
8320                                + scanTxTimeSinceMarkMs + " ms)");
8321                    }
8322
8323                    ControllerActivityCounterImpl activityCounter =
8324                            uid.getOrCreateWifiControllerActivityLocked();
8325                    activityCounter.getRxTimeCounter().addCountLocked(scanRxTimeSinceMarkMs);
8326                    activityCounter.getTxTimeCounters()[0].addCountLocked(scanTxTimeSinceMarkMs);
8327                    leftOverRxTimeMs -= scanRxTimeSinceMarkMs;
8328                    leftOverTxTimeMs -= scanTxTimeSinceMarkMs;
8329                }
8330
8331                // Distribute evenly the power consumed while Idle to each app holding a WiFi
8332                // lock.
8333                final long wifiLockTimeSinceMarkMs = uid.mFullWifiLockTimer.getTimeSinceMarkLocked(
8334                        elapsedRealtimeMs * 1000) / 1000;
8335                if (wifiLockTimeSinceMarkMs > 0) {
8336                    // Set the new mark so that next time we get new data since this point.
8337                    uid.mFullWifiLockTimer.setMark(elapsedRealtimeMs);
8338
8339                    final long myIdleTimeMs = (wifiLockTimeSinceMarkMs * idleTimeMs)
8340                            / totalWifiLockTimeMs;
8341                    if (DEBUG_ENERGY) {
8342                        Slog.d(TAG, "  IdleTime for UID " + uid.getUid() + ": "
8343                                + myIdleTimeMs + " ms");
8344                    }
8345                    uid.getOrCreateWifiControllerActivityLocked().getIdleTimeCounter()
8346                            .addCountLocked(myIdleTimeMs);
8347                }
8348            }
8349
8350            if (DEBUG_ENERGY) {
8351                Slog.d(TAG, "  New RxPower: " + leftOverRxTimeMs + " ms");
8352                Slog.d(TAG, "  New TxPower: " + leftOverTxTimeMs + " ms");
8353            }
8354
8355            // Distribute the remaining Tx power appropriately between all apps that transmitted
8356            // packets.
8357            for (int i = 0; i < txPackets.size(); i++) {
8358                final Uid uid = getUidStatsLocked(txPackets.keyAt(i));
8359                final long myTxTimeMs = (txPackets.valueAt(i) * leftOverTxTimeMs) / totalTxPackets;
8360                if (DEBUG_ENERGY) {
8361                    Slog.d(TAG, "  TxTime for UID " + uid.getUid() + ": " + myTxTimeMs + " ms");
8362                }
8363                uid.getOrCreateWifiControllerActivityLocked().getTxTimeCounters()[0]
8364                        .addCountLocked(myTxTimeMs);
8365            }
8366
8367            // Distribute the remaining Rx power appropriately between all apps that received
8368            // packets.
8369            for (int i = 0; i < rxPackets.size(); i++) {
8370                final Uid uid = getUidStatsLocked(rxPackets.keyAt(i));
8371                final long myRxTimeMs = (rxPackets.valueAt(i) * leftOverRxTimeMs) / totalRxPackets;
8372                if (DEBUG_ENERGY) {
8373                    Slog.d(TAG, "  RxTime for UID " + uid.getUid() + ": " + myRxTimeMs + " ms");
8374                }
8375                uid.getOrCreateWifiControllerActivityLocked().getRxTimeCounter()
8376                        .addCountLocked(myRxTimeMs);
8377            }
8378
8379            // Any left over power use will be picked up by the WiFi category in BatteryStatsHelper.
8380
8381            // Update WiFi controller stats.
8382            mWifiActivity.getRxTimeCounter().addCountLocked(info.getControllerRxTimeMillis());
8383            mWifiActivity.getTxTimeCounters()[0].addCountLocked(info.getControllerTxTimeMillis());
8384            mWifiActivity.getIdleTimeCounter().addCountLocked(info.getControllerIdleTimeMillis());
8385
8386            // POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
8387            final double opVolt = mPowerProfile.getAveragePower(
8388                    PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
8389            if (opVolt != 0) {
8390                // We store the power drain as mAms.
8391                mWifiActivity.getPowerCounter().addCountLocked(
8392                        (long)(info.getControllerEnergyUsed() / opVolt));
8393            }
8394        }
8395    }
8396
8397    /**
8398     * Distribute Cell radio energy info and network traffic to apps.
8399     */
8400    public void updateMobileRadioStateLocked(final long elapsedRealtimeMs,
8401                                             final ModemActivityInfo activityInfo) {
8402        if (DEBUG_ENERGY) {
8403            Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
8404        }
8405
8406        NetworkStats delta = null;
8407        try {
8408            if (!ArrayUtils.isEmpty(mMobileIfaces)) {
8409                delta = getNetworkStatsDeltaLocked(mMobileIfaces, mMobileNetworkStats);
8410            }
8411        } catch (IOException e) {
8412            Slog.wtf(TAG, "Failed to get mobile network stats", e);
8413            return;
8414        }
8415
8416        if (!mOnBatteryInternal) {
8417            return;
8418        }
8419
8420        long radioTime = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
8421                elapsedRealtimeMs * 1000);
8422        mMobileRadioActivePerAppTimer.setMark(elapsedRealtimeMs);
8423
8424        long totalRxPackets = 0;
8425        long totalTxPackets = 0;
8426        if (delta != null) {
8427            final int size = delta.size();
8428            for (int i = 0; i < size; i++) {
8429                final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
8430                if (entry.rxPackets == 0 && entry.txPackets == 0) {
8431                    continue;
8432                }
8433
8434                if (DEBUG_ENERGY) {
8435                    Slog.d(TAG, "Mobile uid " + entry.uid + ": delta rx=" + entry.rxBytes
8436                            + " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets
8437                            + " txPackets=" + entry.txPackets);
8438                }
8439
8440                totalRxPackets += entry.rxPackets;
8441                totalTxPackets += entry.txPackets;
8442
8443                final Uid u = getUidStatsLocked(mapUid(entry.uid));
8444                u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes, entry.rxPackets);
8445                u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes, entry.txPackets);
8446
8447                mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
8448                        entry.rxBytes);
8449                mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
8450                        entry.txBytes);
8451                mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
8452                        entry.rxPackets);
8453                mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
8454                        entry.txPackets);
8455            }
8456
8457            // Now distribute proportional blame to the apps that did networking.
8458            long totalPackets = totalRxPackets + totalTxPackets;
8459            if (totalPackets > 0) {
8460                for (int i = 0; i < size; i++) {
8461                    final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
8462                    if (entry.rxPackets == 0 && entry.txPackets == 0) {
8463                        continue;
8464                    }
8465
8466                    final Uid u = getUidStatsLocked(mapUid(entry.uid));
8467
8468                    // Distribute total radio active time in to this app.
8469                    final long appPackets = entry.rxPackets + entry.txPackets;
8470                    final long appRadioTime = (radioTime * appPackets) / totalPackets;
8471                    u.noteMobileRadioActiveTimeLocked(appRadioTime);
8472
8473                    // Remove this app from the totals, so that we don't lose any time
8474                    // due to rounding.
8475                    radioTime -= appRadioTime;
8476                    totalPackets -= appPackets;
8477
8478                    if (activityInfo != null) {
8479                        ControllerActivityCounterImpl activityCounter =
8480                                u.getOrCreateModemControllerActivityLocked();
8481                        if (totalRxPackets > 0 && entry.rxPackets > 0) {
8482                            final long rxMs = (entry.rxPackets * activityInfo.getRxTimeMillis())
8483                                    / totalRxPackets;
8484                            activityCounter.getRxTimeCounter().addCountLocked(rxMs);
8485                        }
8486
8487                        if (totalTxPackets > 0 && entry.txPackets > 0) {
8488                            for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
8489                                long txMs = entry.txPackets * activityInfo.getTxTimeMillis()[lvl];
8490                                txMs /= totalTxPackets;
8491                                activityCounter.getTxTimeCounters()[lvl].addCountLocked(txMs);
8492                            }
8493                        }
8494                    }
8495                }
8496            }
8497
8498            if (radioTime > 0) {
8499                // Whoops, there is some radio time we can't blame on an app!
8500                mMobileRadioActiveUnknownTime.addCountLocked(radioTime);
8501                mMobileRadioActiveUnknownCount.addCountLocked(1);
8502            }
8503        }
8504
8505        if (activityInfo != null) {
8506            mHasModemReporting = true;
8507            mModemActivity.getIdleTimeCounter().addCountLocked(activityInfo.getIdleTimeMillis());
8508            mModemActivity.getRxTimeCounter().addCountLocked(activityInfo.getRxTimeMillis());
8509            for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
8510                mModemActivity.getTxTimeCounters()[lvl]
8511                        .addCountLocked(activityInfo.getTxTimeMillis()[lvl]);
8512            }
8513
8514            // POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
8515            final double opVolt = mPowerProfile.getAveragePower(
8516                    PowerProfile.POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
8517            if (opVolt != 0) {
8518                // We store the power drain as mAms.
8519                mModemActivity.getPowerCounter().addCountLocked(
8520                        (long) (activityInfo.getEnergyUsed() / opVolt));
8521            }
8522        }
8523    }
8524
8525    /**
8526     * Distribute Bluetooth energy info and network traffic to apps.
8527     * @param info The energy information from the bluetooth controller.
8528     */
8529    public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
8530        if (DEBUG_ENERGY) {
8531            Slog.d(TAG, "Updating bluetooth stats: " + info);
8532        }
8533
8534        if (info == null || !mOnBatteryInternal) {
8535            return;
8536        }
8537
8538        mHasBluetoothReporting = true;
8539
8540        final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
8541        final long rxTimeMs = info.getControllerRxTimeMillis();
8542        final long txTimeMs = info.getControllerTxTimeMillis();
8543
8544        if (DEBUG_ENERGY) {
8545            Slog.d(TAG, "------ BEGIN BLE power blaming ------");
8546            Slog.d(TAG, "  Tx Time:    " + txTimeMs + " ms");
8547            Slog.d(TAG, "  Rx Time:    " + rxTimeMs + " ms");
8548            Slog.d(TAG, "  Idle Time:  " + info.getControllerIdleTimeMillis() + " ms");
8549        }
8550
8551        long totalScanTimeMs = 0;
8552
8553        final int uidCount = mUidStats.size();
8554        for (int i = 0; i < uidCount; i++) {
8555            final Uid u = mUidStats.valueAt(i);
8556            if (u.mBluetoothScanTimer == null) {
8557                continue;
8558            }
8559
8560            totalScanTimeMs += u.mBluetoothScanTimer.getTimeSinceMarkLocked(
8561                    elapsedRealtimeMs * 1000) / 1000;
8562        }
8563
8564        final boolean normalizeScanRxTime = (totalScanTimeMs > rxTimeMs);
8565        final boolean normalizeScanTxTime = (totalScanTimeMs > txTimeMs);
8566
8567        if (DEBUG_ENERGY) {
8568            Slog.d(TAG, "Normalizing scan power for RX=" + normalizeScanRxTime
8569                    + " TX=" + normalizeScanTxTime);
8570        }
8571
8572        long leftOverRxTimeMs = rxTimeMs;
8573        long leftOverTxTimeMs = txTimeMs;
8574
8575        for (int i = 0; i < uidCount; i++) {
8576            final Uid u = mUidStats.valueAt(i);
8577            if (u.mBluetoothScanTimer == null) {
8578                continue;
8579            }
8580
8581            long scanTimeSinceMarkMs = u.mBluetoothScanTimer.getTimeSinceMarkLocked(
8582                    elapsedRealtimeMs * 1000) / 1000;
8583            if (scanTimeSinceMarkMs > 0) {
8584                // Set the new mark so that next time we get new data since this point.
8585                u.mBluetoothScanTimer.setMark(elapsedRealtimeMs);
8586
8587                long scanTimeRxSinceMarkMs = scanTimeSinceMarkMs;
8588                long scanTimeTxSinceMarkMs = scanTimeSinceMarkMs;
8589
8590                if (normalizeScanRxTime) {
8591                    // Scan time is longer than the total rx time in the controller,
8592                    // so distribute the scan time proportionately. This means regular traffic
8593                    // will not blamed, but scans are more expensive anyways.
8594                    scanTimeRxSinceMarkMs = (rxTimeMs * scanTimeRxSinceMarkMs) / totalScanTimeMs;
8595                }
8596
8597                if (normalizeScanTxTime) {
8598                    // Scan time is longer than the total tx time in the controller,
8599                    // so distribute the scan time proportionately. This means regular traffic
8600                    // will not blamed, but scans are more expensive anyways.
8601                    scanTimeTxSinceMarkMs = (txTimeMs * scanTimeTxSinceMarkMs) / totalScanTimeMs;
8602                }
8603
8604                final ControllerActivityCounterImpl counter =
8605                        u.getOrCreateBluetoothControllerActivityLocked();
8606                counter.getRxTimeCounter().addCountLocked(scanTimeRxSinceMarkMs);
8607                counter.getTxTimeCounters()[0].addCountLocked(scanTimeTxSinceMarkMs);
8608
8609                leftOverRxTimeMs -= scanTimeRxSinceMarkMs;
8610                leftOverTxTimeMs -= scanTimeTxSinceMarkMs;
8611            }
8612        }
8613
8614        if (DEBUG_ENERGY) {
8615            Slog.d(TAG, "Left over time for traffic RX=" + leftOverRxTimeMs
8616                    + " TX=" + leftOverTxTimeMs);
8617        }
8618
8619        //
8620        // Now distribute blame to apps that did bluetooth traffic.
8621        //
8622
8623        long totalTxBytes = 0;
8624        long totalRxBytes = 0;
8625
8626        final UidTraffic[] uidTraffic = info.getUidTraffic();
8627        final int numUids = uidTraffic != null ? uidTraffic.length : 0;
8628        for (int i = 0; i < numUids; i++) {
8629            final UidTraffic traffic = uidTraffic[i];
8630
8631            // Add to the global counters.
8632            mNetworkByteActivityCounters[NETWORK_BT_RX_DATA].addCountLocked(
8633                    traffic.getRxBytes());
8634            mNetworkByteActivityCounters[NETWORK_BT_TX_DATA].addCountLocked(
8635                    traffic.getTxBytes());
8636
8637            // Add to the UID counters.
8638            final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
8639            u.noteNetworkActivityLocked(NETWORK_BT_RX_DATA, traffic.getRxBytes(), 0);
8640            u.noteNetworkActivityLocked(NETWORK_BT_TX_DATA, traffic.getTxBytes(), 0);
8641
8642            // Calculate the total traffic.
8643            totalTxBytes += traffic.getTxBytes();
8644            totalRxBytes += traffic.getRxBytes();
8645        }
8646
8647        if ((totalTxBytes != 0 || totalRxBytes != 0) &&
8648                (leftOverRxTimeMs != 0 || leftOverTxTimeMs != 0)) {
8649            for (int i = 0; i < numUids; i++) {
8650                final UidTraffic traffic = uidTraffic[i];
8651
8652                final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
8653                final ControllerActivityCounterImpl counter =
8654                        u.getOrCreateBluetoothControllerActivityLocked();
8655
8656                if (totalRxBytes > 0 && traffic.getRxBytes() > 0) {
8657                    final long timeRxMs = (leftOverRxTimeMs * traffic.getRxBytes()) / totalRxBytes;
8658
8659                    if (DEBUG_ENERGY) {
8660                        Slog.d(TAG, "UID=" + traffic.getUid() + " rx_bytes=" + traffic.getRxBytes()
8661                                + " rx_time=" + timeRxMs);
8662                    }
8663                    counter.getRxTimeCounter().addCountLocked(timeRxMs);
8664                    leftOverRxTimeMs -= timeRxMs;
8665                }
8666
8667                if (totalTxBytes > 0 && traffic.getTxBytes() > 0) {
8668                    final long timeTxMs = (leftOverTxTimeMs * traffic.getTxBytes()) / totalTxBytes;
8669
8670                    if (DEBUG_ENERGY) {
8671                        Slog.d(TAG, "UID=" + traffic.getUid() + " tx_bytes=" + traffic.getTxBytes()
8672                                + " tx_time=" + timeTxMs);
8673                    }
8674
8675                    counter.getTxTimeCounters()[0].addCountLocked(timeTxMs);
8676                    leftOverTxTimeMs -= timeTxMs;
8677                }
8678            }
8679        }
8680
8681        mBluetoothActivity.getRxTimeCounter().addCountLocked(
8682                info.getControllerRxTimeMillis());
8683        mBluetoothActivity.getTxTimeCounters()[0].addCountLocked(
8684                info.getControllerTxTimeMillis());
8685        mBluetoothActivity.getIdleTimeCounter().addCountLocked(
8686                info.getControllerIdleTimeMillis());
8687
8688        // POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
8689        final double opVolt = mPowerProfile.getAveragePower(
8690                PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
8691        if (opVolt != 0) {
8692            // We store the power drain as mAms.
8693            mBluetoothActivity.getPowerCounter().addCountLocked(
8694                    (long) (info.getControllerEnergyUsed() / opVolt));
8695        }
8696    }
8697
8698    /**
8699     * Read and distribute kernel wake lock use across apps.
8700     */
8701    public void updateKernelWakelocksLocked() {
8702        final KernelWakelockStats wakelockStats = mKernelWakelockReader.readKernelWakelockStats(
8703                mTmpWakelockStats);
8704        if (wakelockStats == null) {
8705            // Not crashing might make board bringup easier.
8706            Slog.w(TAG, "Couldn't get kernel wake lock stats");
8707            return;
8708        }
8709
8710        // Record whether we've seen a non-zero time (for debugging b/22716723).
8711        boolean seenNonZeroTime = false;
8712        for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
8713            String name = ent.getKey();
8714            KernelWakelockStats.Entry kws = ent.getValue();
8715
8716            SamplingTimer kwlt = mKernelWakelockStats.get(name);
8717            if (kwlt == null) {
8718                kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase,
8719                        true /* track reported val */);
8720                mKernelWakelockStats.put(name, kwlt);
8721            }
8722            kwlt.updateCurrentReportedCount(kws.mCount);
8723            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
8724            kwlt.setUpdateVersion(kws.mVersion);
8725
8726            if (kws.mVersion != wakelockStats.kernelWakelockVersion)
8727            seenNonZeroTime |= kws.mTotalTime > 0;
8728        }
8729
8730        int numWakelocksSetStale = 0;
8731        if (wakelockStats.size() != mKernelWakelockStats.size()) {
8732            // Set timers to stale if they didn't appear in /proc/wakelocks this time.
8733            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
8734                SamplingTimer st = ent.getValue();
8735                if (st.getUpdateVersion() != wakelockStats.kernelWakelockVersion) {
8736                    st.setStale();
8737                    numWakelocksSetStale++;
8738                }
8739            }
8740        }
8741
8742        if (!seenNonZeroTime) {
8743            Slog.wtf(TAG, "All kernel wakelocks had time of zero");
8744        }
8745
8746        if (numWakelocksSetStale == mKernelWakelockStats.size()) {
8747            Slog.wtf(TAG, "All kernel wakelocks were set stale. new version=" +
8748                    wakelockStats.kernelWakelockVersion);
8749        }
8750    }
8751
8752    // We use an anonymous class to access these variables,
8753    // so they can't live on the stack or they'd have to be
8754    // final MutableLong objects (more allocations).
8755    // Used in updateCpuTimeLocked().
8756    long mTempTotalCpuUserTimeUs;
8757    long mTempTotalCpuSystemTimeUs;
8758
8759    /**
8760     * Read and distribute CPU usage across apps. If their are partial wakelocks being held
8761     * and we are on battery with screen off, we give more of the cpu time to those apps holding
8762     * wakelocks. If the screen is on, we just assign the actual cpu time an app used.
8763     */
8764    public void updateCpuTimeLocked() {
8765        if (mPowerProfile == null) {
8766            return;
8767        }
8768
8769        if (DEBUG_ENERGY_CPU) {
8770            Slog.d(TAG, "!Cpu updating!");
8771        }
8772
8773        // Holding a wakelock costs more than just using the cpu.
8774        // Currently, we assign only half the cpu time to an app that is running but
8775        // not holding a wakelock. The apps holding wakelocks get the rest of the blame.
8776        // If no app is holding a wakelock, then the distribution is normal.
8777        final int wakelockWeight = 50;
8778
8779        // Read the time spent for each cluster at various cpu frequencies.
8780        final long[][] clusterSpeeds = new long[mKernelCpuSpeedReaders.length][];
8781        for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
8782            clusterSpeeds[cluster] = mKernelCpuSpeedReaders[cluster].readDelta();
8783        }
8784
8785        int numWakelocks = 0;
8786
8787        // Calculate how many wakelocks we have to distribute amongst. The system is excluded.
8788        // Only distribute cpu power to wakelocks if the screen is off and we're on battery.
8789        final int numPartialTimers = mPartialTimers.size();
8790        if (mOnBatteryScreenOffTimeBase.isRunning()) {
8791            for (int i = 0; i < numPartialTimers; i++) {
8792                final StopwatchTimer timer = mPartialTimers.get(i);
8793                if (timer.mInList && timer.mUid != null && timer.mUid.mUid != Process.SYSTEM_UID) {
8794                    // Since the collection and blaming of wakelocks can be scheduled to run after
8795                    // some delay, the mPartialTimers list may have new entries. We can't blame
8796                    // the newly added timer for past cpu time, so we only consider timers that
8797                    // were present for one round of collection. Once a timer has gone through
8798                    // a round of collection, its mInList field is set to true.
8799                    numWakelocks++;
8800                }
8801            }
8802        }
8803
8804        final int numWakelocksF = numWakelocks;
8805        mTempTotalCpuUserTimeUs = 0;
8806        mTempTotalCpuSystemTimeUs = 0;
8807
8808        // Read the CPU data for each UID. This will internally generate a snapshot so next time
8809        // we read, we get a delta. If we are to distribute the cpu time, then do so. Otherwise
8810        // we just ignore the data.
8811        final long startTimeMs = mClocks.elapsedRealtime();
8812        mKernelUidCpuTimeReader.readDelta(!mOnBatteryInternal ? null :
8813                new KernelUidCpuTimeReader.Callback() {
8814                    @Override
8815                    public void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs,
8816                                             long powerMaUs) {
8817                        final Uid u = getUidStatsLocked(mapUid(uid));
8818
8819                        // Accumulate the total system and user time.
8820                        mTempTotalCpuUserTimeUs += userTimeUs;
8821                        mTempTotalCpuSystemTimeUs += systemTimeUs;
8822
8823                        StringBuilder sb = null;
8824                        if (DEBUG_ENERGY_CPU) {
8825                            sb = new StringBuilder();
8826                            sb.append("  got time for uid=").append(u.mUid).append(": u=");
8827                            TimeUtils.formatDuration(userTimeUs / 1000, sb);
8828                            sb.append(" s=");
8829                            TimeUtils.formatDuration(systemTimeUs / 1000, sb);
8830                            sb.append(" p=").append(powerMaUs / 1000).append("mAms\n");
8831                        }
8832
8833                        if (numWakelocksF > 0) {
8834                            // We have wakelocks being held, so only give a portion of the
8835                            // time to the process. The rest will be distributed among wakelock
8836                            // holders.
8837                            userTimeUs = (userTimeUs * wakelockWeight) / 100;
8838                            systemTimeUs = (systemTimeUs * wakelockWeight) / 100;
8839                        }
8840
8841                        if (sb != null) {
8842                            sb.append("  adding to uid=").append(u.mUid).append(": u=");
8843                            TimeUtils.formatDuration(userTimeUs / 1000, sb);
8844                            sb.append(" s=");
8845                            TimeUtils.formatDuration(systemTimeUs / 1000, sb);
8846                            sb.append(" p=").append(powerMaUs / 1000).append("mAms");
8847                            Slog.d(TAG, sb.toString());
8848                        }
8849
8850                        u.mUserCpuTime.addCountLocked(userTimeUs);
8851                        u.mSystemCpuTime.addCountLocked(systemTimeUs);
8852                        u.mCpuPower.addCountLocked(powerMaUs);
8853
8854                        // Add the cpu speeds to this UID. These are used as a ratio
8855                        // for computing the power this UID used.
8856                        final int numClusters = mPowerProfile.getNumCpuClusters();
8857                        if (u.mCpuClusterSpeed == null || u.mCpuClusterSpeed.length !=
8858                                numClusters) {
8859                            u.mCpuClusterSpeed = new LongSamplingCounter[numClusters][];
8860                        }
8861
8862                        for (int cluster = 0; cluster < clusterSpeeds.length; cluster++) {
8863                            final int speedsInCluster = mPowerProfile.getNumSpeedStepsInCpuCluster(
8864                                    cluster);
8865                            if (u.mCpuClusterSpeed[cluster] == null || speedsInCluster !=
8866                                    u.mCpuClusterSpeed[cluster].length) {
8867                                u.mCpuClusterSpeed[cluster] =
8868                                        new LongSamplingCounter[speedsInCluster];
8869                            }
8870
8871                            final LongSamplingCounter[] cpuSpeeds = u.mCpuClusterSpeed[cluster];
8872                            for (int speed = 0; speed < clusterSpeeds[cluster].length; speed++) {
8873                                if (cpuSpeeds[speed] == null) {
8874                                    cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase);
8875                                }
8876                                cpuSpeeds[speed].addCountLocked(clusterSpeeds[cluster][speed]);
8877                            }
8878                        }
8879                    }
8880                });
8881
8882        if (DEBUG_ENERGY_CPU) {
8883            Slog.d(TAG, "Reading cpu stats took " + (mClocks.elapsedRealtime() - startTimeMs) +
8884                    " ms");
8885        }
8886
8887        if (mOnBatteryInternal && numWakelocks > 0) {
8888            // Distribute a portion of the total cpu time to wakelock holders.
8889            mTempTotalCpuUserTimeUs = (mTempTotalCpuUserTimeUs * (100 - wakelockWeight)) / 100;
8890            mTempTotalCpuSystemTimeUs =
8891                    (mTempTotalCpuSystemTimeUs * (100 - wakelockWeight)) / 100;
8892
8893            for (int i = 0; i < numPartialTimers; i++) {
8894                final StopwatchTimer timer = mPartialTimers.get(i);
8895
8896                // The system does not share any blame, as it is usually holding the wakelock
8897                // on behalf of an app.
8898                if (timer.mInList && timer.mUid != null && timer.mUid.mUid != Process.SYSTEM_UID) {
8899                    int userTimeUs = (int) (mTempTotalCpuUserTimeUs / numWakelocks);
8900                    int systemTimeUs = (int) (mTempTotalCpuSystemTimeUs / numWakelocks);
8901
8902                    if (DEBUG_ENERGY_CPU) {
8903                        StringBuilder sb = new StringBuilder();
8904                        sb.append("  Distributing wakelock uid=").append(timer.mUid.mUid)
8905                                .append(": u=");
8906                        TimeUtils.formatDuration(userTimeUs / 1000, sb);
8907                        sb.append(" s=");
8908                        TimeUtils.formatDuration(systemTimeUs / 1000, sb);
8909                        Slog.d(TAG, sb.toString());
8910                    }
8911
8912                    timer.mUid.mUserCpuTime.addCountLocked(userTimeUs);
8913                    timer.mUid.mSystemCpuTime.addCountLocked(systemTimeUs);
8914
8915                    final Uid.Proc proc = timer.mUid.getProcessStatsLocked("*wakelock*");
8916                    proc.addCpuTimeLocked(userTimeUs / 1000, systemTimeUs / 1000);
8917
8918                    mTempTotalCpuUserTimeUs -= userTimeUs;
8919                    mTempTotalCpuSystemTimeUs -= systemTimeUs;
8920                    numWakelocks--;
8921                }
8922            }
8923
8924            if (mTempTotalCpuUserTimeUs > 0 || mTempTotalCpuSystemTimeUs > 0) {
8925                // Anything left over is given to the system.
8926                if (DEBUG_ENERGY_CPU) {
8927                    StringBuilder sb = new StringBuilder();
8928                    sb.append("  Distributing lost time to system: u=");
8929                    TimeUtils.formatDuration(mTempTotalCpuUserTimeUs / 1000, sb);
8930                    sb.append(" s=");
8931                    TimeUtils.formatDuration(mTempTotalCpuSystemTimeUs / 1000, sb);
8932                    Slog.d(TAG, sb.toString());
8933                }
8934
8935                final Uid u = getUidStatsLocked(Process.SYSTEM_UID);
8936                u.mUserCpuTime.addCountLocked(mTempTotalCpuUserTimeUs);
8937                u.mSystemCpuTime.addCountLocked(mTempTotalCpuSystemTimeUs);
8938
8939                final Uid.Proc proc = u.getProcessStatsLocked("*lost*");
8940                proc.addCpuTimeLocked((int) mTempTotalCpuUserTimeUs / 1000,
8941                        (int) mTempTotalCpuSystemTimeUs / 1000);
8942            }
8943        }
8944
8945        // See if there is a difference in wakelocks between this collection and the last
8946        // collection.
8947        if (ArrayUtils.referenceEquals(mPartialTimers, mLastPartialTimers)) {
8948            // No difference, so each timer is now considered for the next collection.
8949            for (int i = 0; i < numPartialTimers; i++) {
8950                mPartialTimers.get(i).mInList = true;
8951            }
8952        } else {
8953            // The lists are different, meaning we added (or removed a timer) since the last
8954            // collection.
8955            final int numLastPartialTimers = mLastPartialTimers.size();
8956            for (int i = 0; i < numLastPartialTimers; i++) {
8957                mLastPartialTimers.get(i).mInList = false;
8958            }
8959            mLastPartialTimers.clear();
8960
8961            // Mark the current timers as gone through a collection.
8962            for (int i = 0; i < numPartialTimers; i++) {
8963                final StopwatchTimer timer = mPartialTimers.get(i);
8964                timer.mInList = true;
8965                mLastPartialTimers.add(timer);
8966            }
8967        }
8968    }
8969
8970    boolean setChargingLocked(boolean charging) {
8971        if (mCharging != charging) {
8972            mCharging = charging;
8973            if (charging) {
8974                mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
8975            } else {
8976                mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG;
8977            }
8978            mHandler.sendEmptyMessage(MSG_REPORT_CHARGING);
8979            return true;
8980        }
8981        return false;
8982    }
8983
8984    void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery,
8985            final int oldStatus, final int level) {
8986        boolean doWrite = false;
8987        Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
8988        m.arg1 = onBattery ? 1 : 0;
8989        mHandler.sendMessage(m);
8990
8991        final long uptime = mSecUptime * 1000;
8992        final long realtime = mSecRealtime * 1000;
8993        final boolean screenOn = mScreenState == Display.STATE_ON;
8994        if (onBattery) {
8995            // We will reset our status if we are unplugging after the
8996            // battery was last full, or the level is at 100, or
8997            // we have gone through a significant charge (from a very low
8998            // level to a now very high level).
8999            boolean reset = false;
9000            if (!mNoAutoReset && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
9001                    || level >= 90
9002                    || (mDischargeCurrentLevel < 20 && level >= 80)
9003                    || (getHighDischargeAmountSinceCharge() >= 200
9004                            && mHistoryBuffer.dataSize() >= MAX_HISTORY_BUFFER))) {
9005                Slog.i(TAG, "Resetting battery stats: level=" + level + " status=" + oldStatus
9006                        + " dischargeLevel=" + mDischargeCurrentLevel
9007                        + " lowAmount=" + getLowDischargeAmountSinceCharge()
9008                        + " highAmount=" + getHighDischargeAmountSinceCharge());
9009                // Before we write, collect a snapshot of the final aggregated
9010                // stats to be reported in the next checkin.  Only do this if we have
9011                // a sufficient amount of data to make it interesting.
9012                if (getLowDischargeAmountSinceCharge() >= 20) {
9013                    final Parcel parcel = Parcel.obtain();
9014                    writeSummaryToParcel(parcel, true);
9015                    BackgroundThread.getHandler().post(new Runnable() {
9016                        @Override public void run() {
9017                            synchronized (mCheckinFile) {
9018                                FileOutputStream stream = null;
9019                                try {
9020                                    stream = mCheckinFile.startWrite();
9021                                    stream.write(parcel.marshall());
9022                                    stream.flush();
9023                                    FileUtils.sync(stream);
9024                                    stream.close();
9025                                    mCheckinFile.finishWrite(stream);
9026                                } catch (IOException e) {
9027                                    Slog.w("BatteryStats",
9028                                            "Error writing checkin battery statistics", e);
9029                                    mCheckinFile.failWrite(stream);
9030                                } finally {
9031                                    parcel.recycle();
9032                                }
9033                            }
9034                        }
9035                    });
9036                }
9037                doWrite = true;
9038                resetAllStatsLocked();
9039                mDischargeStartLevel = level;
9040                reset = true;
9041                mDischargeStepTracker.init();
9042            }
9043            if (mCharging) {
9044                setChargingLocked(false);
9045            }
9046            mLastChargingStateLevel = level;
9047            mOnBattery = mOnBatteryInternal = true;
9048            mLastDischargeStepLevel = level;
9049            mMinDischargeStepLevel = level;
9050            mDischargeStepTracker.clearTime();
9051            mDailyDischargeStepTracker.clearTime();
9052            mInitStepMode = mCurStepMode;
9053            mModStepMode = 0;
9054            pullPendingStateUpdatesLocked();
9055            mHistoryCur.batteryLevel = (byte)level;
9056            mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
9057            if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
9058                    + Integer.toHexString(mHistoryCur.states));
9059            if (reset) {
9060                mRecordingHistory = true;
9061                startRecordingHistory(mSecRealtime, mSecUptime, reset);
9062            }
9063            addHistoryRecordLocked(mSecRealtime, mSecUptime);
9064            mDischargeCurrentLevel = mDischargeUnplugLevel = level;
9065            if (screenOn) {
9066                mDischargeScreenOnUnplugLevel = level;
9067                mDischargeScreenOffUnplugLevel = 0;
9068            } else {
9069                mDischargeScreenOnUnplugLevel = 0;
9070                mDischargeScreenOffUnplugLevel = level;
9071            }
9072            mDischargeAmountScreenOn = 0;
9073            mDischargeAmountScreenOff = 0;
9074            updateTimeBasesLocked(true, !screenOn, uptime, realtime);
9075        } else {
9076            mLastChargingStateLevel = level;
9077            mOnBattery = mOnBatteryInternal = false;
9078            pullPendingStateUpdatesLocked();
9079            mHistoryCur.batteryLevel = (byte)level;
9080            mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
9081            if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
9082                    + Integer.toHexString(mHistoryCur.states));
9083            addHistoryRecordLocked(mSecRealtime, mSecUptime);
9084            mDischargeCurrentLevel = mDischargePlugLevel = level;
9085            if (level < mDischargeUnplugLevel) {
9086                mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
9087                mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
9088            }
9089            updateDischargeScreenLevelsLocked(screenOn, screenOn);
9090            updateTimeBasesLocked(false, !screenOn, uptime, realtime);
9091            mChargeStepTracker.init();
9092            mLastChargeStepLevel = level;
9093            mMaxChargeStepLevel = level;
9094            mInitStepMode = mCurStepMode;
9095            mModStepMode = 0;
9096        }
9097        if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
9098            if (mFile != null) {
9099                writeAsyncLocked();
9100            }
9101        }
9102    }
9103
9104    private void startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs,
9105            boolean reset) {
9106        mRecordingHistory = true;
9107        mHistoryCur.currentTime = System.currentTimeMillis();
9108        addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs,
9109                reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME,
9110                mHistoryCur);
9111        mHistoryCur.currentTime = 0;
9112        if (reset) {
9113            initActiveHistoryEventsLocked(elapsedRealtimeMs, uptimeMs);
9114        }
9115    }
9116
9117    private void recordCurrentTimeChangeLocked(final long currentTime, final long elapsedRealtimeMs,
9118            final long uptimeMs) {
9119        if (mRecordingHistory) {
9120            mHistoryCur.currentTime = currentTime;
9121            addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_CURRENT_TIME,
9122                    mHistoryCur);
9123            mHistoryCur.currentTime = 0;
9124        }
9125    }
9126
9127    private void recordShutdownLocked(final long elapsedRealtimeMs, final long uptimeMs) {
9128        if (mRecordingHistory) {
9129            mHistoryCur.currentTime = System.currentTimeMillis();
9130            addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_SHUTDOWN,
9131                    mHistoryCur);
9132            mHistoryCur.currentTime = 0;
9133        }
9134    }
9135
9136    private void scheduleSyncExternalStatsLocked(String reason, int updateFlags) {
9137        if (mExternalSync != null) {
9138            mExternalSync.scheduleSync(reason, updateFlags);
9139        }
9140    }
9141
9142    // This should probably be exposed in the API, though it's not critical
9143    public static final int BATTERY_PLUGGED_NONE = 0;
9144
9145    public void setBatteryStateLocked(int status, int health, int plugType, int level,
9146            int temp, int volt) {
9147        final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
9148        final long uptime = mClocks.uptimeMillis();
9149        final long elapsedRealtime = mClocks.elapsedRealtime();
9150        if (!mHaveBatteryLevel) {
9151            mHaveBatteryLevel = true;
9152            // We start out assuming that the device is plugged in (not
9153            // on battery).  If our first report is now that we are indeed
9154            // plugged in, then twiddle our state to correctly reflect that
9155            // since we won't be going through the full setOnBattery().
9156            if (onBattery == mOnBattery) {
9157                if (onBattery) {
9158                    mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
9159                } else {
9160                    mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
9161                }
9162            }
9163            // Always start out assuming charging, that will be updated later.
9164            mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
9165            mHistoryCur.batteryStatus = (byte)status;
9166            mHistoryCur.batteryLevel = (byte)level;
9167            mMaxChargeStepLevel = mMinDischargeStepLevel =
9168                    mLastChargeStepLevel = mLastDischargeStepLevel = level;
9169            mLastChargingStateLevel = level;
9170        } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) {
9171            recordDailyStatsIfNeededLocked(level >= 100 && onBattery);
9172        }
9173        int oldStatus = mHistoryCur.batteryStatus;
9174        if (onBattery) {
9175            mDischargeCurrentLevel = level;
9176            if (!mRecordingHistory) {
9177                mRecordingHistory = true;
9178                startRecordingHistory(elapsedRealtime, uptime, true);
9179            }
9180        } else if (level < 96) {
9181            if (!mRecordingHistory) {
9182                mRecordingHistory = true;
9183                startRecordingHistory(elapsedRealtime, uptime, true);
9184            }
9185        }
9186        mCurrentBatteryLevel = level;
9187        if (mDischargePlugLevel < 0) {
9188            mDischargePlugLevel = level;
9189        }
9190        if (onBattery != mOnBattery) {
9191            mHistoryCur.batteryLevel = (byte)level;
9192            mHistoryCur.batteryStatus = (byte)status;
9193            mHistoryCur.batteryHealth = (byte)health;
9194            mHistoryCur.batteryPlugType = (byte)plugType;
9195            mHistoryCur.batteryTemperature = (short)temp;
9196            mHistoryCur.batteryVoltage = (char)volt;
9197            setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level);
9198        } else {
9199            boolean changed = false;
9200            if (mHistoryCur.batteryLevel != level) {
9201                mHistoryCur.batteryLevel = (byte)level;
9202                changed = true;
9203
9204                // TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record
9205                // which will pull external stats.
9206                scheduleSyncExternalStatsLocked("battery-level", ExternalStatsSync.UPDATE_ALL);
9207            }
9208            if (mHistoryCur.batteryStatus != status) {
9209                mHistoryCur.batteryStatus = (byte)status;
9210                changed = true;
9211            }
9212            if (mHistoryCur.batteryHealth != health) {
9213                mHistoryCur.batteryHealth = (byte)health;
9214                changed = true;
9215            }
9216            if (mHistoryCur.batteryPlugType != plugType) {
9217                mHistoryCur.batteryPlugType = (byte)plugType;
9218                changed = true;
9219            }
9220            if (temp >= (mHistoryCur.batteryTemperature+10)
9221                    || temp <= (mHistoryCur.batteryTemperature-10)) {
9222                mHistoryCur.batteryTemperature = (short)temp;
9223                changed = true;
9224            }
9225            if (volt > (mHistoryCur.batteryVoltage+20)
9226                    || volt < (mHistoryCur.batteryVoltage-20)) {
9227                mHistoryCur.batteryVoltage = (char)volt;
9228                changed = true;
9229            }
9230            long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT)
9231                    | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT)
9232                    | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
9233            if (onBattery) {
9234                changed |= setChargingLocked(false);
9235                if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
9236                    mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
9237                            modeBits, elapsedRealtime);
9238                    mDailyDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
9239                            modeBits, elapsedRealtime);
9240                    mLastDischargeStepLevel = level;
9241                    mMinDischargeStepLevel = level;
9242                    mInitStepMode = mCurStepMode;
9243                    mModStepMode = 0;
9244                }
9245            } else {
9246                if (level >= 90) {
9247                    // If the battery level is at least 90%, always consider the device to be
9248                    // charging even if it happens to go down a level.
9249                    changed |= setChargingLocked(true);
9250                    mLastChargeStepLevel = level;
9251                } if (!mCharging) {
9252                    if (mLastChargeStepLevel < level) {
9253                        // We have not reporting that we are charging, but the level has now
9254                        // gone up, so consider the state to be charging.
9255                        changed |= setChargingLocked(true);
9256                        mLastChargeStepLevel = level;
9257                    }
9258                } else {
9259                    if (mLastChargeStepLevel > level) {
9260                        // We had reported that the device was charging, but here we are with
9261                        // power connected and the level going down.  Looks like the current
9262                        // power supplied isn't enough, so consider the device to now be
9263                        // discharging.
9264                        changed |= setChargingLocked(false);
9265                        mLastChargeStepLevel = level;
9266                    }
9267                }
9268                if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
9269                    mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
9270                            modeBits, elapsedRealtime);
9271                    mDailyChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
9272                            modeBits, elapsedRealtime);
9273                    mLastChargeStepLevel = level;
9274                    mMaxChargeStepLevel = level;
9275                    mInitStepMode = mCurStepMode;
9276                    mModStepMode = 0;
9277                }
9278            }
9279            if (changed) {
9280                addHistoryRecordLocked(elapsedRealtime, uptime);
9281            }
9282        }
9283        if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
9284            // We don't record history while we are plugged in and fully charged.
9285            // The next time we are unplugged, history will be cleared.
9286            mRecordingHistory = DEBUG;
9287        }
9288    }
9289
9290    public long getAwakeTimeBattery() {
9291        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
9292    }
9293
9294    public long getAwakeTimePlugged() {
9295        return (mClocks.uptimeMillis() * 1000) - getAwakeTimeBattery();
9296    }
9297
9298    @Override
9299    public long computeUptime(long curTime, int which) {
9300        switch (which) {
9301            case STATS_SINCE_CHARGED: return mUptime + (curTime-mUptimeStart);
9302            case STATS_CURRENT: return (curTime-mUptimeStart);
9303            case STATS_SINCE_UNPLUGGED: return (curTime-mOnBatteryTimeBase.getUptimeStart());
9304        }
9305        return 0;
9306    }
9307
9308    @Override
9309    public long computeRealtime(long curTime, int which) {
9310        switch (which) {
9311            case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
9312            case STATS_CURRENT: return (curTime-mRealtimeStart);
9313            case STATS_SINCE_UNPLUGGED: return (curTime-mOnBatteryTimeBase.getRealtimeStart());
9314        }
9315        return 0;
9316    }
9317
9318    @Override
9319    public long computeBatteryUptime(long curTime, int which) {
9320        return mOnBatteryTimeBase.computeUptime(curTime, which);
9321    }
9322
9323    @Override
9324    public long computeBatteryRealtime(long curTime, int which) {
9325        return mOnBatteryTimeBase.computeRealtime(curTime, which);
9326    }
9327
9328    @Override
9329    public long computeBatteryScreenOffUptime(long curTime, int which) {
9330        return mOnBatteryScreenOffTimeBase.computeUptime(curTime, which);
9331    }
9332
9333    @Override
9334    public long computeBatteryScreenOffRealtime(long curTime, int which) {
9335        return mOnBatteryScreenOffTimeBase.computeRealtime(curTime, which);
9336    }
9337
9338    private long computeTimePerLevel(long[] steps, int numSteps) {
9339        // For now we'll do a simple average across all steps.
9340        if (numSteps <= 0) {
9341            return -1;
9342        }
9343        long total = 0;
9344        for (int i=0; i<numSteps; i++) {
9345            total += steps[i] & STEP_LEVEL_TIME_MASK;
9346        }
9347        return total / numSteps;
9348        /*
9349        long[] buckets = new long[numSteps];
9350        int numBuckets = 0;
9351        int numToAverage = 4;
9352        int i = 0;
9353        while (i < numSteps) {
9354            long totalTime = 0;
9355            int num = 0;
9356            for (int j=0; j<numToAverage && (i+j)<numSteps; j++) {
9357                totalTime += steps[i+j] & STEP_LEVEL_TIME_MASK;
9358                num++;
9359            }
9360            buckets[numBuckets] = totalTime / num;
9361            numBuckets++;
9362            numToAverage *= 2;
9363            i += num;
9364        }
9365        if (numBuckets < 1) {
9366            return -1;
9367        }
9368        long averageTime = buckets[numBuckets-1];
9369        for (i=numBuckets-2; i>=0; i--) {
9370            averageTime = (averageTime + buckets[i]) / 2;
9371        }
9372        return averageTime;
9373        */
9374    }
9375
9376    @Override
9377    public long computeBatteryTimeRemaining(long curTime) {
9378        if (!mOnBattery) {
9379            return -1;
9380        }
9381        /* Simple implementation just looks at the average discharge per level across the
9382           entire sample period.
9383        int discharge = (getLowDischargeAmountSinceCharge()+getHighDischargeAmountSinceCharge())/2;
9384        if (discharge < 2) {
9385            return -1;
9386        }
9387        long duration = computeBatteryRealtime(curTime, STATS_SINCE_CHARGED);
9388        if (duration < 1000*1000) {
9389            return -1;
9390        }
9391        long usPerLevel = duration/discharge;
9392        return usPerLevel * mCurrentBatteryLevel;
9393        */
9394        if (mDischargeStepTracker.mNumStepDurations < 1) {
9395            return -1;
9396        }
9397        long msPerLevel = mDischargeStepTracker.computeTimePerLevel();
9398        if (msPerLevel <= 0) {
9399            return -1;
9400        }
9401        return (msPerLevel * mCurrentBatteryLevel) * 1000;
9402    }
9403
9404    @Override
9405    public LevelStepTracker getDischargeLevelStepTracker() {
9406        return mDischargeStepTracker;
9407    }
9408
9409    @Override
9410    public LevelStepTracker getDailyDischargeLevelStepTracker() {
9411        return mDailyDischargeStepTracker;
9412    }
9413
9414    @Override
9415    public long computeChargeTimeRemaining(long curTime) {
9416        if (mOnBattery) {
9417            // Not yet working.
9418            return -1;
9419        }
9420        /* Broken
9421        int curLevel = mCurrentBatteryLevel;
9422        int plugLevel = mDischargePlugLevel;
9423        if (plugLevel < 0 || curLevel < (plugLevel+1)) {
9424            return -1;
9425        }
9426        long duration = computeBatteryRealtime(curTime, STATS_SINCE_UNPLUGGED);
9427        if (duration < 1000*1000) {
9428            return -1;
9429        }
9430        long usPerLevel = duration/(curLevel-plugLevel);
9431        return usPerLevel * (100-curLevel);
9432        */
9433        if (mChargeStepTracker.mNumStepDurations < 1) {
9434            return -1;
9435        }
9436        long msPerLevel = mChargeStepTracker.computeTimePerLevel();
9437        if (msPerLevel <= 0) {
9438            return -1;
9439        }
9440        return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000;
9441    }
9442
9443    @Override
9444    public LevelStepTracker getChargeLevelStepTracker() {
9445        return mChargeStepTracker;
9446    }
9447
9448    @Override
9449    public LevelStepTracker getDailyChargeLevelStepTracker() {
9450        return mDailyChargeStepTracker;
9451    }
9452
9453    @Override
9454    public ArrayList<PackageChange> getDailyPackageChanges() {
9455        return mDailyPackageChanges;
9456    }
9457
9458    protected long getBatteryUptimeLocked() {
9459        return mOnBatteryTimeBase.getUptime(mClocks.uptimeMillis() * 1000);
9460    }
9461
9462    @Override
9463    public long getBatteryUptime(long curTime) {
9464        return mOnBatteryTimeBase.getUptime(curTime);
9465    }
9466
9467    @Override
9468    public long getBatteryRealtime(long curTime) {
9469        return mOnBatteryTimeBase.getRealtime(curTime);
9470    }
9471
9472    @Override
9473    public int getDischargeStartLevel() {
9474        synchronized(this) {
9475            return getDischargeStartLevelLocked();
9476        }
9477    }
9478
9479    public int getDischargeStartLevelLocked() {
9480            return mDischargeUnplugLevel;
9481    }
9482
9483    @Override
9484    public int getDischargeCurrentLevel() {
9485        synchronized(this) {
9486            return getDischargeCurrentLevelLocked();
9487        }
9488    }
9489
9490    public int getDischargeCurrentLevelLocked() {
9491        return mDischargeCurrentLevel;
9492    }
9493
9494    @Override
9495    public int getLowDischargeAmountSinceCharge() {
9496        synchronized(this) {
9497            int val = mLowDischargeAmountSinceCharge;
9498            if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
9499                val += mDischargeUnplugLevel-mDischargeCurrentLevel-1;
9500            }
9501            return val;
9502        }
9503    }
9504
9505    @Override
9506    public int getHighDischargeAmountSinceCharge() {
9507        synchronized(this) {
9508            int val = mHighDischargeAmountSinceCharge;
9509            if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
9510                val += mDischargeUnplugLevel-mDischargeCurrentLevel;
9511            }
9512            return val;
9513        }
9514    }
9515
9516    @Override
9517    public int getDischargeAmount(int which) {
9518        int dischargeAmount = which == STATS_SINCE_CHARGED
9519                ? getHighDischargeAmountSinceCharge()
9520                : (getDischargeStartLevel() - getDischargeCurrentLevel());
9521        if (dischargeAmount < 0) {
9522            dischargeAmount = 0;
9523        }
9524        return dischargeAmount;
9525    }
9526
9527    public int getDischargeAmountScreenOn() {
9528        synchronized(this) {
9529            int val = mDischargeAmountScreenOn;
9530            if (mOnBattery && mScreenState == Display.STATE_ON
9531                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
9532                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
9533            }
9534            return val;
9535        }
9536    }
9537
9538    public int getDischargeAmountScreenOnSinceCharge() {
9539        synchronized(this) {
9540            int val = mDischargeAmountScreenOnSinceCharge;
9541            if (mOnBattery && mScreenState == Display.STATE_ON
9542                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
9543                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
9544            }
9545            return val;
9546        }
9547    }
9548
9549    public int getDischargeAmountScreenOff() {
9550        synchronized(this) {
9551            int val = mDischargeAmountScreenOff;
9552            if (mOnBattery && mScreenState != Display.STATE_ON
9553                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
9554                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
9555            }
9556            return val;
9557        }
9558    }
9559
9560    public int getDischargeAmountScreenOffSinceCharge() {
9561        synchronized(this) {
9562            int val = mDischargeAmountScreenOffSinceCharge;
9563            if (mOnBattery && mScreenState != Display.STATE_ON
9564                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
9565                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
9566            }
9567            return val;
9568        }
9569    }
9570
9571    /**
9572     * Retrieve the statistics object for a particular uid, creating if needed.
9573     */
9574    public Uid getUidStatsLocked(int uid) {
9575        Uid u = mUidStats.get(uid);
9576        if (u == null) {
9577            u = new Uid(this, uid);
9578            mUidStats.put(uid, u);
9579        }
9580        return u;
9581    }
9582
9583    /**
9584     * Remove the statistics object for a particular uid.
9585     */
9586    public void removeUidStatsLocked(int uid) {
9587        mKernelUidCpuTimeReader.removeUid(uid);
9588        mUidStats.remove(uid);
9589    }
9590
9591    /**
9592     * Retrieve the statistics object for a particular process, creating
9593     * if needed.
9594     */
9595    public Uid.Proc getProcessStatsLocked(int uid, String name) {
9596        uid = mapUid(uid);
9597        Uid u = getUidStatsLocked(uid);
9598        return u.getProcessStatsLocked(name);
9599    }
9600
9601    /**
9602     * Retrieve the statistics object for a particular process, creating
9603     * if needed.
9604     */
9605    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
9606        uid = mapUid(uid);
9607        Uid u = getUidStatsLocked(uid);
9608        return u.getPackageStatsLocked(pkg);
9609    }
9610
9611    /**
9612     * Retrieve the statistics object for a particular service, creating
9613     * if needed.
9614     */
9615    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
9616        uid = mapUid(uid);
9617        Uid u = getUidStatsLocked(uid);
9618        return u.getServiceStatsLocked(pkg, name);
9619    }
9620
9621    public void shutdownLocked() {
9622        recordShutdownLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
9623        writeSyncLocked();
9624        mShuttingDown = true;
9625    }
9626
9627    Parcel mPendingWrite = null;
9628    final ReentrantLock mWriteLock = new ReentrantLock();
9629
9630    public void writeAsyncLocked() {
9631        writeLocked(false);
9632    }
9633
9634    public void writeSyncLocked() {
9635        writeLocked(true);
9636    }
9637
9638    void writeLocked(boolean sync) {
9639        if (mFile == null) {
9640            Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
9641            return;
9642        }
9643
9644        if (mShuttingDown) {
9645            return;
9646        }
9647
9648        Parcel out = Parcel.obtain();
9649        writeSummaryToParcel(out, true);
9650        mLastWriteTime = mClocks.elapsedRealtime();
9651
9652        if (mPendingWrite != null) {
9653            mPendingWrite.recycle();
9654        }
9655        mPendingWrite = out;
9656
9657        if (sync) {
9658            commitPendingDataToDisk();
9659        } else {
9660            BackgroundThread.getHandler().post(new Runnable() {
9661                @Override public void run() {
9662                    commitPendingDataToDisk();
9663                }
9664            });
9665        }
9666    }
9667
9668    public void commitPendingDataToDisk() {
9669        final Parcel next;
9670        synchronized (this) {
9671            next = mPendingWrite;
9672            mPendingWrite = null;
9673            if (next == null) {
9674                return;
9675            }
9676
9677            mWriteLock.lock();
9678        }
9679
9680        try {
9681            FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
9682            stream.write(next.marshall());
9683            stream.flush();
9684            FileUtils.sync(stream);
9685            stream.close();
9686            mFile.commit();
9687        } catch (IOException e) {
9688            Slog.w("BatteryStats", "Error writing battery statistics", e);
9689            mFile.rollback();
9690        } finally {
9691            next.recycle();
9692            mWriteLock.unlock();
9693        }
9694    }
9695
9696    public void readLocked() {
9697        if (mDailyFile != null) {
9698            readDailyStatsLocked();
9699        }
9700
9701        if (mFile == null) {
9702            Slog.w("BatteryStats", "readLocked: no file associated with this instance");
9703            return;
9704        }
9705
9706        mUidStats.clear();
9707
9708        try {
9709            File file = mFile.chooseForRead();
9710            if (!file.exists()) {
9711                return;
9712            }
9713            FileInputStream stream = new FileInputStream(file);
9714
9715            byte[] raw = BatteryStatsHelper.readFully(stream);
9716            Parcel in = Parcel.obtain();
9717            in.unmarshall(raw, 0, raw.length);
9718            in.setDataPosition(0);
9719            stream.close();
9720
9721            readSummaryFromParcel(in);
9722        } catch(Exception e) {
9723            Slog.e("BatteryStats", "Error reading battery statistics", e);
9724            resetAllStatsLocked();
9725        }
9726
9727        mEndPlatformVersion = Build.ID;
9728
9729        if (mHistoryBuffer.dataPosition() > 0) {
9730            mRecordingHistory = true;
9731            final long elapsedRealtime = mClocks.elapsedRealtime();
9732            final long uptime = mClocks.uptimeMillis();
9733            if (USE_OLD_HISTORY) {
9734                addHistoryRecordLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
9735            }
9736            addHistoryBufferLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
9737            startRecordingHistory(elapsedRealtime, uptime, false);
9738        }
9739
9740        recordDailyStatsIfNeededLocked(false);
9741    }
9742
9743    public int describeContents() {
9744        return 0;
9745    }
9746
9747    void readHistory(Parcel in, boolean andOldHistory) throws ParcelFormatException {
9748        final long historyBaseTime = in.readLong();
9749
9750        mHistoryBuffer.setDataSize(0);
9751        mHistoryBuffer.setDataPosition(0);
9752        mHistoryTagPool.clear();
9753        mNextHistoryTagIdx = 0;
9754        mNumHistoryTagChars = 0;
9755
9756        int numTags = in.readInt();
9757        for (int i=0; i<numTags; i++) {
9758            int idx = in.readInt();
9759            String str = in.readString();
9760            if (str == null) {
9761                throw new ParcelFormatException("null history tag string");
9762            }
9763            int uid = in.readInt();
9764            HistoryTag tag = new HistoryTag();
9765            tag.string = str;
9766            tag.uid = uid;
9767            tag.poolIdx = idx;
9768            mHistoryTagPool.put(tag, idx);
9769            if (idx >= mNextHistoryTagIdx) {
9770                mNextHistoryTagIdx = idx+1;
9771            }
9772            mNumHistoryTagChars += tag.string.length() + 1;
9773        }
9774
9775        int bufSize = in.readInt();
9776        int curPos = in.dataPosition();
9777        if (bufSize >= (MAX_MAX_HISTORY_BUFFER*3)) {
9778            throw new ParcelFormatException("File corrupt: history data buffer too large " +
9779                    bufSize);
9780        } else if ((bufSize&~3) != bufSize) {
9781            throw new ParcelFormatException("File corrupt: history data buffer not aligned " +
9782                    bufSize);
9783        } else {
9784            if (DEBUG_HISTORY) Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
9785                    + " bytes at " + curPos);
9786            mHistoryBuffer.appendFrom(in, curPos, bufSize);
9787            in.setDataPosition(curPos + bufSize);
9788        }
9789
9790        if (andOldHistory) {
9791            readOldHistory(in);
9792        }
9793
9794        if (DEBUG_HISTORY) {
9795            StringBuilder sb = new StringBuilder(128);
9796            sb.append("****************** OLD mHistoryBaseTime: ");
9797            TimeUtils.formatDuration(mHistoryBaseTime, sb);
9798            Slog.i(TAG, sb.toString());
9799        }
9800        mHistoryBaseTime = historyBaseTime;
9801        if (DEBUG_HISTORY) {
9802            StringBuilder sb = new StringBuilder(128);
9803            sb.append("****************** NEW mHistoryBaseTime: ");
9804            TimeUtils.formatDuration(mHistoryBaseTime, sb);
9805            Slog.i(TAG, sb.toString());
9806        }
9807
9808        // We are just arbitrarily going to insert 1 minute from the sample of
9809        // the last run until samples in this run.
9810        if (mHistoryBaseTime > 0) {
9811            long oldnow = mClocks.elapsedRealtime();
9812            mHistoryBaseTime = mHistoryBaseTime - oldnow + 1;
9813            if (DEBUG_HISTORY) {
9814                StringBuilder sb = new StringBuilder(128);
9815                sb.append("****************** ADJUSTED mHistoryBaseTime: ");
9816                TimeUtils.formatDuration(mHistoryBaseTime, sb);
9817                Slog.i(TAG, sb.toString());
9818            }
9819        }
9820    }
9821
9822    void readOldHistory(Parcel in) {
9823        if (!USE_OLD_HISTORY) {
9824            return;
9825        }
9826        mHistory = mHistoryEnd = mHistoryCache = null;
9827        long time;
9828        while (in.dataAvail() > 0 && (time=in.readLong()) >= 0) {
9829            HistoryItem rec = new HistoryItem(time, in);
9830            addHistoryRecordLocked(rec);
9831        }
9832    }
9833
9834    void writeHistory(Parcel out, boolean inclData, boolean andOldHistory) {
9835        if (DEBUG_HISTORY) {
9836            StringBuilder sb = new StringBuilder(128);
9837            sb.append("****************** WRITING mHistoryBaseTime: ");
9838            TimeUtils.formatDuration(mHistoryBaseTime, sb);
9839            sb.append(" mLastHistoryElapsedRealtime: ");
9840            TimeUtils.formatDuration(mLastHistoryElapsedRealtime, sb);
9841            Slog.i(TAG, sb.toString());
9842        }
9843        out.writeLong(mHistoryBaseTime + mLastHistoryElapsedRealtime);
9844        if (!inclData) {
9845            out.writeInt(0);
9846            out.writeInt(0);
9847            return;
9848        }
9849        out.writeInt(mHistoryTagPool.size());
9850        for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
9851            HistoryTag tag = ent.getKey();
9852            out.writeInt(ent.getValue());
9853            out.writeString(tag.string);
9854            out.writeInt(tag.uid);
9855        }
9856        out.writeInt(mHistoryBuffer.dataSize());
9857        if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
9858                + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
9859        out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
9860
9861        if (andOldHistory) {
9862            writeOldHistory(out);
9863        }
9864    }
9865
9866    void writeOldHistory(Parcel out) {
9867        if (!USE_OLD_HISTORY) {
9868            return;
9869        }
9870        HistoryItem rec = mHistory;
9871        while (rec != null) {
9872            if (rec.time >= 0) rec.writeToParcel(out, 0);
9873            rec = rec.next;
9874        }
9875        out.writeLong(-1);
9876    }
9877
9878    public void readSummaryFromParcel(Parcel in) throws ParcelFormatException {
9879        final int version = in.readInt();
9880        if (version != VERSION) {
9881            Slog.w("BatteryStats", "readFromParcel: version got " + version
9882                + ", expected " + VERSION + "; erasing old stats");
9883            return;
9884        }
9885
9886        readHistory(in, true);
9887
9888        mStartCount = in.readInt();
9889        mUptime = in.readLong();
9890        mRealtime = in.readLong();
9891        mStartClockTime = in.readLong();
9892        mStartPlatformVersion = in.readString();
9893        mEndPlatformVersion = in.readString();
9894        mOnBatteryTimeBase.readSummaryFromParcel(in);
9895        mOnBatteryScreenOffTimeBase.readSummaryFromParcel(in);
9896        mDischargeUnplugLevel = in.readInt();
9897        mDischargePlugLevel = in.readInt();
9898        mDischargeCurrentLevel = in.readInt();
9899        mCurrentBatteryLevel = in.readInt();
9900        mLowDischargeAmountSinceCharge = in.readInt();
9901        mHighDischargeAmountSinceCharge = in.readInt();
9902        mDischargeAmountScreenOnSinceCharge = in.readInt();
9903        mDischargeAmountScreenOffSinceCharge = in.readInt();
9904        mDischargeStepTracker.readFromParcel(in);
9905        mChargeStepTracker.readFromParcel(in);
9906        mDailyDischargeStepTracker.readFromParcel(in);
9907        mDailyChargeStepTracker.readFromParcel(in);
9908        int NPKG = in.readInt();
9909        if (NPKG > 0) {
9910            mDailyPackageChanges = new ArrayList<>(NPKG);
9911            while (NPKG > 0) {
9912                NPKG--;
9913                PackageChange pc = new PackageChange();
9914                pc.mPackageName = in.readString();
9915                pc.mUpdate = in.readInt() != 0;
9916                pc.mVersionCode = in.readInt();
9917                mDailyPackageChanges.add(pc);
9918            }
9919        } else {
9920            mDailyPackageChanges = null;
9921        }
9922        mDailyStartTime = in.readLong();
9923        mNextMinDailyDeadline = in.readLong();
9924        mNextMaxDailyDeadline = in.readLong();
9925
9926        mStartCount++;
9927
9928        mScreenState = Display.STATE_UNKNOWN;
9929        mScreenOnTimer.readSummaryFromParcelLocked(in);
9930        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
9931            mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
9932        }
9933        mInteractive = false;
9934        mInteractiveTimer.readSummaryFromParcelLocked(in);
9935        mPhoneOn = false;
9936        mPowerSaveModeEnabledTimer.readSummaryFromParcelLocked(in);
9937        mLongestLightIdleTime = in.readLong();
9938        mLongestFullIdleTime = in.readLong();
9939        mDeviceIdleModeLightTimer.readSummaryFromParcelLocked(in);
9940        mDeviceIdleModeFullTimer.readSummaryFromParcelLocked(in);
9941        mDeviceLightIdlingTimer.readSummaryFromParcelLocked(in);
9942        mDeviceIdlingTimer.readSummaryFromParcelLocked(in);
9943        mPhoneOnTimer.readSummaryFromParcelLocked(in);
9944        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
9945            mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
9946        }
9947        mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
9948        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
9949            mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
9950        }
9951        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
9952            mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
9953            mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
9954        }
9955        mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
9956        mMobileRadioActiveTimer.readSummaryFromParcelLocked(in);
9957        mMobileRadioActivePerAppTimer.readSummaryFromParcelLocked(in);
9958        mMobileRadioActiveAdjustedTime.readSummaryFromParcelLocked(in);
9959        mMobileRadioActiveUnknownTime.readSummaryFromParcelLocked(in);
9960        mMobileRadioActiveUnknownCount.readSummaryFromParcelLocked(in);
9961        mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
9962        mWifiOn = false;
9963        mWifiOnTimer.readSummaryFromParcelLocked(in);
9964        mGlobalWifiRunning = false;
9965        mGlobalWifiRunningTimer.readSummaryFromParcelLocked(in);
9966        for (int i=0; i<NUM_WIFI_STATES; i++) {
9967            mWifiStateTimer[i].readSummaryFromParcelLocked(in);
9968        }
9969        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
9970            mWifiSupplStateTimer[i].readSummaryFromParcelLocked(in);
9971        }
9972        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
9973            mWifiSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
9974        }
9975        mWifiActivity.readSummaryFromParcel(in);
9976        mBluetoothActivity.readSummaryFromParcel(in);
9977        mModemActivity.readSummaryFromParcel(in);
9978        mHasWifiReporting = in.readInt() != 0;
9979        mHasBluetoothReporting = in.readInt() != 0;
9980        mHasModemReporting = in.readInt() != 0;
9981
9982        mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt();
9983        mFlashlightOnNesting = 0;
9984        mFlashlightOnTimer.readSummaryFromParcelLocked(in);
9985        mCameraOnNesting = 0;
9986        mCameraOnTimer.readSummaryFromParcelLocked(in);
9987        mBluetoothScanNesting = 0;
9988        mBluetoothScanTimer.readSummaryFromParcelLocked(in);
9989
9990        int NKW = in.readInt();
9991        if (NKW > 10000) {
9992            throw new ParcelFormatException("File corrupt: too many kernel wake locks " + NKW);
9993        }
9994        for (int ikw = 0; ikw < NKW; ikw++) {
9995            if (in.readInt() != 0) {
9996                String kwltName = in.readString();
9997                getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
9998            }
9999        }
10000
10001        int NWR = in.readInt();
10002        if (NWR > 10000) {
10003            throw new ParcelFormatException("File corrupt: too many wakeup reasons " + NWR);
10004        }
10005        for (int iwr = 0; iwr < NWR; iwr++) {
10006            if (in.readInt() != 0) {
10007                String reasonName = in.readString();
10008                getWakeupReasonTimerLocked(reasonName).readSummaryFromParcelLocked(in);
10009            }
10010        }
10011
10012        final int NU = in.readInt();
10013        if (NU > 10000) {
10014            throw new ParcelFormatException("File corrupt: too many uids " + NU);
10015        }
10016        for (int iu = 0; iu < NU; iu++) {
10017            int uid = in.readInt();
10018            Uid u = new Uid(this, uid);
10019            mUidStats.put(uid, u);
10020
10021            u.mWifiRunning = false;
10022            if (in.readInt() != 0) {
10023                u.mWifiRunningTimer.readSummaryFromParcelLocked(in);
10024            }
10025            u.mFullWifiLockOut = false;
10026            if (in.readInt() != 0) {
10027                u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
10028            }
10029            u.mWifiScanStarted = false;
10030            if (in.readInt() != 0) {
10031                u.mWifiScanTimer.readSummaryFromParcelLocked(in);
10032            }
10033            u.mWifiBatchedScanBinStarted = Uid.NO_BATCHED_SCAN_STARTED;
10034            for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
10035                if (in.readInt() != 0) {
10036                    u.makeWifiBatchedScanBin(i, null);
10037                    u.mWifiBatchedScanTimer[i].readSummaryFromParcelLocked(in);
10038                }
10039            }
10040            u.mWifiMulticastEnabled = false;
10041            if (in.readInt() != 0) {
10042                u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
10043            }
10044            if (in.readInt() != 0) {
10045                u.createAudioTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
10046            }
10047            if (in.readInt() != 0) {
10048                u.createVideoTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
10049            }
10050            if (in.readInt() != 0) {
10051                u.createFlashlightTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
10052            }
10053            if (in.readInt() != 0) {
10054                u.createCameraTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
10055            }
10056            if (in.readInt() != 0) {
10057                u.createForegroundActivityTimerLocked().readSummaryFromParcelLocked(in);
10058            }
10059            if (in.readInt() != 0) {
10060                u.createBluetoothScanTimerLocked().readSummaryFromParcelLocked(in);
10061            }
10062            u.mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
10063            for (int i = 0; i < Uid.NUM_PROCESS_STATE; i++) {
10064                if (in.readInt() != 0) {
10065                    u.makeProcessState(i, null);
10066                    u.mProcessStateTimer[i].readSummaryFromParcelLocked(in);
10067                }
10068            }
10069            if (in.readInt() != 0) {
10070                u.createVibratorOnTimerLocked().readSummaryFromParcelLocked(in);
10071            }
10072
10073            if (in.readInt() != 0) {
10074                if (u.mUserActivityCounters == null) {
10075                    u.initUserActivityLocked();
10076                }
10077                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
10078                    u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
10079                }
10080            }
10081
10082            if (in.readInt() != 0) {
10083                if (u.mNetworkByteActivityCounters == null) {
10084                    u.initNetworkActivityLocked();
10085                }
10086                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
10087                    u.mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
10088                    u.mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
10089                }
10090                u.mMobileRadioActiveTime.readSummaryFromParcelLocked(in);
10091                u.mMobileRadioActiveCount.readSummaryFromParcelLocked(in);
10092            }
10093
10094            u.mUserCpuTime.readSummaryFromParcelLocked(in);
10095            u.mSystemCpuTime.readSummaryFromParcelLocked(in);
10096            u.mCpuPower.readSummaryFromParcelLocked(in);
10097
10098            if (in.readInt() != 0) {
10099                final int numClusters = in.readInt();
10100                if (mPowerProfile != null && mPowerProfile.getNumCpuClusters() != numClusters) {
10101                    throw new ParcelFormatException("Incompatible cpu cluster arrangement");
10102                }
10103
10104                u.mCpuClusterSpeed = new LongSamplingCounter[numClusters][];
10105                for (int cluster = 0; cluster < numClusters; cluster++) {
10106                    if (in.readInt() != 0) {
10107                        final int NSB = in.readInt();
10108                        if (mPowerProfile != null &&
10109                                mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != NSB) {
10110                            throw new ParcelFormatException("File corrupt: too many speed bins " +
10111                                    NSB);
10112                        }
10113
10114                        u.mCpuClusterSpeed[cluster] = new LongSamplingCounter[NSB];
10115                        for (int speed = 0; speed < NSB; speed++) {
10116                            if (in.readInt() != 0) {
10117                                u.mCpuClusterSpeed[cluster][speed] = new LongSamplingCounter(
10118                                        mOnBatteryTimeBase);
10119                                u.mCpuClusterSpeed[cluster][speed].readSummaryFromParcelLocked(in);
10120                            }
10121                        }
10122                    } else {
10123                        u.mCpuClusterSpeed[cluster] = null;
10124                    }
10125                }
10126            } else {
10127                u.mCpuClusterSpeed = null;
10128            }
10129
10130            int NW = in.readInt();
10131            if (NW > 100) {
10132                throw new ParcelFormatException("File corrupt: too many wake locks " + NW);
10133            }
10134            for (int iw = 0; iw < NW; iw++) {
10135                String wlName = in.readString();
10136                u.readWakeSummaryFromParcelLocked(wlName, in);
10137            }
10138
10139            int NS = in.readInt();
10140            if (NS > 100) {
10141                throw new ParcelFormatException("File corrupt: too many syncs " + NS);
10142            }
10143            for (int is = 0; is < NS; is++) {
10144                String name = in.readString();
10145                u.readSyncSummaryFromParcelLocked(name, in);
10146            }
10147
10148            int NJ = in.readInt();
10149            if (NJ > 100) {
10150                throw new ParcelFormatException("File corrupt: too many job timers " + NJ);
10151            }
10152            for (int ij = 0; ij < NJ; ij++) {
10153                String name = in.readString();
10154                u.readJobSummaryFromParcelLocked(name, in);
10155            }
10156
10157            int NP = in.readInt();
10158            if (NP > 1000) {
10159                throw new ParcelFormatException("File corrupt: too many sensors " + NP);
10160            }
10161            for (int is = 0; is < NP; is++) {
10162                int seNumber = in.readInt();
10163                if (in.readInt() != 0) {
10164                    u.getSensorTimerLocked(seNumber, true)
10165                            .readSummaryFromParcelLocked(in);
10166                }
10167            }
10168
10169            NP = in.readInt();
10170            if (NP > 1000) {
10171                throw new ParcelFormatException("File corrupt: too many processes " + NP);
10172            }
10173            for (int ip = 0; ip < NP; ip++) {
10174                String procName = in.readString();
10175                Uid.Proc p = u.getProcessStatsLocked(procName);
10176                p.mUserTime = p.mLoadedUserTime = in.readLong();
10177                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
10178                p.mForegroundTime = p.mLoadedForegroundTime = in.readLong();
10179                p.mStarts = p.mLoadedStarts = in.readInt();
10180                p.mNumCrashes = p.mLoadedNumCrashes = in.readInt();
10181                p.mNumAnrs = p.mLoadedNumAnrs = in.readInt();
10182                p.readExcessivePowerFromParcelLocked(in);
10183            }
10184
10185            NP = in.readInt();
10186            if (NP > 10000) {
10187                throw new ParcelFormatException("File corrupt: too many packages " + NP);
10188            }
10189            for (int ip = 0; ip < NP; ip++) {
10190                String pkgName = in.readString();
10191                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
10192                final int NWA = in.readInt();
10193                if (NWA > 1000) {
10194                    throw new ParcelFormatException("File corrupt: too many wakeup alarms " + NWA);
10195                }
10196                p.mWakeupAlarms.clear();
10197                for (int iwa=0; iwa<NWA; iwa++) {
10198                    String tag = in.readString();
10199                    Counter c = new Counter(mOnBatteryTimeBase);
10200                    c.readSummaryFromParcelLocked(in);
10201                    p.mWakeupAlarms.put(tag, c);
10202                }
10203                NS = in.readInt();
10204                if (NS > 1000) {
10205                    throw new ParcelFormatException("File corrupt: too many services " + NS);
10206                }
10207                for (int is = 0; is < NS; is++) {
10208                    String servName = in.readString();
10209                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
10210                    s.mStartTime = s.mLoadedStartTime = in.readLong();
10211                    s.mStarts = s.mLoadedStarts = in.readInt();
10212                    s.mLaunches = s.mLoadedLaunches = in.readInt();
10213                }
10214            }
10215        }
10216    }
10217
10218    /**
10219     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
10220     * disk.  This format does not allow a lossless round-trip.
10221     *
10222     * @param out the Parcel to be written to.
10223     */
10224    public void writeSummaryToParcel(Parcel out, boolean inclHistory) {
10225        pullPendingStateUpdatesLocked();
10226
10227        // Pull the clock time.  This may update the time and make a new history entry
10228        // if we had originally pulled a time before the RTC was set.
10229        long startClockTime = getStartClockTime();
10230
10231        final long NOW_SYS = mClocks.uptimeMillis() * 1000;
10232        final long NOWREAL_SYS = mClocks.elapsedRealtime() * 1000;
10233
10234        out.writeInt(VERSION);
10235
10236        writeHistory(out, inclHistory, true);
10237
10238        out.writeInt(mStartCount);
10239        out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
10240        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
10241        out.writeLong(startClockTime);
10242        out.writeString(mStartPlatformVersion);
10243        out.writeString(mEndPlatformVersion);
10244        mOnBatteryTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
10245        mOnBatteryScreenOffTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
10246        out.writeInt(mDischargeUnplugLevel);
10247        out.writeInt(mDischargePlugLevel);
10248        out.writeInt(mDischargeCurrentLevel);
10249        out.writeInt(mCurrentBatteryLevel);
10250        out.writeInt(getLowDischargeAmountSinceCharge());
10251        out.writeInt(getHighDischargeAmountSinceCharge());
10252        out.writeInt(getDischargeAmountScreenOnSinceCharge());
10253        out.writeInt(getDischargeAmountScreenOffSinceCharge());
10254        mDischargeStepTracker.writeToParcel(out);
10255        mChargeStepTracker.writeToParcel(out);
10256        mDailyDischargeStepTracker.writeToParcel(out);
10257        mDailyChargeStepTracker.writeToParcel(out);
10258        if (mDailyPackageChanges != null) {
10259            final int NPKG = mDailyPackageChanges.size();
10260            out.writeInt(NPKG);
10261            for (int i=0; i<NPKG; i++) {
10262                PackageChange pc = mDailyPackageChanges.get(i);
10263                out.writeString(pc.mPackageName);
10264                out.writeInt(pc.mUpdate ? 1 : 0);
10265                out.writeInt(pc.mVersionCode);
10266            }
10267        } else {
10268            out.writeInt(0);
10269        }
10270        out.writeLong(mDailyStartTime);
10271        out.writeLong(mNextMinDailyDeadline);
10272        out.writeLong(mNextMaxDailyDeadline);
10273
10274        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10275        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
10276            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10277        }
10278        mInteractiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10279        mPowerSaveModeEnabledTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10280        out.writeLong(mLongestLightIdleTime);
10281        out.writeLong(mLongestFullIdleTime);
10282        mDeviceIdleModeLightTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10283        mDeviceIdleModeFullTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10284        mDeviceLightIdlingTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10285        mDeviceIdlingTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10286        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10287        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
10288            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10289        }
10290        mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10291        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
10292            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10293        }
10294        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
10295            mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
10296            mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
10297        }
10298        mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10299        mMobileRadioActivePerAppTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10300        mMobileRadioActiveAdjustedTime.writeSummaryFromParcelLocked(out);
10301        mMobileRadioActiveUnknownTime.writeSummaryFromParcelLocked(out);
10302        mMobileRadioActiveUnknownCount.writeSummaryFromParcelLocked(out);
10303        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10304        mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10305        for (int i=0; i<NUM_WIFI_STATES; i++) {
10306            mWifiStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10307        }
10308        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
10309            mWifiSupplStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10310        }
10311        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
10312            mWifiSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10313        }
10314        mWifiActivity.writeSummaryToParcel(out);
10315        mBluetoothActivity.writeSummaryToParcel(out);
10316        mModemActivity.writeSummaryToParcel(out);
10317        out.writeInt(mHasWifiReporting ? 1 : 0);
10318        out.writeInt(mHasBluetoothReporting ? 1 : 0);
10319        out.writeInt(mHasModemReporting ? 1 : 0);
10320
10321        out.writeInt(mNumConnectivityChange);
10322        mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10323        mCameraOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10324        mBluetoothScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10325
10326        out.writeInt(mKernelWakelockStats.size());
10327        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
10328            Timer kwlt = ent.getValue();
10329            if (kwlt != null) {
10330                out.writeInt(1);
10331                out.writeString(ent.getKey());
10332                kwlt.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10333            } else {
10334                out.writeInt(0);
10335            }
10336        }
10337
10338        out.writeInt(mWakeupReasonStats.size());
10339        for (Map.Entry<String, SamplingTimer> ent : mWakeupReasonStats.entrySet()) {
10340            SamplingTimer timer = ent.getValue();
10341            if (timer != null) {
10342                out.writeInt(1);
10343                out.writeString(ent.getKey());
10344                timer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10345            } else {
10346                out.writeInt(0);
10347            }
10348        }
10349
10350        final int NU = mUidStats.size();
10351        out.writeInt(NU);
10352        for (int iu = 0; iu < NU; iu++) {
10353            out.writeInt(mUidStats.keyAt(iu));
10354            Uid u = mUidStats.valueAt(iu);
10355
10356            if (u.mWifiRunningTimer != null) {
10357                out.writeInt(1);
10358                u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10359            } else {
10360                out.writeInt(0);
10361            }
10362            if (u.mFullWifiLockTimer != null) {
10363                out.writeInt(1);
10364                u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10365            } else {
10366                out.writeInt(0);
10367            }
10368            if (u.mWifiScanTimer != null) {
10369                out.writeInt(1);
10370                u.mWifiScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10371            } else {
10372                out.writeInt(0);
10373            }
10374            for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
10375                if (u.mWifiBatchedScanTimer[i] != null) {
10376                    out.writeInt(1);
10377                    u.mWifiBatchedScanTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10378                } else {
10379                    out.writeInt(0);
10380                }
10381            }
10382            if (u.mWifiMulticastTimer != null) {
10383                out.writeInt(1);
10384                u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10385            } else {
10386                out.writeInt(0);
10387            }
10388            if (u.mAudioTurnedOnTimer != null) {
10389                out.writeInt(1);
10390                u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10391            } else {
10392                out.writeInt(0);
10393            }
10394            if (u.mVideoTurnedOnTimer != null) {
10395                out.writeInt(1);
10396                u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10397            } else {
10398                out.writeInt(0);
10399            }
10400            if (u.mFlashlightTurnedOnTimer != null) {
10401                out.writeInt(1);
10402                u.mFlashlightTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10403            } else {
10404                out.writeInt(0);
10405            }
10406            if (u.mCameraTurnedOnTimer != null) {
10407                out.writeInt(1);
10408                u.mCameraTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10409            } else {
10410                out.writeInt(0);
10411            }
10412            if (u.mForegroundActivityTimer != null) {
10413                out.writeInt(1);
10414                u.mForegroundActivityTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10415            } else {
10416                out.writeInt(0);
10417            }
10418            if (u.mBluetoothScanTimer != null) {
10419                out.writeInt(1);
10420                u.mBluetoothScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10421            } else {
10422                out.writeInt(0);
10423            }
10424            for (int i = 0; i < Uid.NUM_PROCESS_STATE; i++) {
10425                if (u.mProcessStateTimer[i] != null) {
10426                    out.writeInt(1);
10427                    u.mProcessStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10428                } else {
10429                    out.writeInt(0);
10430                }
10431            }
10432            if (u.mVibratorOnTimer != null) {
10433                out.writeInt(1);
10434                u.mVibratorOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10435            } else {
10436                out.writeInt(0);
10437            }
10438
10439            if (u.mUserActivityCounters == null) {
10440                out.writeInt(0);
10441            } else {
10442                out.writeInt(1);
10443                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
10444                    u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
10445                }
10446            }
10447
10448            if (u.mNetworkByteActivityCounters == null) {
10449                out.writeInt(0);
10450            } else {
10451                out.writeInt(1);
10452                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
10453                    u.mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
10454                    u.mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
10455                }
10456                u.mMobileRadioActiveTime.writeSummaryFromParcelLocked(out);
10457                u.mMobileRadioActiveCount.writeSummaryFromParcelLocked(out);
10458            }
10459
10460            u.mUserCpuTime.writeSummaryFromParcelLocked(out);
10461            u.mSystemCpuTime.writeSummaryFromParcelLocked(out);
10462            u.mCpuPower.writeSummaryFromParcelLocked(out);
10463
10464            if (u.mCpuClusterSpeed != null) {
10465                out.writeInt(1);
10466                out.writeInt(u.mCpuClusterSpeed.length);
10467                for (LongSamplingCounter[] cpuSpeeds : u.mCpuClusterSpeed) {
10468                    if (cpuSpeeds != null) {
10469                        out.writeInt(1);
10470                        out.writeInt(cpuSpeeds.length);
10471                        for (LongSamplingCounter c : cpuSpeeds) {
10472                            if (c != null) {
10473                                out.writeInt(1);
10474                                c.writeSummaryFromParcelLocked(out);
10475                            } else {
10476                                out.writeInt(0);
10477                            }
10478                        }
10479                    } else {
10480                        out.writeInt(0);
10481                    }
10482                }
10483            } else {
10484                out.writeInt(0);
10485            }
10486
10487            final ArrayMap<String, Uid.Wakelock> wakeStats = u.mWakelockStats.getMap();
10488            int NW = wakeStats.size();
10489            out.writeInt(NW);
10490            for (int iw=0; iw<NW; iw++) {
10491                out.writeString(wakeStats.keyAt(iw));
10492                Uid.Wakelock wl = wakeStats.valueAt(iw);
10493                if (wl.mTimerFull != null) {
10494                    out.writeInt(1);
10495                    wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10496                } else {
10497                    out.writeInt(0);
10498                }
10499                if (wl.mTimerPartial != null) {
10500                    out.writeInt(1);
10501                    wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10502                } else {
10503                    out.writeInt(0);
10504                }
10505                if (wl.mTimerWindow != null) {
10506                    out.writeInt(1);
10507                    wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10508                } else {
10509                    out.writeInt(0);
10510                }
10511                if (wl.mTimerDraw != null) {
10512                    out.writeInt(1);
10513                    wl.mTimerDraw.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10514                } else {
10515                    out.writeInt(0);
10516                }
10517            }
10518
10519            final ArrayMap<String, StopwatchTimer> syncStats = u.mSyncStats.getMap();
10520            int NS = syncStats.size();
10521            out.writeInt(NS);
10522            for (int is=0; is<NS; is++) {
10523                out.writeString(syncStats.keyAt(is));
10524                syncStats.valueAt(is).writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10525            }
10526
10527            final ArrayMap<String, StopwatchTimer> jobStats = u.mJobStats.getMap();
10528            int NJ = jobStats.size();
10529            out.writeInt(NJ);
10530            for (int ij=0; ij<NJ; ij++) {
10531                out.writeString(jobStats.keyAt(ij));
10532                jobStats.valueAt(ij).writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10533            }
10534
10535            int NSE = u.mSensorStats.size();
10536            out.writeInt(NSE);
10537            for (int ise=0; ise<NSE; ise++) {
10538                out.writeInt(u.mSensorStats.keyAt(ise));
10539                Uid.Sensor se = u.mSensorStats.valueAt(ise);
10540                if (se.mTimer != null) {
10541                    out.writeInt(1);
10542                    se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10543                } else {
10544                    out.writeInt(0);
10545                }
10546            }
10547
10548            int NP = u.mProcessStats.size();
10549            out.writeInt(NP);
10550            for (int ip=0; ip<NP; ip++) {
10551                out.writeString(u.mProcessStats.keyAt(ip));
10552                Uid.Proc ps = u.mProcessStats.valueAt(ip);
10553                out.writeLong(ps.mUserTime);
10554                out.writeLong(ps.mSystemTime);
10555                out.writeLong(ps.mForegroundTime);
10556                out.writeInt(ps.mStarts);
10557                out.writeInt(ps.mNumCrashes);
10558                out.writeInt(ps.mNumAnrs);
10559                ps.writeExcessivePowerToParcelLocked(out);
10560            }
10561
10562            NP = u.mPackageStats.size();
10563            out.writeInt(NP);
10564            if (NP > 0) {
10565                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
10566                    : u.mPackageStats.entrySet()) {
10567                    out.writeString(ent.getKey());
10568                    Uid.Pkg ps = ent.getValue();
10569                    final int NWA = ps.mWakeupAlarms.size();
10570                    out.writeInt(NWA);
10571                    for (int iwa=0; iwa<NWA; iwa++) {
10572                        out.writeString(ps.mWakeupAlarms.keyAt(iwa));
10573                        ps.mWakeupAlarms.valueAt(iwa).writeSummaryFromParcelLocked(out);
10574                    }
10575                    NS = ps.mServiceStats.size();
10576                    out.writeInt(NS);
10577                    for (int is=0; is<NS; is++) {
10578                        out.writeString(ps.mServiceStats.keyAt(is));
10579                        BatteryStatsImpl.Uid.Pkg.Serv ss = ps.mServiceStats.valueAt(is);
10580                        long time = ss.getStartTimeToNowLocked(
10581                                mOnBatteryTimeBase.getUptime(NOW_SYS));
10582                        out.writeLong(time);
10583                        out.writeInt(ss.mStarts);
10584                        out.writeInt(ss.mLaunches);
10585                    }
10586                }
10587            }
10588        }
10589    }
10590
10591    public void readFromParcel(Parcel in) {
10592        readFromParcelLocked(in);
10593    }
10594
10595    void readFromParcelLocked(Parcel in) {
10596        int magic = in.readInt();
10597        if (magic != MAGIC) {
10598            throw new ParcelFormatException("Bad magic number: #" + Integer.toHexString(magic));
10599        }
10600
10601        readHistory(in, false);
10602
10603        mStartCount = in.readInt();
10604        mStartClockTime = in.readLong();
10605        mStartPlatformVersion = in.readString();
10606        mEndPlatformVersion = in.readString();
10607        mUptime = in.readLong();
10608        mUptimeStart = in.readLong();
10609        mRealtime = in.readLong();
10610        mRealtimeStart = in.readLong();
10611        mOnBattery = in.readInt() != 0;
10612        mOnBatteryInternal = false; // we are no longer really running.
10613        mOnBatteryTimeBase.readFromParcel(in);
10614        mOnBatteryScreenOffTimeBase.readFromParcel(in);
10615
10616        mScreenState = Display.STATE_UNKNOWN;
10617        mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase, in);
10618        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
10619            mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
10620                    mOnBatteryTimeBase, in);
10621        }
10622        mInteractive = false;
10623        mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase, in);
10624        mPhoneOn = false;
10625        mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
10626                mOnBatteryTimeBase, in);
10627        mLongestLightIdleTime = in.readLong();
10628        mLongestFullIdleTime = in.readLong();
10629        mDeviceIdleModeLightTimer = new StopwatchTimer(mClocks, null, -14, null,
10630                mOnBatteryTimeBase, in);
10631        mDeviceIdleModeFullTimer = new StopwatchTimer(mClocks, null, -11, null,
10632                mOnBatteryTimeBase, in);
10633        mDeviceLightIdlingTimer = new StopwatchTimer(mClocks, null, -15, null,
10634                mOnBatteryTimeBase, in);
10635        mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase, in);
10636        mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase, in);
10637        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
10638            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i,
10639                    null, mOnBatteryTimeBase, in);
10640        }
10641        mPhoneSignalScanningTimer = new StopwatchTimer(mClocks, null, -200+1, null,
10642                mOnBatteryTimeBase, in);
10643        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
10644            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClocks, null, -300-i,
10645                    null, mOnBatteryTimeBase, in);
10646        }
10647        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
10648            mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
10649            mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
10650        }
10651        mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
10652        mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null,
10653                mOnBatteryTimeBase, in);
10654        mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
10655                mOnBatteryTimeBase, in);
10656        mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
10657        mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
10658        mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
10659        mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
10660        mWifiOn = false;
10661        mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase, in);
10662        mGlobalWifiRunning = false;
10663        mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null,
10664                mOnBatteryTimeBase, in);
10665        for (int i=0; i<NUM_WIFI_STATES; i++) {
10666            mWifiStateTimer[i] = new StopwatchTimer(mClocks, null, -600-i,
10667                    null, mOnBatteryTimeBase, in);
10668        }
10669        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
10670            mWifiSupplStateTimer[i] = new StopwatchTimer(mClocks, null, -700-i,
10671                    null, mOnBatteryTimeBase, in);
10672        }
10673        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
10674            mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i,
10675                    null, mOnBatteryTimeBase, in);
10676        }
10677
10678        mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
10679                NUM_WIFI_TX_LEVELS, in);
10680        mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
10681                NUM_BT_TX_LEVELS, in);
10682        mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
10683                ModemActivityInfo.TX_POWER_LEVELS, in);
10684        mHasWifiReporting = in.readInt() != 0;
10685        mHasBluetoothReporting = in.readInt() != 0;
10686        mHasModemReporting = in.readInt() != 0;
10687
10688        mNumConnectivityChange = in.readInt();
10689        mLoadedNumConnectivityChange = in.readInt();
10690        mUnpluggedNumConnectivityChange = in.readInt();
10691        mAudioOnNesting = 0;
10692        mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
10693        mVideoOnNesting = 0;
10694        mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
10695        mFlashlightOnNesting = 0;
10696        mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase, in);
10697        mCameraOnNesting = 0;
10698        mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase, in);
10699        mBluetoothScanNesting = 0;
10700        mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase, in);
10701        mDischargeUnplugLevel = in.readInt();
10702        mDischargePlugLevel = in.readInt();
10703        mDischargeCurrentLevel = in.readInt();
10704        mCurrentBatteryLevel = in.readInt();
10705        mLowDischargeAmountSinceCharge = in.readInt();
10706        mHighDischargeAmountSinceCharge = in.readInt();
10707        mDischargeAmountScreenOn = in.readInt();
10708        mDischargeAmountScreenOnSinceCharge = in.readInt();
10709        mDischargeAmountScreenOff = in.readInt();
10710        mDischargeAmountScreenOffSinceCharge = in.readInt();
10711        mDischargeStepTracker.readFromParcel(in);
10712        mChargeStepTracker.readFromParcel(in);
10713        mLastWriteTime = in.readLong();
10714
10715        mKernelWakelockStats.clear();
10716        int NKW = in.readInt();
10717        for (int ikw = 0; ikw < NKW; ikw++) {
10718            if (in.readInt() != 0) {
10719                String wakelockName = in.readString();
10720                SamplingTimer kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase, in);
10721                mKernelWakelockStats.put(wakelockName, kwlt);
10722            }
10723        }
10724
10725        mWakeupReasonStats.clear();
10726        int NWR = in.readInt();
10727        for (int iwr = 0; iwr < NWR; iwr++) {
10728            if (in.readInt() != 0) {
10729                String reasonName = in.readString();
10730                SamplingTimer timer = new SamplingTimer(mClocks, mOnBatteryTimeBase, in);
10731                mWakeupReasonStats.put(reasonName, timer);
10732            }
10733        }
10734
10735        mPartialTimers.clear();
10736        mFullTimers.clear();
10737        mWindowTimers.clear();
10738        mWifiRunningTimers.clear();
10739        mFullWifiLockTimers.clear();
10740        mWifiScanTimers.clear();
10741        mWifiBatchedScanTimers.clear();
10742        mWifiMulticastTimers.clear();
10743        mAudioTurnedOnTimers.clear();
10744        mVideoTurnedOnTimers.clear();
10745        mFlashlightTurnedOnTimers.clear();
10746        mCameraTurnedOnTimers.clear();
10747
10748        int numUids = in.readInt();
10749        mUidStats.clear();
10750        for (int i = 0; i < numUids; i++) {
10751            int uid = in.readInt();
10752            Uid u = new Uid(this, uid);
10753            u.readFromParcelLocked(mOnBatteryTimeBase, mOnBatteryScreenOffTimeBase, in);
10754            mUidStats.append(uid, u);
10755        }
10756    }
10757
10758    public void writeToParcel(Parcel out, int flags) {
10759        writeToParcelLocked(out, true, flags);
10760    }
10761
10762    public void writeToParcelWithoutUids(Parcel out, int flags) {
10763        writeToParcelLocked(out, false, flags);
10764    }
10765
10766    @SuppressWarnings("unused")
10767    void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
10768        // Need to update with current kernel wake lock counts.
10769        pullPendingStateUpdatesLocked();
10770
10771        // Pull the clock time.  This may update the time and make a new history entry
10772        // if we had originally pulled a time before the RTC was set.
10773        long startClockTime = getStartClockTime();
10774
10775        final long uSecUptime = mClocks.uptimeMillis() * 1000;
10776        final long uSecRealtime = mClocks.elapsedRealtime() * 1000;
10777        final long batteryRealtime = mOnBatteryTimeBase.getRealtime(uSecRealtime);
10778        final long batteryScreenOffRealtime = mOnBatteryScreenOffTimeBase.getRealtime(uSecRealtime);
10779
10780        out.writeInt(MAGIC);
10781
10782        writeHistory(out, true, false);
10783
10784        out.writeInt(mStartCount);
10785        out.writeLong(startClockTime);
10786        out.writeString(mStartPlatformVersion);
10787        out.writeString(mEndPlatformVersion);
10788        out.writeLong(mUptime);
10789        out.writeLong(mUptimeStart);
10790        out.writeLong(mRealtime);
10791        out.writeLong(mRealtimeStart);
10792        out.writeInt(mOnBattery ? 1 : 0);
10793        mOnBatteryTimeBase.writeToParcel(out, uSecUptime, uSecRealtime);
10794        mOnBatteryScreenOffTimeBase.writeToParcel(out, uSecUptime, uSecRealtime);
10795
10796        mScreenOnTimer.writeToParcel(out, uSecRealtime);
10797        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
10798            mScreenBrightnessTimer[i].writeToParcel(out, uSecRealtime);
10799        }
10800        mInteractiveTimer.writeToParcel(out, uSecRealtime);
10801        mPowerSaveModeEnabledTimer.writeToParcel(out, uSecRealtime);
10802        out.writeLong(mLongestLightIdleTime);
10803        out.writeLong(mLongestFullIdleTime);
10804        mDeviceIdleModeLightTimer.writeToParcel(out, uSecRealtime);
10805        mDeviceIdleModeFullTimer.writeToParcel(out, uSecRealtime);
10806        mDeviceLightIdlingTimer.writeToParcel(out, uSecRealtime);
10807        mDeviceIdlingTimer.writeToParcel(out, uSecRealtime);
10808        mPhoneOnTimer.writeToParcel(out, uSecRealtime);
10809        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
10810            mPhoneSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
10811        }
10812        mPhoneSignalScanningTimer.writeToParcel(out, uSecRealtime);
10813        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
10814            mPhoneDataConnectionsTimer[i].writeToParcel(out, uSecRealtime);
10815        }
10816        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
10817            mNetworkByteActivityCounters[i].writeToParcel(out);
10818            mNetworkPacketActivityCounters[i].writeToParcel(out);
10819        }
10820        mMobileRadioActiveTimer.writeToParcel(out, uSecRealtime);
10821        mMobileRadioActivePerAppTimer.writeToParcel(out, uSecRealtime);
10822        mMobileRadioActiveAdjustedTime.writeToParcel(out);
10823        mMobileRadioActiveUnknownTime.writeToParcel(out);
10824        mMobileRadioActiveUnknownCount.writeToParcel(out);
10825        mWifiOnTimer.writeToParcel(out, uSecRealtime);
10826        mGlobalWifiRunningTimer.writeToParcel(out, uSecRealtime);
10827        for (int i=0; i<NUM_WIFI_STATES; i++) {
10828            mWifiStateTimer[i].writeToParcel(out, uSecRealtime);
10829        }
10830        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
10831            mWifiSupplStateTimer[i].writeToParcel(out, uSecRealtime);
10832        }
10833        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
10834            mWifiSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
10835        }
10836        mWifiActivity.writeToParcel(out, 0);
10837        mBluetoothActivity.writeToParcel(out, 0);
10838        mModemActivity.writeToParcel(out, 0);
10839        out.writeInt(mHasWifiReporting ? 1 : 0);
10840        out.writeInt(mHasBluetoothReporting ? 1 : 0);
10841        out.writeInt(mHasModemReporting ? 1 : 0);
10842
10843        out.writeInt(mNumConnectivityChange);
10844        out.writeInt(mLoadedNumConnectivityChange);
10845        out.writeInt(mUnpluggedNumConnectivityChange);
10846        mFlashlightOnTimer.writeToParcel(out, uSecRealtime);
10847        mCameraOnTimer.writeToParcel(out, uSecRealtime);
10848        mBluetoothScanTimer.writeToParcel(out, uSecRealtime);
10849        out.writeInt(mDischargeUnplugLevel);
10850        out.writeInt(mDischargePlugLevel);
10851        out.writeInt(mDischargeCurrentLevel);
10852        out.writeInt(mCurrentBatteryLevel);
10853        out.writeInt(mLowDischargeAmountSinceCharge);
10854        out.writeInt(mHighDischargeAmountSinceCharge);
10855        out.writeInt(mDischargeAmountScreenOn);
10856        out.writeInt(mDischargeAmountScreenOnSinceCharge);
10857        out.writeInt(mDischargeAmountScreenOff);
10858        out.writeInt(mDischargeAmountScreenOffSinceCharge);
10859        mDischargeStepTracker.writeToParcel(out);
10860        mChargeStepTracker.writeToParcel(out);
10861        out.writeLong(mLastWriteTime);
10862
10863        if (inclUids) {
10864            out.writeInt(mKernelWakelockStats.size());
10865            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
10866                SamplingTimer kwlt = ent.getValue();
10867                if (kwlt != null) {
10868                    out.writeInt(1);
10869                    out.writeString(ent.getKey());
10870                    kwlt.writeToParcel(out, uSecRealtime);
10871                } else {
10872                    out.writeInt(0);
10873                }
10874            }
10875            out.writeInt(mWakeupReasonStats.size());
10876            for (Map.Entry<String, SamplingTimer> ent : mWakeupReasonStats.entrySet()) {
10877                SamplingTimer timer = ent.getValue();
10878                if (timer != null) {
10879                    out.writeInt(1);
10880                    out.writeString(ent.getKey());
10881                    timer.writeToParcel(out, uSecRealtime);
10882                } else {
10883                    out.writeInt(0);
10884                }
10885            }
10886        } else {
10887            out.writeInt(0);
10888        }
10889
10890        if (inclUids) {
10891            int size = mUidStats.size();
10892            out.writeInt(size);
10893            for (int i = 0; i < size; i++) {
10894                out.writeInt(mUidStats.keyAt(i));
10895                Uid uid = mUidStats.valueAt(i);
10896
10897                uid.writeToParcelLocked(out, uSecRealtime);
10898            }
10899        } else {
10900            out.writeInt(0);
10901        }
10902    }
10903
10904    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
10905        new Parcelable.Creator<BatteryStatsImpl>() {
10906        public BatteryStatsImpl createFromParcel(Parcel in) {
10907            return new BatteryStatsImpl(in);
10908        }
10909
10910        public BatteryStatsImpl[] newArray(int size) {
10911            return new BatteryStatsImpl[size];
10912        }
10913    };
10914
10915    public void prepareForDumpLocked() {
10916        // Need to retrieve current kernel wake lock stats before printing.
10917        pullPendingStateUpdatesLocked();
10918
10919        // Pull the clock time.  This may update the time and make a new history entry
10920        // if we had originally pulled a time before the RTC was set.
10921        getStartClockTime();
10922    }
10923
10924    public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
10925        if (DEBUG) {
10926            pw.println("mOnBatteryTimeBase:");
10927            mOnBatteryTimeBase.dump(pw, "  ");
10928            pw.println("mOnBatteryScreenOffTimeBase:");
10929            mOnBatteryScreenOffTimeBase.dump(pw, "  ");
10930            Printer pr = new PrintWriterPrinter(pw);
10931            pr.println("*** Screen timer:");
10932            mScreenOnTimer.logState(pr, "  ");
10933            for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
10934                pr.println("*** Screen brightness #" + i + ":");
10935                mScreenBrightnessTimer[i].logState(pr, "  ");
10936            }
10937            pr.println("*** Interactive timer:");
10938            mInteractiveTimer.logState(pr, "  ");
10939            pr.println("*** Power save mode timer:");
10940            mPowerSaveModeEnabledTimer.logState(pr, "  ");
10941            pr.println("*** Device idle mode light timer:");
10942            mDeviceIdleModeLightTimer.logState(pr, "  ");
10943            pr.println("*** Device idle mode full timer:");
10944            mDeviceIdleModeFullTimer.logState(pr, "  ");
10945            pr.println("*** Device light idling timer:");
10946            mDeviceLightIdlingTimer.logState(pr, "  ");
10947            pr.println("*** Device idling timer:");
10948            mDeviceIdlingTimer.logState(pr, "  ");
10949            pr.println("*** Phone timer:");
10950            mPhoneOnTimer.logState(pr, "  ");
10951            for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
10952                pr.println("*** Phone signal strength #" + i + ":");
10953                mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
10954            }
10955            pr.println("*** Signal scanning :");
10956            mPhoneSignalScanningTimer.logState(pr, "  ");
10957            for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
10958                pr.println("*** Data connection type #" + i + ":");
10959                mPhoneDataConnectionsTimer[i].logState(pr, "  ");
10960            }
10961            pr.println("*** mMobileRadioPowerState=" + mMobileRadioPowerState);
10962            pr.println("*** Mobile network active timer:");
10963            mMobileRadioActiveTimer.logState(pr, "  ");
10964            pr.println("*** Mobile network active adjusted timer:");
10965            mMobileRadioActiveAdjustedTime.logState(pr, "  ");
10966            pr.println("*** mWifiRadioPowerState=" + mWifiRadioPowerState);
10967            pr.println("*** Wifi timer:");
10968            mWifiOnTimer.logState(pr, "  ");
10969            pr.println("*** WifiRunning timer:");
10970            mGlobalWifiRunningTimer.logState(pr, "  ");
10971            for (int i=0; i<NUM_WIFI_STATES; i++) {
10972                pr.println("*** Wifi state #" + i + ":");
10973                mWifiStateTimer[i].logState(pr, "  ");
10974            }
10975            for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
10976                pr.println("*** Wifi suppl state #" + i + ":");
10977                mWifiSupplStateTimer[i].logState(pr, "  ");
10978            }
10979            for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
10980                pr.println("*** Wifi signal strength #" + i + ":");
10981                mWifiSignalStrengthsTimer[i].logState(pr, "  ");
10982            }
10983            pr.println("*** Flashlight timer:");
10984            mFlashlightOnTimer.logState(pr, "  ");
10985            pr.println("*** Camera timer:");
10986            mCameraOnTimer.logState(pr, "  ");
10987        }
10988        super.dumpLocked(context, pw, flags, reqUid, histStart);
10989    }
10990}
10991