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