BatteryStatsImpl.java revision 09c09fd345a6b4c9619885428dce9802ad7b8cd8
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                    // Skip the lookup below since there is no work to do.
8197                    continue;
8198                }
8199
8200                final Uid u = getUidStatsLocked(mapUid(entry.uid));
8201                if (entry.rxBytes != 0) {
8202                    u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
8203                            entry.rxPackets);
8204                    mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
8205                            entry.rxBytes);
8206                    mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
8207                            entry.rxPackets);
8208
8209                    rxPackets.put(u.getUid(), entry.rxPackets);
8210
8211                    // Sum the total number of packets so that the Rx Power can
8212                    // be evenly distributed amongst the apps.
8213                    totalRxPackets += entry.rxPackets;
8214                }
8215
8216                if (entry.txBytes != 0) {
8217                    u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes,
8218                            entry.txPackets);
8219                    mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
8220                            entry.txBytes);
8221                    mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
8222                            entry.txPackets);
8223
8224                    txPackets.put(u.getUid(), entry.txPackets);
8225
8226                    // Sum the total number of packets so that the Tx Power can
8227                    // be evenly distributed amongst the apps.
8228                    totalTxPackets += entry.txPackets;
8229                }
8230            }
8231        }
8232
8233        if (info != null) {
8234            mHasWifiReporting = true;
8235
8236            // Measured in mAms
8237            final long txTimeMs = info.getControllerTxTimeMillis();
8238            final long rxTimeMs = info.getControllerRxTimeMillis();
8239            final long idleTimeMs = info.getControllerIdleTimeMillis();
8240            final long totalTimeMs = txTimeMs + rxTimeMs + idleTimeMs;
8241
8242            long leftOverRxTimeMs = rxTimeMs;
8243            long leftOverTxTimeMs = txTimeMs;
8244
8245            if (DEBUG_ENERGY) {
8246                Slog.d(TAG, "------ BEGIN WiFi power blaming ------");
8247                Slog.d(TAG, "  Tx Time:    " + txTimeMs + " ms");
8248                Slog.d(TAG, "  Rx Time:    " + rxTimeMs + " ms");
8249                Slog.d(TAG, "  Idle Time:  " + idleTimeMs + " ms");
8250                Slog.d(TAG, "  Total Time: " + totalTimeMs + " ms");
8251            }
8252
8253            long totalWifiLockTimeMs = 0;
8254            long totalScanTimeMs = 0;
8255
8256            // On the first pass, collect some totals so that we can normalize power
8257            // calculations if we need to.
8258            final int uidStatsSize = mUidStats.size();
8259            for (int i = 0; i < uidStatsSize; i++) {
8260                final Uid uid = mUidStats.valueAt(i);
8261
8262                // Sum the total scan power for all apps.
8263                totalScanTimeMs += uid.mWifiScanTimer.getTimeSinceMarkLocked(
8264                        elapsedRealtimeMs * 1000) / 1000;
8265
8266                // Sum the total time holding wifi lock for all apps.
8267                totalWifiLockTimeMs += uid.mFullWifiLockTimer.getTimeSinceMarkLocked(
8268                        elapsedRealtimeMs * 1000) / 1000;
8269            }
8270
8271            if (DEBUG_ENERGY && totalScanTimeMs > rxTimeMs) {
8272                Slog.d(TAG, "  !Estimated scan time > Actual rx time (" + totalScanTimeMs + " ms > "
8273                        + rxTimeMs + " ms). Normalizing scan time.");
8274            }
8275            if (DEBUG_ENERGY && totalScanTimeMs > txTimeMs) {
8276                Slog.d(TAG, "  !Estimated scan time > Actual tx time (" + totalScanTimeMs + " ms > "
8277                        + txTimeMs + " ms). Normalizing scan time.");
8278            }
8279
8280            // Actually assign and distribute power usage to apps.
8281            for (int i = 0; i < uidStatsSize; i++) {
8282                final Uid uid = mUidStats.valueAt(i);
8283
8284                long scanTimeSinceMarkMs = uid.mWifiScanTimer.getTimeSinceMarkLocked(
8285                        elapsedRealtimeMs * 1000) / 1000;
8286                if (scanTimeSinceMarkMs > 0) {
8287                    // Set the new mark so that next time we get new data since this point.
8288                    uid.mWifiScanTimer.setMark(elapsedRealtimeMs);
8289
8290                    long scanRxTimeSinceMarkMs = scanTimeSinceMarkMs;
8291                    long scanTxTimeSinceMarkMs = scanTimeSinceMarkMs;
8292
8293                    // Our total scan time is more than the reported Tx/Rx time.
8294                    // This is possible because the cost of a scan is approximate.
8295                    // Let's normalize the result so that we evenly blame each app
8296                    // scanning.
8297                    //
8298                    // This means that we may have apps that transmitted/received packets not be
8299                    // blamed for this, but this is fine as scans are relatively more expensive.
8300                    if (totalScanTimeMs > rxTimeMs) {
8301                        scanRxTimeSinceMarkMs = (rxTimeMs * scanRxTimeSinceMarkMs) /
8302                                totalScanTimeMs;
8303                    }
8304                    if (totalScanTimeMs > txTimeMs) {
8305                        scanTxTimeSinceMarkMs = (txTimeMs * scanTxTimeSinceMarkMs) /
8306                                totalScanTimeMs;
8307                    }
8308
8309                    if (DEBUG_ENERGY) {
8310                        Slog.d(TAG, "  ScanTime for UID " + uid.getUid() + ": Rx:"
8311                                + scanRxTimeSinceMarkMs + " ms  Tx:"
8312                                + scanTxTimeSinceMarkMs + " ms)");
8313                    }
8314
8315                    ControllerActivityCounterImpl activityCounter =
8316                            uid.getOrCreateWifiControllerActivityLocked();
8317                    activityCounter.getRxTimeCounter().addCountLocked(scanRxTimeSinceMarkMs);
8318                    activityCounter.getTxTimeCounters()[0].addCountLocked(scanTxTimeSinceMarkMs);
8319                    leftOverRxTimeMs -= scanRxTimeSinceMarkMs;
8320                    leftOverTxTimeMs -= scanTxTimeSinceMarkMs;
8321                }
8322
8323                // Distribute evenly the power consumed while Idle to each app holding a WiFi
8324                // lock.
8325                final long wifiLockTimeSinceMarkMs = uid.mFullWifiLockTimer.getTimeSinceMarkLocked(
8326                        elapsedRealtimeMs * 1000) / 1000;
8327                if (wifiLockTimeSinceMarkMs > 0) {
8328                    // Set the new mark so that next time we get new data since this point.
8329                    uid.mFullWifiLockTimer.setMark(elapsedRealtimeMs);
8330
8331                    final long myIdleTimeMs = (wifiLockTimeSinceMarkMs * idleTimeMs)
8332                            / totalWifiLockTimeMs;
8333                    if (DEBUG_ENERGY) {
8334                        Slog.d(TAG, "  IdleTime for UID " + uid.getUid() + ": "
8335                                + myIdleTimeMs + " ms");
8336                    }
8337                    uid.getOrCreateWifiControllerActivityLocked().getIdleTimeCounter()
8338                            .addCountLocked(myIdleTimeMs);
8339                }
8340            }
8341
8342            if (DEBUG_ENERGY) {
8343                Slog.d(TAG, "  New RxPower: " + leftOverRxTimeMs + " ms");
8344                Slog.d(TAG, "  New TxPower: " + leftOverTxTimeMs + " ms");
8345            }
8346
8347            // Distribute the remaining Tx power appropriately between all apps that transmitted
8348            // packets.
8349            for (int i = 0; i < txPackets.size(); i++) {
8350                final Uid uid = getUidStatsLocked(txPackets.keyAt(i));
8351                final long myTxTimeMs = (txPackets.valueAt(i) * leftOverTxTimeMs) / totalTxPackets;
8352                if (DEBUG_ENERGY) {
8353                    Slog.d(TAG, "  TxTime for UID " + uid.getUid() + ": " + myTxTimeMs + " ms");
8354                }
8355                uid.getOrCreateWifiControllerActivityLocked().getTxTimeCounters()[0]
8356                        .addCountLocked(myTxTimeMs);
8357            }
8358
8359            // Distribute the remaining Rx power appropriately between all apps that received
8360            // packets.
8361            for (int i = 0; i < rxPackets.size(); i++) {
8362                final Uid uid = getUidStatsLocked(rxPackets.keyAt(i));
8363                final long myRxTimeMs = (rxPackets.valueAt(i) * leftOverRxTimeMs) / totalRxPackets;
8364                if (DEBUG_ENERGY) {
8365                    Slog.d(TAG, "  RxTime for UID " + uid.getUid() + ": " + myRxTimeMs + " ms");
8366                }
8367                uid.getOrCreateWifiControllerActivityLocked().getRxTimeCounter()
8368                        .addCountLocked(myRxTimeMs);
8369            }
8370
8371            // Any left over power use will be picked up by the WiFi category in BatteryStatsHelper.
8372
8373            // Update WiFi controller stats.
8374            mWifiActivity.getRxTimeCounter().addCountLocked(info.getControllerRxTimeMillis());
8375            mWifiActivity.getTxTimeCounters()[0].addCountLocked(info.getControllerTxTimeMillis());
8376            mWifiActivity.getIdleTimeCounter().addCountLocked(info.getControllerIdleTimeMillis());
8377
8378            // POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
8379            final double opVolt = mPowerProfile.getAveragePower(
8380                    PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
8381            if (opVolt != 0) {
8382                // We store the power drain as mAms.
8383                mWifiActivity.getPowerCounter().addCountLocked(
8384                        (long)(info.getControllerEnergyUsed() / opVolt));
8385            }
8386        }
8387    }
8388
8389    /**
8390     * Distribute Cell radio energy info and network traffic to apps.
8391     */
8392    public void updateMobileRadioStateLocked(final long elapsedRealtimeMs,
8393                                             final ModemActivityInfo activityInfo) {
8394        if (DEBUG_ENERGY) {
8395            Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
8396        }
8397
8398        NetworkStats delta = null;
8399        try {
8400            if (!ArrayUtils.isEmpty(mMobileIfaces)) {
8401                delta = getNetworkStatsDeltaLocked(mMobileIfaces, mMobileNetworkStats);
8402            }
8403        } catch (IOException e) {
8404            Slog.wtf(TAG, "Failed to get mobile network stats", e);
8405            return;
8406        }
8407
8408        if (!mOnBatteryInternal) {
8409            return;
8410        }
8411
8412        long radioTime = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
8413                elapsedRealtimeMs * 1000);
8414        mMobileRadioActivePerAppTimer.setMark(elapsedRealtimeMs);
8415
8416        long totalRxPackets = 0;
8417        long totalTxPackets = 0;
8418        if (delta != null) {
8419            final int size = delta.size();
8420            for (int i = 0; i < size; i++) {
8421                final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
8422                if (entry.rxPackets == 0 && entry.txPackets == 0) {
8423                    continue;
8424                }
8425
8426                if (DEBUG_ENERGY) {
8427                    Slog.d(TAG, "Mobile uid " + entry.uid + ": delta rx=" + entry.rxBytes
8428                            + " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets
8429                            + " txPackets=" + entry.txPackets);
8430                }
8431
8432                totalRxPackets += entry.rxPackets;
8433                totalTxPackets += entry.txPackets;
8434
8435                final Uid u = getUidStatsLocked(mapUid(entry.uid));
8436                u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes, entry.rxPackets);
8437                u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes, entry.txPackets);
8438
8439                mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
8440                        entry.rxBytes);
8441                mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
8442                        entry.txBytes);
8443                mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
8444                        entry.rxPackets);
8445                mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
8446                        entry.txPackets);
8447            }
8448
8449            // Now distribute proportional blame to the apps that did networking.
8450            long totalPackets = totalRxPackets + totalTxPackets;
8451            if (totalPackets > 0) {
8452                for (int i = 0; i < size; i++) {
8453                    final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
8454                    if (entry.rxPackets == 0 && entry.txPackets == 0) {
8455                        continue;
8456                    }
8457
8458                    final Uid u = getUidStatsLocked(mapUid(entry.uid));
8459
8460                    // Distribute total radio active time in to this app.
8461                    final long appPackets = entry.rxPackets + entry.txPackets;
8462                    final long appRadioTime = (radioTime * appPackets) / totalPackets;
8463                    u.noteMobileRadioActiveTimeLocked(appRadioTime);
8464
8465                    // Remove this app from the totals, so that we don't lose any time
8466                    // due to rounding.
8467                    radioTime -= appRadioTime;
8468                    totalPackets -= appPackets;
8469
8470                    if (activityInfo != null) {
8471                        ControllerActivityCounterImpl activityCounter =
8472                                u.getOrCreateModemControllerActivityLocked();
8473                        if (totalRxPackets > 0 && entry.rxPackets > 0) {
8474                            final long rxMs = (entry.rxPackets * activityInfo.getRxTimeMillis())
8475                                    / totalRxPackets;
8476                            activityCounter.getRxTimeCounter().addCountLocked(rxMs);
8477                        }
8478
8479                        if (totalTxPackets > 0 && entry.txPackets > 0) {
8480                            for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
8481                                long txMs = entry.txPackets * activityInfo.getTxTimeMillis()[lvl];
8482                                txMs /= totalTxPackets;
8483                                activityCounter.getTxTimeCounters()[lvl].addCountLocked(txMs);
8484                            }
8485                        }
8486                    }
8487                }
8488            }
8489
8490            if (radioTime > 0) {
8491                // Whoops, there is some radio time we can't blame on an app!
8492                mMobileRadioActiveUnknownTime.addCountLocked(radioTime);
8493                mMobileRadioActiveUnknownCount.addCountLocked(1);
8494            }
8495        }
8496
8497        if (activityInfo != null) {
8498            mHasModemReporting = true;
8499            mModemActivity.getIdleTimeCounter().addCountLocked(activityInfo.getIdleTimeMillis());
8500            mModemActivity.getRxTimeCounter().addCountLocked(activityInfo.getRxTimeMillis());
8501            for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
8502                mModemActivity.getTxTimeCounters()[lvl]
8503                        .addCountLocked(activityInfo.getTxTimeMillis()[lvl]);
8504            }
8505
8506            // POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
8507            final double opVolt = mPowerProfile.getAveragePower(
8508                    PowerProfile.POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
8509            if (opVolt != 0) {
8510                // We store the power drain as mAms.
8511                mModemActivity.getPowerCounter().addCountLocked(
8512                        (long) (activityInfo.getEnergyUsed() / opVolt));
8513            }
8514        }
8515    }
8516
8517    /**
8518     * Distribute Bluetooth energy info and network traffic to apps.
8519     * @param info The energy information from the bluetooth controller.
8520     */
8521    public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
8522        if (DEBUG_ENERGY) {
8523            Slog.d(TAG, "Updating bluetooth stats: " + info);
8524        }
8525
8526        if (info == null || !mOnBatteryInternal) {
8527            return;
8528        }
8529
8530        mHasBluetoothReporting = true;
8531
8532        final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
8533        final long rxTimeMs = info.getControllerRxTimeMillis();
8534        final long txTimeMs = info.getControllerTxTimeMillis();
8535
8536        if (DEBUG_ENERGY) {
8537            Slog.d(TAG, "------ BEGIN BLE power blaming ------");
8538            Slog.d(TAG, "  Tx Time:    " + txTimeMs + " ms");
8539            Slog.d(TAG, "  Rx Time:    " + rxTimeMs + " ms");
8540            Slog.d(TAG, "  Idle Time:  " + info.getControllerIdleTimeMillis() + " ms");
8541        }
8542
8543        long totalScanTimeMs = 0;
8544
8545        final int uidCount = mUidStats.size();
8546        for (int i = 0; i < uidCount; i++) {
8547            final Uid u = mUidStats.valueAt(i);
8548            if (u.mBluetoothScanTimer == null) {
8549                continue;
8550            }
8551
8552            totalScanTimeMs += u.mBluetoothScanTimer.getTimeSinceMarkLocked(
8553                    elapsedRealtimeMs * 1000) / 1000;
8554        }
8555
8556        final boolean normalizeScanRxTime = (totalScanTimeMs > rxTimeMs);
8557        final boolean normalizeScanTxTime = (totalScanTimeMs > txTimeMs);
8558
8559        if (DEBUG_ENERGY) {
8560            Slog.d(TAG, "Normalizing scan power for RX=" + normalizeScanRxTime
8561                    + " TX=" + normalizeScanTxTime);
8562        }
8563
8564        long leftOverRxTimeMs = rxTimeMs;
8565        long leftOverTxTimeMs = txTimeMs;
8566
8567        for (int i = 0; i < uidCount; i++) {
8568            final Uid u = mUidStats.valueAt(i);
8569            if (u.mBluetoothScanTimer == null) {
8570                continue;
8571            }
8572
8573            long scanTimeSinceMarkMs = u.mBluetoothScanTimer.getTimeSinceMarkLocked(
8574                    elapsedRealtimeMs * 1000) / 1000;
8575            if (scanTimeSinceMarkMs > 0) {
8576                // Set the new mark so that next time we get new data since this point.
8577                u.mBluetoothScanTimer.setMark(elapsedRealtimeMs);
8578
8579                long scanTimeRxSinceMarkMs = scanTimeSinceMarkMs;
8580                long scanTimeTxSinceMarkMs = scanTimeSinceMarkMs;
8581
8582                if (normalizeScanRxTime) {
8583                    // Scan time is longer than the total rx time in the controller,
8584                    // so distribute the scan time proportionately. This means regular traffic
8585                    // will not blamed, but scans are more expensive anyways.
8586                    scanTimeRxSinceMarkMs = (rxTimeMs * scanTimeRxSinceMarkMs) / totalScanTimeMs;
8587                }
8588
8589                if (normalizeScanTxTime) {
8590                    // Scan time is longer than the total tx time in the controller,
8591                    // so distribute the scan time proportionately. This means regular traffic
8592                    // will not blamed, but scans are more expensive anyways.
8593                    scanTimeTxSinceMarkMs = (txTimeMs * scanTimeTxSinceMarkMs) / totalScanTimeMs;
8594                }
8595
8596                final ControllerActivityCounterImpl counter =
8597                        u.getOrCreateBluetoothControllerActivityLocked();
8598                counter.getRxTimeCounter().addCountLocked(scanTimeRxSinceMarkMs);
8599                counter.getTxTimeCounters()[0].addCountLocked(scanTimeTxSinceMarkMs);
8600
8601                leftOverRxTimeMs -= scanTimeRxSinceMarkMs;
8602                leftOverTxTimeMs -= scanTimeTxSinceMarkMs;
8603            }
8604        }
8605
8606        if (DEBUG_ENERGY) {
8607            Slog.d(TAG, "Left over time for traffic RX=" + leftOverRxTimeMs
8608                    + " TX=" + leftOverTxTimeMs);
8609        }
8610
8611        //
8612        // Now distribute blame to apps that did bluetooth traffic.
8613        //
8614
8615        long totalTxBytes = 0;
8616        long totalRxBytes = 0;
8617
8618        final UidTraffic[] uidTraffic = info.getUidTraffic();
8619        final int numUids = uidTraffic != null ? uidTraffic.length : 0;
8620        for (int i = 0; i < numUids; i++) {
8621            final UidTraffic traffic = uidTraffic[i];
8622
8623            // Add to the global counters.
8624            mNetworkByteActivityCounters[NETWORK_BT_RX_DATA].addCountLocked(
8625                    traffic.getRxBytes());
8626            mNetworkByteActivityCounters[NETWORK_BT_TX_DATA].addCountLocked(
8627                    traffic.getTxBytes());
8628
8629            // Add to the UID counters.
8630            final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
8631            u.noteNetworkActivityLocked(NETWORK_BT_RX_DATA, traffic.getRxBytes(), 0);
8632            u.noteNetworkActivityLocked(NETWORK_BT_TX_DATA, traffic.getTxBytes(), 0);
8633
8634            // Calculate the total traffic.
8635            totalTxBytes += traffic.getTxBytes();
8636            totalRxBytes += traffic.getRxBytes();
8637        }
8638
8639        if ((totalTxBytes != 0 || totalRxBytes != 0) &&
8640                (leftOverRxTimeMs != 0 || leftOverTxTimeMs != 0)) {
8641            for (int i = 0; i < numUids; i++) {
8642                final UidTraffic traffic = uidTraffic[i];
8643
8644                final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
8645                final ControllerActivityCounterImpl counter =
8646                        u.getOrCreateBluetoothControllerActivityLocked();
8647
8648                if (totalRxBytes > 0 && traffic.getRxBytes() > 0) {
8649                    final long timeRxMs = (leftOverRxTimeMs * traffic.getRxBytes()) / totalRxBytes;
8650
8651                    if (DEBUG_ENERGY) {
8652                        Slog.d(TAG, "UID=" + traffic.getUid() + " rx_bytes=" + traffic.getRxBytes()
8653                                + " rx_time=" + timeRxMs);
8654                    }
8655                    counter.getRxTimeCounter().addCountLocked(timeRxMs);
8656                    leftOverRxTimeMs -= timeRxMs;
8657                }
8658
8659                if (totalTxBytes > 0 && traffic.getTxBytes() > 0) {
8660                    final long timeTxMs = (leftOverTxTimeMs * traffic.getTxBytes()) / totalTxBytes;
8661
8662                    if (DEBUG_ENERGY) {
8663                        Slog.d(TAG, "UID=" + traffic.getUid() + " tx_bytes=" + traffic.getTxBytes()
8664                                + " tx_time=" + timeTxMs);
8665                    }
8666
8667                    counter.getTxTimeCounters()[0].addCountLocked(timeTxMs);
8668                    leftOverTxTimeMs -= timeTxMs;
8669                }
8670            }
8671        }
8672
8673        mBluetoothActivity.getRxTimeCounter().addCountLocked(
8674                info.getControllerRxTimeMillis());
8675        mBluetoothActivity.getTxTimeCounters()[0].addCountLocked(
8676                info.getControllerTxTimeMillis());
8677        mBluetoothActivity.getIdleTimeCounter().addCountLocked(
8678                info.getControllerIdleTimeMillis());
8679
8680        // POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
8681        final double opVolt = mPowerProfile.getAveragePower(
8682                PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
8683        if (opVolt != 0) {
8684            // We store the power drain as mAms.
8685            mBluetoothActivity.getPowerCounter().addCountLocked(
8686                    (long) (info.getControllerEnergyUsed() / opVolt));
8687        }
8688    }
8689
8690    /**
8691     * Read and distribute kernel wake lock use across apps.
8692     */
8693    public void updateKernelWakelocksLocked() {
8694        final KernelWakelockStats wakelockStats = mKernelWakelockReader.readKernelWakelockStats(
8695                mTmpWakelockStats);
8696        if (wakelockStats == null) {
8697            // Not crashing might make board bringup easier.
8698            Slog.w(TAG, "Couldn't get kernel wake lock stats");
8699            return;
8700        }
8701
8702        // Record whether we've seen a non-zero time (for debugging b/22716723).
8703        boolean seenNonZeroTime = false;
8704        for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
8705            String name = ent.getKey();
8706            KernelWakelockStats.Entry kws = ent.getValue();
8707
8708            SamplingTimer kwlt = mKernelWakelockStats.get(name);
8709            if (kwlt == null) {
8710                kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase,
8711                        true /* track reported val */);
8712                mKernelWakelockStats.put(name, kwlt);
8713            }
8714            kwlt.updateCurrentReportedCount(kws.mCount);
8715            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
8716            kwlt.setUpdateVersion(kws.mVersion);
8717
8718            if (kws.mVersion != wakelockStats.kernelWakelockVersion)
8719            seenNonZeroTime |= kws.mTotalTime > 0;
8720        }
8721
8722        int numWakelocksSetStale = 0;
8723        if (wakelockStats.size() != mKernelWakelockStats.size()) {
8724            // Set timers to stale if they didn't appear in /proc/wakelocks this time.
8725            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
8726                SamplingTimer st = ent.getValue();
8727                if (st.getUpdateVersion() != wakelockStats.kernelWakelockVersion) {
8728                    st.setStale();
8729                    numWakelocksSetStale++;
8730                }
8731            }
8732        }
8733
8734        if (!seenNonZeroTime) {
8735            Slog.wtf(TAG, "All kernel wakelocks had time of zero");
8736        }
8737
8738        if (numWakelocksSetStale == mKernelWakelockStats.size()) {
8739            Slog.wtf(TAG, "All kernel wakelocks were set stale. new version=" +
8740                    wakelockStats.kernelWakelockVersion);
8741        }
8742    }
8743
8744    // We use an anonymous class to access these variables,
8745    // so they can't live on the stack or they'd have to be
8746    // final MutableLong objects (more allocations).
8747    // Used in updateCpuTimeLocked().
8748    long mTempTotalCpuUserTimeUs;
8749    long mTempTotalCpuSystemTimeUs;
8750
8751    /**
8752     * Read and distribute CPU usage across apps. If their are partial wakelocks being held
8753     * and we are on battery with screen off, we give more of the cpu time to those apps holding
8754     * wakelocks. If the screen is on, we just assign the actual cpu time an app used.
8755     */
8756    public void updateCpuTimeLocked() {
8757        if (mPowerProfile == null) {
8758            return;
8759        }
8760
8761        if (DEBUG_ENERGY_CPU) {
8762            Slog.d(TAG, "!Cpu updating!");
8763        }
8764
8765        // Holding a wakelock costs more than just using the cpu.
8766        // Currently, we assign only half the cpu time to an app that is running but
8767        // not holding a wakelock. The apps holding wakelocks get the rest of the blame.
8768        // If no app is holding a wakelock, then the distribution is normal.
8769        final int wakelockWeight = 50;
8770
8771        // Read the time spent for each cluster at various cpu frequencies.
8772        final long[][] clusterSpeeds = new long[mKernelCpuSpeedReaders.length][];
8773        for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
8774            clusterSpeeds[cluster] = mKernelCpuSpeedReaders[cluster].readDelta();
8775        }
8776
8777        int numWakelocks = 0;
8778
8779        // Calculate how many wakelocks we have to distribute amongst. The system is excluded.
8780        // Only distribute cpu power to wakelocks if the screen is off and we're on battery.
8781        final int numPartialTimers = mPartialTimers.size();
8782        if (mOnBatteryScreenOffTimeBase.isRunning()) {
8783            for (int i = 0; i < numPartialTimers; i++) {
8784                final StopwatchTimer timer = mPartialTimers.get(i);
8785                if (timer.mInList && timer.mUid != null && timer.mUid.mUid != Process.SYSTEM_UID) {
8786                    // Since the collection and blaming of wakelocks can be scheduled to run after
8787                    // some delay, the mPartialTimers list may have new entries. We can't blame
8788                    // the newly added timer for past cpu time, so we only consider timers that
8789                    // were present for one round of collection. Once a timer has gone through
8790                    // a round of collection, its mInList field is set to true.
8791                    numWakelocks++;
8792                }
8793            }
8794        }
8795
8796        final int numWakelocksF = numWakelocks;
8797        mTempTotalCpuUserTimeUs = 0;
8798        mTempTotalCpuSystemTimeUs = 0;
8799
8800        // Read the CPU data for each UID. This will internally generate a snapshot so next time
8801        // we read, we get a delta. If we are to distribute the cpu time, then do so. Otherwise
8802        // we just ignore the data.
8803        final long startTimeMs = mClocks.elapsedRealtime();
8804        mKernelUidCpuTimeReader.readDelta(!mOnBatteryInternal ? null :
8805                new KernelUidCpuTimeReader.Callback() {
8806                    @Override
8807                    public void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs,
8808                                             long powerMaUs) {
8809                        final Uid u = getUidStatsLocked(mapUid(uid));
8810
8811                        // Accumulate the total system and user time.
8812                        mTempTotalCpuUserTimeUs += userTimeUs;
8813                        mTempTotalCpuSystemTimeUs += systemTimeUs;
8814
8815                        StringBuilder sb = null;
8816                        if (DEBUG_ENERGY_CPU) {
8817                            sb = new StringBuilder();
8818                            sb.append("  got time for uid=").append(u.mUid).append(": u=");
8819                            TimeUtils.formatDuration(userTimeUs / 1000, sb);
8820                            sb.append(" s=");
8821                            TimeUtils.formatDuration(systemTimeUs / 1000, sb);
8822                            sb.append(" p=").append(powerMaUs / 1000).append("mAms\n");
8823                        }
8824
8825                        if (numWakelocksF > 0) {
8826                            // We have wakelocks being held, so only give a portion of the
8827                            // time to the process. The rest will be distributed among wakelock
8828                            // holders.
8829                            userTimeUs = (userTimeUs * wakelockWeight) / 100;
8830                            systemTimeUs = (systemTimeUs * wakelockWeight) / 100;
8831                        }
8832
8833                        if (sb != null) {
8834                            sb.append("  adding to uid=").append(u.mUid).append(": u=");
8835                            TimeUtils.formatDuration(userTimeUs / 1000, sb);
8836                            sb.append(" s=");
8837                            TimeUtils.formatDuration(systemTimeUs / 1000, sb);
8838                            sb.append(" p=").append(powerMaUs / 1000).append("mAms");
8839                            Slog.d(TAG, sb.toString());
8840                        }
8841
8842                        u.mUserCpuTime.addCountLocked(userTimeUs);
8843                        u.mSystemCpuTime.addCountLocked(systemTimeUs);
8844                        u.mCpuPower.addCountLocked(powerMaUs);
8845
8846                        // Add the cpu speeds to this UID. These are used as a ratio
8847                        // for computing the power this UID used.
8848                        final int numClusters = mPowerProfile.getNumCpuClusters();
8849                        if (u.mCpuClusterSpeed == null || u.mCpuClusterSpeed.length !=
8850                                numClusters) {
8851                            u.mCpuClusterSpeed = new LongSamplingCounter[numClusters][];
8852                        }
8853
8854                        for (int cluster = 0; cluster < clusterSpeeds.length; cluster++) {
8855                            final int speedsInCluster = mPowerProfile.getNumSpeedStepsInCpuCluster(
8856                                    cluster);
8857                            if (u.mCpuClusterSpeed[cluster] == null || speedsInCluster !=
8858                                    u.mCpuClusterSpeed[cluster].length) {
8859                                u.mCpuClusterSpeed[cluster] =
8860                                        new LongSamplingCounter[speedsInCluster];
8861                            }
8862
8863                            final LongSamplingCounter[] cpuSpeeds = u.mCpuClusterSpeed[cluster];
8864                            for (int speed = 0; speed < clusterSpeeds[cluster].length; speed++) {
8865                                if (cpuSpeeds[speed] == null) {
8866                                    cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase);
8867                                }
8868                                cpuSpeeds[speed].addCountLocked(clusterSpeeds[cluster][speed]);
8869                            }
8870                        }
8871                    }
8872                });
8873
8874        if (DEBUG_ENERGY_CPU) {
8875            Slog.d(TAG, "Reading cpu stats took " + (mClocks.elapsedRealtime() - startTimeMs) +
8876                    " ms");
8877        }
8878
8879        if (mOnBatteryInternal && numWakelocks > 0) {
8880            // Distribute a portion of the total cpu time to wakelock holders.
8881            mTempTotalCpuUserTimeUs = (mTempTotalCpuUserTimeUs * (100 - wakelockWeight)) / 100;
8882            mTempTotalCpuSystemTimeUs =
8883                    (mTempTotalCpuSystemTimeUs * (100 - wakelockWeight)) / 100;
8884
8885            for (int i = 0; i < numPartialTimers; i++) {
8886                final StopwatchTimer timer = mPartialTimers.get(i);
8887
8888                // The system does not share any blame, as it is usually holding the wakelock
8889                // on behalf of an app.
8890                if (timer.mInList && timer.mUid != null && timer.mUid.mUid != Process.SYSTEM_UID) {
8891                    int userTimeUs = (int) (mTempTotalCpuUserTimeUs / numWakelocks);
8892                    int systemTimeUs = (int) (mTempTotalCpuSystemTimeUs / numWakelocks);
8893
8894                    if (DEBUG_ENERGY_CPU) {
8895                        StringBuilder sb = new StringBuilder();
8896                        sb.append("  Distributing wakelock uid=").append(timer.mUid.mUid)
8897                                .append(": u=");
8898                        TimeUtils.formatDuration(userTimeUs / 1000, sb);
8899                        sb.append(" s=");
8900                        TimeUtils.formatDuration(systemTimeUs / 1000, sb);
8901                        Slog.d(TAG, sb.toString());
8902                    }
8903
8904                    timer.mUid.mUserCpuTime.addCountLocked(userTimeUs);
8905                    timer.mUid.mSystemCpuTime.addCountLocked(systemTimeUs);
8906
8907                    final Uid.Proc proc = timer.mUid.getProcessStatsLocked("*wakelock*");
8908                    proc.addCpuTimeLocked(userTimeUs / 1000, systemTimeUs / 1000);
8909
8910                    mTempTotalCpuUserTimeUs -= userTimeUs;
8911                    mTempTotalCpuSystemTimeUs -= systemTimeUs;
8912                    numWakelocks--;
8913                }
8914            }
8915
8916            if (mTempTotalCpuUserTimeUs > 0 || mTempTotalCpuSystemTimeUs > 0) {
8917                // Anything left over is given to the system.
8918                if (DEBUG_ENERGY_CPU) {
8919                    StringBuilder sb = new StringBuilder();
8920                    sb.append("  Distributing lost time to system: u=");
8921                    TimeUtils.formatDuration(mTempTotalCpuUserTimeUs / 1000, sb);
8922                    sb.append(" s=");
8923                    TimeUtils.formatDuration(mTempTotalCpuSystemTimeUs / 1000, sb);
8924                    Slog.d(TAG, sb.toString());
8925                }
8926
8927                final Uid u = getUidStatsLocked(Process.SYSTEM_UID);
8928                u.mUserCpuTime.addCountLocked(mTempTotalCpuUserTimeUs);
8929                u.mSystemCpuTime.addCountLocked(mTempTotalCpuSystemTimeUs);
8930
8931                final Uid.Proc proc = u.getProcessStatsLocked("*lost*");
8932                proc.addCpuTimeLocked((int) mTempTotalCpuUserTimeUs / 1000,
8933                        (int) mTempTotalCpuSystemTimeUs / 1000);
8934            }
8935        }
8936
8937        // See if there is a difference in wakelocks between this collection and the last
8938        // collection.
8939        if (ArrayUtils.referenceEquals(mPartialTimers, mLastPartialTimers)) {
8940            // No difference, so each timer is now considered for the next collection.
8941            for (int i = 0; i < numPartialTimers; i++) {
8942                mPartialTimers.get(i).mInList = true;
8943            }
8944        } else {
8945            // The lists are different, meaning we added (or removed a timer) since the last
8946            // collection.
8947            final int numLastPartialTimers = mLastPartialTimers.size();
8948            for (int i = 0; i < numLastPartialTimers; i++) {
8949                mLastPartialTimers.get(i).mInList = false;
8950            }
8951            mLastPartialTimers.clear();
8952
8953            // Mark the current timers as gone through a collection.
8954            for (int i = 0; i < numPartialTimers; i++) {
8955                final StopwatchTimer timer = mPartialTimers.get(i);
8956                timer.mInList = true;
8957                mLastPartialTimers.add(timer);
8958            }
8959        }
8960    }
8961
8962    boolean setChargingLocked(boolean charging) {
8963        if (mCharging != charging) {
8964            mCharging = charging;
8965            if (charging) {
8966                mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
8967            } else {
8968                mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG;
8969            }
8970            mHandler.sendEmptyMessage(MSG_REPORT_CHARGING);
8971            return true;
8972        }
8973        return false;
8974    }
8975
8976    void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery,
8977            final int oldStatus, final int level) {
8978        boolean doWrite = false;
8979        Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
8980        m.arg1 = onBattery ? 1 : 0;
8981        mHandler.sendMessage(m);
8982
8983        final long uptime = mSecUptime * 1000;
8984        final long realtime = mSecRealtime * 1000;
8985        final boolean screenOn = mScreenState == Display.STATE_ON;
8986        if (onBattery) {
8987            // We will reset our status if we are unplugging after the
8988            // battery was last full, or the level is at 100, or
8989            // we have gone through a significant charge (from a very low
8990            // level to a now very high level).
8991            boolean reset = false;
8992            if (!mNoAutoReset && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
8993                    || level >= 90
8994                    || (mDischargeCurrentLevel < 20 && level >= 80)
8995                    || (getHighDischargeAmountSinceCharge() >= 200
8996                            && mHistoryBuffer.dataSize() >= MAX_HISTORY_BUFFER))) {
8997                Slog.i(TAG, "Resetting battery stats: level=" + level + " status=" + oldStatus
8998                        + " dischargeLevel=" + mDischargeCurrentLevel
8999                        + " lowAmount=" + getLowDischargeAmountSinceCharge()
9000                        + " highAmount=" + getHighDischargeAmountSinceCharge());
9001                // Before we write, collect a snapshot of the final aggregated
9002                // stats to be reported in the next checkin.  Only do this if we have
9003                // a sufficient amount of data to make it interesting.
9004                if (getLowDischargeAmountSinceCharge() >= 20) {
9005                    final Parcel parcel = Parcel.obtain();
9006                    writeSummaryToParcel(parcel, true);
9007                    BackgroundThread.getHandler().post(new Runnable() {
9008                        @Override public void run() {
9009                            synchronized (mCheckinFile) {
9010                                FileOutputStream stream = null;
9011                                try {
9012                                    stream = mCheckinFile.startWrite();
9013                                    stream.write(parcel.marshall());
9014                                    stream.flush();
9015                                    FileUtils.sync(stream);
9016                                    stream.close();
9017                                    mCheckinFile.finishWrite(stream);
9018                                } catch (IOException e) {
9019                                    Slog.w("BatteryStats",
9020                                            "Error writing checkin battery statistics", e);
9021                                    mCheckinFile.failWrite(stream);
9022                                } finally {
9023                                    parcel.recycle();
9024                                }
9025                            }
9026                        }
9027                    });
9028                }
9029                doWrite = true;
9030                resetAllStatsLocked();
9031                mDischargeStartLevel = level;
9032                reset = true;
9033                mDischargeStepTracker.init();
9034            }
9035            if (mCharging) {
9036                setChargingLocked(false);
9037            }
9038            mLastChargingStateLevel = level;
9039            mOnBattery = mOnBatteryInternal = true;
9040            mLastDischargeStepLevel = level;
9041            mMinDischargeStepLevel = level;
9042            mDischargeStepTracker.clearTime();
9043            mDailyDischargeStepTracker.clearTime();
9044            mInitStepMode = mCurStepMode;
9045            mModStepMode = 0;
9046            pullPendingStateUpdatesLocked();
9047            mHistoryCur.batteryLevel = (byte)level;
9048            mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
9049            if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
9050                    + Integer.toHexString(mHistoryCur.states));
9051            if (reset) {
9052                mRecordingHistory = true;
9053                startRecordingHistory(mSecRealtime, mSecUptime, reset);
9054            }
9055            addHistoryRecordLocked(mSecRealtime, mSecUptime);
9056            mDischargeCurrentLevel = mDischargeUnplugLevel = level;
9057            if (screenOn) {
9058                mDischargeScreenOnUnplugLevel = level;
9059                mDischargeScreenOffUnplugLevel = 0;
9060            } else {
9061                mDischargeScreenOnUnplugLevel = 0;
9062                mDischargeScreenOffUnplugLevel = level;
9063            }
9064            mDischargeAmountScreenOn = 0;
9065            mDischargeAmountScreenOff = 0;
9066            updateTimeBasesLocked(true, !screenOn, uptime, realtime);
9067        } else {
9068            mLastChargingStateLevel = level;
9069            mOnBattery = mOnBatteryInternal = false;
9070            pullPendingStateUpdatesLocked();
9071            mHistoryCur.batteryLevel = (byte)level;
9072            mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
9073            if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
9074                    + Integer.toHexString(mHistoryCur.states));
9075            addHistoryRecordLocked(mSecRealtime, mSecUptime);
9076            mDischargeCurrentLevel = mDischargePlugLevel = level;
9077            if (level < mDischargeUnplugLevel) {
9078                mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
9079                mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
9080            }
9081            updateDischargeScreenLevelsLocked(screenOn, screenOn);
9082            updateTimeBasesLocked(false, !screenOn, uptime, realtime);
9083            mChargeStepTracker.init();
9084            mLastChargeStepLevel = level;
9085            mMaxChargeStepLevel = level;
9086            mInitStepMode = mCurStepMode;
9087            mModStepMode = 0;
9088        }
9089        if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
9090            if (mFile != null) {
9091                writeAsyncLocked();
9092            }
9093        }
9094    }
9095
9096    private void startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs,
9097            boolean reset) {
9098        mRecordingHistory = true;
9099        mHistoryCur.currentTime = System.currentTimeMillis();
9100        addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs,
9101                reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME,
9102                mHistoryCur);
9103        mHistoryCur.currentTime = 0;
9104        if (reset) {
9105            initActiveHistoryEventsLocked(elapsedRealtimeMs, uptimeMs);
9106        }
9107    }
9108
9109    private void recordCurrentTimeChangeLocked(final long currentTime, final long elapsedRealtimeMs,
9110            final long uptimeMs) {
9111        if (mRecordingHistory) {
9112            mHistoryCur.currentTime = currentTime;
9113            addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_CURRENT_TIME,
9114                    mHistoryCur);
9115            mHistoryCur.currentTime = 0;
9116        }
9117    }
9118
9119    private void recordShutdownLocked(final long elapsedRealtimeMs, final long uptimeMs) {
9120        if (mRecordingHistory) {
9121            mHistoryCur.currentTime = System.currentTimeMillis();
9122            addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_SHUTDOWN,
9123                    mHistoryCur);
9124            mHistoryCur.currentTime = 0;
9125        }
9126    }
9127
9128    private void scheduleSyncExternalStatsLocked(String reason, int updateFlags) {
9129        if (mExternalSync != null) {
9130            mExternalSync.scheduleSync(reason, updateFlags);
9131        }
9132    }
9133
9134    // This should probably be exposed in the API, though it's not critical
9135    public static final int BATTERY_PLUGGED_NONE = 0;
9136
9137    public void setBatteryStateLocked(int status, int health, int plugType, int level,
9138            int temp, int volt) {
9139        final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
9140        final long uptime = mClocks.uptimeMillis();
9141        final long elapsedRealtime = mClocks.elapsedRealtime();
9142        if (!mHaveBatteryLevel) {
9143            mHaveBatteryLevel = true;
9144            // We start out assuming that the device is plugged in (not
9145            // on battery).  If our first report is now that we are indeed
9146            // plugged in, then twiddle our state to correctly reflect that
9147            // since we won't be going through the full setOnBattery().
9148            if (onBattery == mOnBattery) {
9149                if (onBattery) {
9150                    mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
9151                } else {
9152                    mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
9153                }
9154            }
9155            // Always start out assuming charging, that will be updated later.
9156            mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
9157            mHistoryCur.batteryStatus = (byte)status;
9158            mHistoryCur.batteryLevel = (byte)level;
9159            mMaxChargeStepLevel = mMinDischargeStepLevel =
9160                    mLastChargeStepLevel = mLastDischargeStepLevel = level;
9161            mLastChargingStateLevel = level;
9162        } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) {
9163            recordDailyStatsIfNeededLocked(level >= 100 && onBattery);
9164        }
9165        int oldStatus = mHistoryCur.batteryStatus;
9166        if (onBattery) {
9167            mDischargeCurrentLevel = level;
9168            if (!mRecordingHistory) {
9169                mRecordingHistory = true;
9170                startRecordingHistory(elapsedRealtime, uptime, true);
9171            }
9172        } else if (level < 96) {
9173            if (!mRecordingHistory) {
9174                mRecordingHistory = true;
9175                startRecordingHistory(elapsedRealtime, uptime, true);
9176            }
9177        }
9178        mCurrentBatteryLevel = level;
9179        if (mDischargePlugLevel < 0) {
9180            mDischargePlugLevel = level;
9181        }
9182        if (onBattery != mOnBattery) {
9183            mHistoryCur.batteryLevel = (byte)level;
9184            mHistoryCur.batteryStatus = (byte)status;
9185            mHistoryCur.batteryHealth = (byte)health;
9186            mHistoryCur.batteryPlugType = (byte)plugType;
9187            mHistoryCur.batteryTemperature = (short)temp;
9188            mHistoryCur.batteryVoltage = (char)volt;
9189            setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level);
9190        } else {
9191            boolean changed = false;
9192            if (mHistoryCur.batteryLevel != level) {
9193                mHistoryCur.batteryLevel = (byte)level;
9194                changed = true;
9195
9196                // TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record
9197                // which will pull external stats.
9198                scheduleSyncExternalStatsLocked("battery-level", ExternalStatsSync.UPDATE_ALL);
9199            }
9200            if (mHistoryCur.batteryStatus != status) {
9201                mHistoryCur.batteryStatus = (byte)status;
9202                changed = true;
9203            }
9204            if (mHistoryCur.batteryHealth != health) {
9205                mHistoryCur.batteryHealth = (byte)health;
9206                changed = true;
9207            }
9208            if (mHistoryCur.batteryPlugType != plugType) {
9209                mHistoryCur.batteryPlugType = (byte)plugType;
9210                changed = true;
9211            }
9212            if (temp >= (mHistoryCur.batteryTemperature+10)
9213                    || temp <= (mHistoryCur.batteryTemperature-10)) {
9214                mHistoryCur.batteryTemperature = (short)temp;
9215                changed = true;
9216            }
9217            if (volt > (mHistoryCur.batteryVoltage+20)
9218                    || volt < (mHistoryCur.batteryVoltage-20)) {
9219                mHistoryCur.batteryVoltage = (char)volt;
9220                changed = true;
9221            }
9222            long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT)
9223                    | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT)
9224                    | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
9225            if (onBattery) {
9226                changed |= setChargingLocked(false);
9227                if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
9228                    mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
9229                            modeBits, elapsedRealtime);
9230                    mDailyDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
9231                            modeBits, elapsedRealtime);
9232                    mLastDischargeStepLevel = level;
9233                    mMinDischargeStepLevel = level;
9234                    mInitStepMode = mCurStepMode;
9235                    mModStepMode = 0;
9236                }
9237            } else {
9238                if (level >= 90) {
9239                    // If the battery level is at least 90%, always consider the device to be
9240                    // charging even if it happens to go down a level.
9241                    changed |= setChargingLocked(true);
9242                    mLastChargeStepLevel = level;
9243                } if (!mCharging) {
9244                    if (mLastChargeStepLevel < level) {
9245                        // We have not reporting that we are charging, but the level has now
9246                        // gone up, so consider the state to be charging.
9247                        changed |= setChargingLocked(true);
9248                        mLastChargeStepLevel = level;
9249                    }
9250                } else {
9251                    if (mLastChargeStepLevel > level) {
9252                        // We had reported that the device was charging, but here we are with
9253                        // power connected and the level going down.  Looks like the current
9254                        // power supplied isn't enough, so consider the device to now be
9255                        // discharging.
9256                        changed |= setChargingLocked(false);
9257                        mLastChargeStepLevel = level;
9258                    }
9259                }
9260                if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
9261                    mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
9262                            modeBits, elapsedRealtime);
9263                    mDailyChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
9264                            modeBits, elapsedRealtime);
9265                    mLastChargeStepLevel = level;
9266                    mMaxChargeStepLevel = level;
9267                    mInitStepMode = mCurStepMode;
9268                    mModStepMode = 0;
9269                }
9270            }
9271            if (changed) {
9272                addHistoryRecordLocked(elapsedRealtime, uptime);
9273            }
9274        }
9275        if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
9276            // We don't record history while we are plugged in and fully charged.
9277            // The next time we are unplugged, history will be cleared.
9278            mRecordingHistory = DEBUG;
9279        }
9280    }
9281
9282    public long getAwakeTimeBattery() {
9283        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
9284    }
9285
9286    public long getAwakeTimePlugged() {
9287        return (mClocks.uptimeMillis() * 1000) - getAwakeTimeBattery();
9288    }
9289
9290    @Override
9291    public long computeUptime(long curTime, int which) {
9292        switch (which) {
9293            case STATS_SINCE_CHARGED: return mUptime + (curTime-mUptimeStart);
9294            case STATS_CURRENT: return (curTime-mUptimeStart);
9295            case STATS_SINCE_UNPLUGGED: return (curTime-mOnBatteryTimeBase.getUptimeStart());
9296        }
9297        return 0;
9298    }
9299
9300    @Override
9301    public long computeRealtime(long curTime, int which) {
9302        switch (which) {
9303            case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
9304            case STATS_CURRENT: return (curTime-mRealtimeStart);
9305            case STATS_SINCE_UNPLUGGED: return (curTime-mOnBatteryTimeBase.getRealtimeStart());
9306        }
9307        return 0;
9308    }
9309
9310    @Override
9311    public long computeBatteryUptime(long curTime, int which) {
9312        return mOnBatteryTimeBase.computeUptime(curTime, which);
9313    }
9314
9315    @Override
9316    public long computeBatteryRealtime(long curTime, int which) {
9317        return mOnBatteryTimeBase.computeRealtime(curTime, which);
9318    }
9319
9320    @Override
9321    public long computeBatteryScreenOffUptime(long curTime, int which) {
9322        return mOnBatteryScreenOffTimeBase.computeUptime(curTime, which);
9323    }
9324
9325    @Override
9326    public long computeBatteryScreenOffRealtime(long curTime, int which) {
9327        return mOnBatteryScreenOffTimeBase.computeRealtime(curTime, which);
9328    }
9329
9330    private long computeTimePerLevel(long[] steps, int numSteps) {
9331        // For now we'll do a simple average across all steps.
9332        if (numSteps <= 0) {
9333            return -1;
9334        }
9335        long total = 0;
9336        for (int i=0; i<numSteps; i++) {
9337            total += steps[i] & STEP_LEVEL_TIME_MASK;
9338        }
9339        return total / numSteps;
9340        /*
9341        long[] buckets = new long[numSteps];
9342        int numBuckets = 0;
9343        int numToAverage = 4;
9344        int i = 0;
9345        while (i < numSteps) {
9346            long totalTime = 0;
9347            int num = 0;
9348            for (int j=0; j<numToAverage && (i+j)<numSteps; j++) {
9349                totalTime += steps[i+j] & STEP_LEVEL_TIME_MASK;
9350                num++;
9351            }
9352            buckets[numBuckets] = totalTime / num;
9353            numBuckets++;
9354            numToAverage *= 2;
9355            i += num;
9356        }
9357        if (numBuckets < 1) {
9358            return -1;
9359        }
9360        long averageTime = buckets[numBuckets-1];
9361        for (i=numBuckets-2; i>=0; i--) {
9362            averageTime = (averageTime + buckets[i]) / 2;
9363        }
9364        return averageTime;
9365        */
9366    }
9367
9368    @Override
9369    public long computeBatteryTimeRemaining(long curTime) {
9370        if (!mOnBattery) {
9371            return -1;
9372        }
9373        /* Simple implementation just looks at the average discharge per level across the
9374           entire sample period.
9375        int discharge = (getLowDischargeAmountSinceCharge()+getHighDischargeAmountSinceCharge())/2;
9376        if (discharge < 2) {
9377            return -1;
9378        }
9379        long duration = computeBatteryRealtime(curTime, STATS_SINCE_CHARGED);
9380        if (duration < 1000*1000) {
9381            return -1;
9382        }
9383        long usPerLevel = duration/discharge;
9384        return usPerLevel * mCurrentBatteryLevel;
9385        */
9386        if (mDischargeStepTracker.mNumStepDurations < 1) {
9387            return -1;
9388        }
9389        long msPerLevel = mDischargeStepTracker.computeTimePerLevel();
9390        if (msPerLevel <= 0) {
9391            return -1;
9392        }
9393        return (msPerLevel * mCurrentBatteryLevel) * 1000;
9394    }
9395
9396    @Override
9397    public LevelStepTracker getDischargeLevelStepTracker() {
9398        return mDischargeStepTracker;
9399    }
9400
9401    @Override
9402    public LevelStepTracker getDailyDischargeLevelStepTracker() {
9403        return mDailyDischargeStepTracker;
9404    }
9405
9406    @Override
9407    public long computeChargeTimeRemaining(long curTime) {
9408        if (mOnBattery) {
9409            // Not yet working.
9410            return -1;
9411        }
9412        /* Broken
9413        int curLevel = mCurrentBatteryLevel;
9414        int plugLevel = mDischargePlugLevel;
9415        if (plugLevel < 0 || curLevel < (plugLevel+1)) {
9416            return -1;
9417        }
9418        long duration = computeBatteryRealtime(curTime, STATS_SINCE_UNPLUGGED);
9419        if (duration < 1000*1000) {
9420            return -1;
9421        }
9422        long usPerLevel = duration/(curLevel-plugLevel);
9423        return usPerLevel * (100-curLevel);
9424        */
9425        if (mChargeStepTracker.mNumStepDurations < 1) {
9426            return -1;
9427        }
9428        long msPerLevel = mChargeStepTracker.computeTimePerLevel();
9429        if (msPerLevel <= 0) {
9430            return -1;
9431        }
9432        return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000;
9433    }
9434
9435    @Override
9436    public LevelStepTracker getChargeLevelStepTracker() {
9437        return mChargeStepTracker;
9438    }
9439
9440    @Override
9441    public LevelStepTracker getDailyChargeLevelStepTracker() {
9442        return mDailyChargeStepTracker;
9443    }
9444
9445    @Override
9446    public ArrayList<PackageChange> getDailyPackageChanges() {
9447        return mDailyPackageChanges;
9448    }
9449
9450    protected long getBatteryUptimeLocked() {
9451        return mOnBatteryTimeBase.getUptime(mClocks.uptimeMillis() * 1000);
9452    }
9453
9454    @Override
9455    public long getBatteryUptime(long curTime) {
9456        return mOnBatteryTimeBase.getUptime(curTime);
9457    }
9458
9459    @Override
9460    public long getBatteryRealtime(long curTime) {
9461        return mOnBatteryTimeBase.getRealtime(curTime);
9462    }
9463
9464    @Override
9465    public int getDischargeStartLevel() {
9466        synchronized(this) {
9467            return getDischargeStartLevelLocked();
9468        }
9469    }
9470
9471    public int getDischargeStartLevelLocked() {
9472            return mDischargeUnplugLevel;
9473    }
9474
9475    @Override
9476    public int getDischargeCurrentLevel() {
9477        synchronized(this) {
9478            return getDischargeCurrentLevelLocked();
9479        }
9480    }
9481
9482    public int getDischargeCurrentLevelLocked() {
9483        return mDischargeCurrentLevel;
9484    }
9485
9486    @Override
9487    public int getLowDischargeAmountSinceCharge() {
9488        synchronized(this) {
9489            int val = mLowDischargeAmountSinceCharge;
9490            if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
9491                val += mDischargeUnplugLevel-mDischargeCurrentLevel-1;
9492            }
9493            return val;
9494        }
9495    }
9496
9497    @Override
9498    public int getHighDischargeAmountSinceCharge() {
9499        synchronized(this) {
9500            int val = mHighDischargeAmountSinceCharge;
9501            if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
9502                val += mDischargeUnplugLevel-mDischargeCurrentLevel;
9503            }
9504            return val;
9505        }
9506    }
9507
9508    @Override
9509    public int getDischargeAmount(int which) {
9510        int dischargeAmount = which == STATS_SINCE_CHARGED
9511                ? getHighDischargeAmountSinceCharge()
9512                : (getDischargeStartLevel() - getDischargeCurrentLevel());
9513        if (dischargeAmount < 0) {
9514            dischargeAmount = 0;
9515        }
9516        return dischargeAmount;
9517    }
9518
9519    public int getDischargeAmountScreenOn() {
9520        synchronized(this) {
9521            int val = mDischargeAmountScreenOn;
9522            if (mOnBattery && mScreenState == Display.STATE_ON
9523                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
9524                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
9525            }
9526            return val;
9527        }
9528    }
9529
9530    public int getDischargeAmountScreenOnSinceCharge() {
9531        synchronized(this) {
9532            int val = mDischargeAmountScreenOnSinceCharge;
9533            if (mOnBattery && mScreenState == Display.STATE_ON
9534                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
9535                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
9536            }
9537            return val;
9538        }
9539    }
9540
9541    public int getDischargeAmountScreenOff() {
9542        synchronized(this) {
9543            int val = mDischargeAmountScreenOff;
9544            if (mOnBattery && mScreenState != Display.STATE_ON
9545                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
9546                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
9547            }
9548            return val;
9549        }
9550    }
9551
9552    public int getDischargeAmountScreenOffSinceCharge() {
9553        synchronized(this) {
9554            int val = mDischargeAmountScreenOffSinceCharge;
9555            if (mOnBattery && mScreenState != Display.STATE_ON
9556                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
9557                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
9558            }
9559            return val;
9560        }
9561    }
9562
9563    /**
9564     * Retrieve the statistics object for a particular uid, creating if needed.
9565     */
9566    public Uid getUidStatsLocked(int uid) {
9567        Uid u = mUidStats.get(uid);
9568        if (u == null) {
9569            u = new Uid(this, uid);
9570            mUidStats.put(uid, u);
9571        }
9572        return u;
9573    }
9574
9575    /**
9576     * Remove the statistics object for a particular uid.
9577     */
9578    public void removeUidStatsLocked(int uid) {
9579        mKernelUidCpuTimeReader.removeUid(uid);
9580        mUidStats.remove(uid);
9581    }
9582
9583    /**
9584     * Retrieve the statistics object for a particular process, creating
9585     * if needed.
9586     */
9587    public Uid.Proc getProcessStatsLocked(int uid, String name) {
9588        uid = mapUid(uid);
9589        Uid u = getUidStatsLocked(uid);
9590        return u.getProcessStatsLocked(name);
9591    }
9592
9593    /**
9594     * Retrieve the statistics object for a particular process, creating
9595     * if needed.
9596     */
9597    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
9598        uid = mapUid(uid);
9599        Uid u = getUidStatsLocked(uid);
9600        return u.getPackageStatsLocked(pkg);
9601    }
9602
9603    /**
9604     * Retrieve the statistics object for a particular service, creating
9605     * if needed.
9606     */
9607    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
9608        uid = mapUid(uid);
9609        Uid u = getUidStatsLocked(uid);
9610        return u.getServiceStatsLocked(pkg, name);
9611    }
9612
9613    public void shutdownLocked() {
9614        recordShutdownLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
9615        writeSyncLocked();
9616        mShuttingDown = true;
9617    }
9618
9619    Parcel mPendingWrite = null;
9620    final ReentrantLock mWriteLock = new ReentrantLock();
9621
9622    public void writeAsyncLocked() {
9623        writeLocked(false);
9624    }
9625
9626    public void writeSyncLocked() {
9627        writeLocked(true);
9628    }
9629
9630    void writeLocked(boolean sync) {
9631        if (mFile == null) {
9632            Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
9633            return;
9634        }
9635
9636        if (mShuttingDown) {
9637            return;
9638        }
9639
9640        Parcel out = Parcel.obtain();
9641        writeSummaryToParcel(out, true);
9642        mLastWriteTime = mClocks.elapsedRealtime();
9643
9644        if (mPendingWrite != null) {
9645            mPendingWrite.recycle();
9646        }
9647        mPendingWrite = out;
9648
9649        if (sync) {
9650            commitPendingDataToDisk();
9651        } else {
9652            BackgroundThread.getHandler().post(new Runnable() {
9653                @Override public void run() {
9654                    commitPendingDataToDisk();
9655                }
9656            });
9657        }
9658    }
9659
9660    public void commitPendingDataToDisk() {
9661        final Parcel next;
9662        synchronized (this) {
9663            next = mPendingWrite;
9664            mPendingWrite = null;
9665            if (next == null) {
9666                return;
9667            }
9668
9669            mWriteLock.lock();
9670        }
9671
9672        try {
9673            FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
9674            stream.write(next.marshall());
9675            stream.flush();
9676            FileUtils.sync(stream);
9677            stream.close();
9678            mFile.commit();
9679        } catch (IOException e) {
9680            Slog.w("BatteryStats", "Error writing battery statistics", e);
9681            mFile.rollback();
9682        } finally {
9683            next.recycle();
9684            mWriteLock.unlock();
9685        }
9686    }
9687
9688    public void readLocked() {
9689        if (mDailyFile != null) {
9690            readDailyStatsLocked();
9691        }
9692
9693        if (mFile == null) {
9694            Slog.w("BatteryStats", "readLocked: no file associated with this instance");
9695            return;
9696        }
9697
9698        mUidStats.clear();
9699
9700        try {
9701            File file = mFile.chooseForRead();
9702            if (!file.exists()) {
9703                return;
9704            }
9705            FileInputStream stream = new FileInputStream(file);
9706
9707            byte[] raw = BatteryStatsHelper.readFully(stream);
9708            Parcel in = Parcel.obtain();
9709            in.unmarshall(raw, 0, raw.length);
9710            in.setDataPosition(0);
9711            stream.close();
9712
9713            readSummaryFromParcel(in);
9714        } catch(Exception e) {
9715            Slog.e("BatteryStats", "Error reading battery statistics", e);
9716            resetAllStatsLocked();
9717        }
9718
9719        mEndPlatformVersion = Build.ID;
9720
9721        if (mHistoryBuffer.dataPosition() > 0) {
9722            mRecordingHistory = true;
9723            final long elapsedRealtime = mClocks.elapsedRealtime();
9724            final long uptime = mClocks.uptimeMillis();
9725            if (USE_OLD_HISTORY) {
9726                addHistoryRecordLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
9727            }
9728            addHistoryBufferLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
9729            startRecordingHistory(elapsedRealtime, uptime, false);
9730        }
9731
9732        recordDailyStatsIfNeededLocked(false);
9733    }
9734
9735    public int describeContents() {
9736        return 0;
9737    }
9738
9739    void readHistory(Parcel in, boolean andOldHistory) throws ParcelFormatException {
9740        final long historyBaseTime = in.readLong();
9741
9742        mHistoryBuffer.setDataSize(0);
9743        mHistoryBuffer.setDataPosition(0);
9744        mHistoryTagPool.clear();
9745        mNextHistoryTagIdx = 0;
9746        mNumHistoryTagChars = 0;
9747
9748        int numTags = in.readInt();
9749        for (int i=0; i<numTags; i++) {
9750            int idx = in.readInt();
9751            String str = in.readString();
9752            if (str == null) {
9753                throw new ParcelFormatException("null history tag string");
9754            }
9755            int uid = in.readInt();
9756            HistoryTag tag = new HistoryTag();
9757            tag.string = str;
9758            tag.uid = uid;
9759            tag.poolIdx = idx;
9760            mHistoryTagPool.put(tag, idx);
9761            if (idx >= mNextHistoryTagIdx) {
9762                mNextHistoryTagIdx = idx+1;
9763            }
9764            mNumHistoryTagChars += tag.string.length() + 1;
9765        }
9766
9767        int bufSize = in.readInt();
9768        int curPos = in.dataPosition();
9769        if (bufSize >= (MAX_MAX_HISTORY_BUFFER*3)) {
9770            throw new ParcelFormatException("File corrupt: history data buffer too large " +
9771                    bufSize);
9772        } else if ((bufSize&~3) != bufSize) {
9773            throw new ParcelFormatException("File corrupt: history data buffer not aligned " +
9774                    bufSize);
9775        } else {
9776            if (DEBUG_HISTORY) Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
9777                    + " bytes at " + curPos);
9778            mHistoryBuffer.appendFrom(in, curPos, bufSize);
9779            in.setDataPosition(curPos + bufSize);
9780        }
9781
9782        if (andOldHistory) {
9783            readOldHistory(in);
9784        }
9785
9786        if (DEBUG_HISTORY) {
9787            StringBuilder sb = new StringBuilder(128);
9788            sb.append("****************** OLD mHistoryBaseTime: ");
9789            TimeUtils.formatDuration(mHistoryBaseTime, sb);
9790            Slog.i(TAG, sb.toString());
9791        }
9792        mHistoryBaseTime = historyBaseTime;
9793        if (DEBUG_HISTORY) {
9794            StringBuilder sb = new StringBuilder(128);
9795            sb.append("****************** NEW mHistoryBaseTime: ");
9796            TimeUtils.formatDuration(mHistoryBaseTime, sb);
9797            Slog.i(TAG, sb.toString());
9798        }
9799
9800        // We are just arbitrarily going to insert 1 minute from the sample of
9801        // the last run until samples in this run.
9802        if (mHistoryBaseTime > 0) {
9803            long oldnow = mClocks.elapsedRealtime();
9804            mHistoryBaseTime = mHistoryBaseTime - oldnow + 1;
9805            if (DEBUG_HISTORY) {
9806                StringBuilder sb = new StringBuilder(128);
9807                sb.append("****************** ADJUSTED mHistoryBaseTime: ");
9808                TimeUtils.formatDuration(mHistoryBaseTime, sb);
9809                Slog.i(TAG, sb.toString());
9810            }
9811        }
9812    }
9813
9814    void readOldHistory(Parcel in) {
9815        if (!USE_OLD_HISTORY) {
9816            return;
9817        }
9818        mHistory = mHistoryEnd = mHistoryCache = null;
9819        long time;
9820        while (in.dataAvail() > 0 && (time=in.readLong()) >= 0) {
9821            HistoryItem rec = new HistoryItem(time, in);
9822            addHistoryRecordLocked(rec);
9823        }
9824    }
9825
9826    void writeHistory(Parcel out, boolean inclData, boolean andOldHistory) {
9827        if (DEBUG_HISTORY) {
9828            StringBuilder sb = new StringBuilder(128);
9829            sb.append("****************** WRITING mHistoryBaseTime: ");
9830            TimeUtils.formatDuration(mHistoryBaseTime, sb);
9831            sb.append(" mLastHistoryElapsedRealtime: ");
9832            TimeUtils.formatDuration(mLastHistoryElapsedRealtime, sb);
9833            Slog.i(TAG, sb.toString());
9834        }
9835        out.writeLong(mHistoryBaseTime + mLastHistoryElapsedRealtime);
9836        if (!inclData) {
9837            out.writeInt(0);
9838            out.writeInt(0);
9839            return;
9840        }
9841        out.writeInt(mHistoryTagPool.size());
9842        for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
9843            HistoryTag tag = ent.getKey();
9844            out.writeInt(ent.getValue());
9845            out.writeString(tag.string);
9846            out.writeInt(tag.uid);
9847        }
9848        out.writeInt(mHistoryBuffer.dataSize());
9849        if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
9850                + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
9851        out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
9852
9853        if (andOldHistory) {
9854            writeOldHistory(out);
9855        }
9856    }
9857
9858    void writeOldHistory(Parcel out) {
9859        if (!USE_OLD_HISTORY) {
9860            return;
9861        }
9862        HistoryItem rec = mHistory;
9863        while (rec != null) {
9864            if (rec.time >= 0) rec.writeToParcel(out, 0);
9865            rec = rec.next;
9866        }
9867        out.writeLong(-1);
9868    }
9869
9870    public void readSummaryFromParcel(Parcel in) throws ParcelFormatException {
9871        final int version = in.readInt();
9872        if (version != VERSION) {
9873            Slog.w("BatteryStats", "readFromParcel: version got " + version
9874                + ", expected " + VERSION + "; erasing old stats");
9875            return;
9876        }
9877
9878        readHistory(in, true);
9879
9880        mStartCount = in.readInt();
9881        mUptime = in.readLong();
9882        mRealtime = in.readLong();
9883        mStartClockTime = in.readLong();
9884        mStartPlatformVersion = in.readString();
9885        mEndPlatformVersion = in.readString();
9886        mOnBatteryTimeBase.readSummaryFromParcel(in);
9887        mOnBatteryScreenOffTimeBase.readSummaryFromParcel(in);
9888        mDischargeUnplugLevel = in.readInt();
9889        mDischargePlugLevel = in.readInt();
9890        mDischargeCurrentLevel = in.readInt();
9891        mCurrentBatteryLevel = in.readInt();
9892        mLowDischargeAmountSinceCharge = in.readInt();
9893        mHighDischargeAmountSinceCharge = in.readInt();
9894        mDischargeAmountScreenOnSinceCharge = in.readInt();
9895        mDischargeAmountScreenOffSinceCharge = in.readInt();
9896        mDischargeStepTracker.readFromParcel(in);
9897        mChargeStepTracker.readFromParcel(in);
9898        mDailyDischargeStepTracker.readFromParcel(in);
9899        mDailyChargeStepTracker.readFromParcel(in);
9900        int NPKG = in.readInt();
9901        if (NPKG > 0) {
9902            mDailyPackageChanges = new ArrayList<>(NPKG);
9903            while (NPKG > 0) {
9904                NPKG--;
9905                PackageChange pc = new PackageChange();
9906                pc.mPackageName = in.readString();
9907                pc.mUpdate = in.readInt() != 0;
9908                pc.mVersionCode = in.readInt();
9909                mDailyPackageChanges.add(pc);
9910            }
9911        } else {
9912            mDailyPackageChanges = null;
9913        }
9914        mDailyStartTime = in.readLong();
9915        mNextMinDailyDeadline = in.readLong();
9916        mNextMaxDailyDeadline = in.readLong();
9917
9918        mStartCount++;
9919
9920        mScreenState = Display.STATE_UNKNOWN;
9921        mScreenOnTimer.readSummaryFromParcelLocked(in);
9922        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
9923            mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
9924        }
9925        mInteractive = false;
9926        mInteractiveTimer.readSummaryFromParcelLocked(in);
9927        mPhoneOn = false;
9928        mPowerSaveModeEnabledTimer.readSummaryFromParcelLocked(in);
9929        mLongestLightIdleTime = in.readLong();
9930        mLongestFullIdleTime = in.readLong();
9931        mDeviceIdleModeLightTimer.readSummaryFromParcelLocked(in);
9932        mDeviceIdleModeFullTimer.readSummaryFromParcelLocked(in);
9933        mDeviceLightIdlingTimer.readSummaryFromParcelLocked(in);
9934        mDeviceIdlingTimer.readSummaryFromParcelLocked(in);
9935        mPhoneOnTimer.readSummaryFromParcelLocked(in);
9936        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
9937            mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
9938        }
9939        mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
9940        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
9941            mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
9942        }
9943        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
9944            mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
9945            mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
9946        }
9947        mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
9948        mMobileRadioActiveTimer.readSummaryFromParcelLocked(in);
9949        mMobileRadioActivePerAppTimer.readSummaryFromParcelLocked(in);
9950        mMobileRadioActiveAdjustedTime.readSummaryFromParcelLocked(in);
9951        mMobileRadioActiveUnknownTime.readSummaryFromParcelLocked(in);
9952        mMobileRadioActiveUnknownCount.readSummaryFromParcelLocked(in);
9953        mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
9954        mWifiOn = false;
9955        mWifiOnTimer.readSummaryFromParcelLocked(in);
9956        mGlobalWifiRunning = false;
9957        mGlobalWifiRunningTimer.readSummaryFromParcelLocked(in);
9958        for (int i=0; i<NUM_WIFI_STATES; i++) {
9959            mWifiStateTimer[i].readSummaryFromParcelLocked(in);
9960        }
9961        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
9962            mWifiSupplStateTimer[i].readSummaryFromParcelLocked(in);
9963        }
9964        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
9965            mWifiSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
9966        }
9967        mWifiActivity.readSummaryFromParcel(in);
9968        mBluetoothActivity.readSummaryFromParcel(in);
9969        mModemActivity.readSummaryFromParcel(in);
9970        mHasWifiReporting = in.readInt() != 0;
9971        mHasBluetoothReporting = in.readInt() != 0;
9972        mHasModemReporting = in.readInt() != 0;
9973
9974        mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt();
9975        mFlashlightOnNesting = 0;
9976        mFlashlightOnTimer.readSummaryFromParcelLocked(in);
9977        mCameraOnNesting = 0;
9978        mCameraOnTimer.readSummaryFromParcelLocked(in);
9979        mBluetoothScanNesting = 0;
9980        mBluetoothScanTimer.readSummaryFromParcelLocked(in);
9981
9982        int NKW = in.readInt();
9983        if (NKW > 10000) {
9984            throw new ParcelFormatException("File corrupt: too many kernel wake locks " + NKW);
9985        }
9986        for (int ikw = 0; ikw < NKW; ikw++) {
9987            if (in.readInt() != 0) {
9988                String kwltName = in.readString();
9989                getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
9990            }
9991        }
9992
9993        int NWR = in.readInt();
9994        if (NWR > 10000) {
9995            throw new ParcelFormatException("File corrupt: too many wakeup reasons " + NWR);
9996        }
9997        for (int iwr = 0; iwr < NWR; iwr++) {
9998            if (in.readInt() != 0) {
9999                String reasonName = in.readString();
10000                getWakeupReasonTimerLocked(reasonName).readSummaryFromParcelLocked(in);
10001            }
10002        }
10003
10004        final int NU = in.readInt();
10005        if (NU > 10000) {
10006            throw new ParcelFormatException("File corrupt: too many uids " + NU);
10007        }
10008        for (int iu = 0; iu < NU; iu++) {
10009            int uid = in.readInt();
10010            Uid u = new Uid(this, uid);
10011            mUidStats.put(uid, u);
10012
10013            u.mWifiRunning = false;
10014            if (in.readInt() != 0) {
10015                u.mWifiRunningTimer.readSummaryFromParcelLocked(in);
10016            }
10017            u.mFullWifiLockOut = false;
10018            if (in.readInt() != 0) {
10019                u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
10020            }
10021            u.mWifiScanStarted = false;
10022            if (in.readInt() != 0) {
10023                u.mWifiScanTimer.readSummaryFromParcelLocked(in);
10024            }
10025            u.mWifiBatchedScanBinStarted = Uid.NO_BATCHED_SCAN_STARTED;
10026            for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
10027                if (in.readInt() != 0) {
10028                    u.makeWifiBatchedScanBin(i, null);
10029                    u.mWifiBatchedScanTimer[i].readSummaryFromParcelLocked(in);
10030                }
10031            }
10032            u.mWifiMulticastEnabled = false;
10033            if (in.readInt() != 0) {
10034                u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
10035            }
10036            if (in.readInt() != 0) {
10037                u.createAudioTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
10038            }
10039            if (in.readInt() != 0) {
10040                u.createVideoTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
10041            }
10042            if (in.readInt() != 0) {
10043                u.createFlashlightTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
10044            }
10045            if (in.readInt() != 0) {
10046                u.createCameraTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
10047            }
10048            if (in.readInt() != 0) {
10049                u.createForegroundActivityTimerLocked().readSummaryFromParcelLocked(in);
10050            }
10051            if (in.readInt() != 0) {
10052                u.createBluetoothScanTimerLocked().readSummaryFromParcelLocked(in);
10053            }
10054            u.mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
10055            for (int i = 0; i < Uid.NUM_PROCESS_STATE; i++) {
10056                if (in.readInt() != 0) {
10057                    u.makeProcessState(i, null);
10058                    u.mProcessStateTimer[i].readSummaryFromParcelLocked(in);
10059                }
10060            }
10061            if (in.readInt() != 0) {
10062                u.createVibratorOnTimerLocked().readSummaryFromParcelLocked(in);
10063            }
10064
10065            if (in.readInt() != 0) {
10066                if (u.mUserActivityCounters == null) {
10067                    u.initUserActivityLocked();
10068                }
10069                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
10070                    u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
10071                }
10072            }
10073
10074            if (in.readInt() != 0) {
10075                if (u.mNetworkByteActivityCounters == null) {
10076                    u.initNetworkActivityLocked();
10077                }
10078                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
10079                    u.mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
10080                    u.mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
10081                }
10082                u.mMobileRadioActiveTime.readSummaryFromParcelLocked(in);
10083                u.mMobileRadioActiveCount.readSummaryFromParcelLocked(in);
10084            }
10085
10086            u.mUserCpuTime.readSummaryFromParcelLocked(in);
10087            u.mSystemCpuTime.readSummaryFromParcelLocked(in);
10088            u.mCpuPower.readSummaryFromParcelLocked(in);
10089
10090            if (in.readInt() != 0) {
10091                final int numClusters = in.readInt();
10092                if (mPowerProfile != null && mPowerProfile.getNumCpuClusters() != numClusters) {
10093                    throw new ParcelFormatException("Incompatible cpu cluster arrangement");
10094                }
10095
10096                u.mCpuClusterSpeed = new LongSamplingCounter[numClusters][];
10097                for (int cluster = 0; cluster < numClusters; cluster++) {
10098                    if (in.readInt() != 0) {
10099                        final int NSB = in.readInt();
10100                        if (mPowerProfile != null &&
10101                                mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != NSB) {
10102                            throw new ParcelFormatException("File corrupt: too many speed bins " +
10103                                    NSB);
10104                        }
10105
10106                        u.mCpuClusterSpeed[cluster] = new LongSamplingCounter[NSB];
10107                        for (int speed = 0; speed < NSB; speed++) {
10108                            if (in.readInt() != 0) {
10109                                u.mCpuClusterSpeed[cluster][speed] = new LongSamplingCounter(
10110                                        mOnBatteryTimeBase);
10111                                u.mCpuClusterSpeed[cluster][speed].readSummaryFromParcelLocked(in);
10112                            }
10113                        }
10114                    } else {
10115                        u.mCpuClusterSpeed[cluster] = null;
10116                    }
10117                }
10118            } else {
10119                u.mCpuClusterSpeed = null;
10120            }
10121
10122            int NW = in.readInt();
10123            if (NW > 100) {
10124                throw new ParcelFormatException("File corrupt: too many wake locks " + NW);
10125            }
10126            for (int iw = 0; iw < NW; iw++) {
10127                String wlName = in.readString();
10128                u.readWakeSummaryFromParcelLocked(wlName, in);
10129            }
10130
10131            int NS = in.readInt();
10132            if (NS > 100) {
10133                throw new ParcelFormatException("File corrupt: too many syncs " + NS);
10134            }
10135            for (int is = 0; is < NS; is++) {
10136                String name = in.readString();
10137                u.readSyncSummaryFromParcelLocked(name, in);
10138            }
10139
10140            int NJ = in.readInt();
10141            if (NJ > 100) {
10142                throw new ParcelFormatException("File corrupt: too many job timers " + NJ);
10143            }
10144            for (int ij = 0; ij < NJ; ij++) {
10145                String name = in.readString();
10146                u.readJobSummaryFromParcelLocked(name, in);
10147            }
10148
10149            int NP = in.readInt();
10150            if (NP > 1000) {
10151                throw new ParcelFormatException("File corrupt: too many sensors " + NP);
10152            }
10153            for (int is = 0; is < NP; is++) {
10154                int seNumber = in.readInt();
10155                if (in.readInt() != 0) {
10156                    u.getSensorTimerLocked(seNumber, true)
10157                            .readSummaryFromParcelLocked(in);
10158                }
10159            }
10160
10161            NP = in.readInt();
10162            if (NP > 1000) {
10163                throw new ParcelFormatException("File corrupt: too many processes " + NP);
10164            }
10165            for (int ip = 0; ip < NP; ip++) {
10166                String procName = in.readString();
10167                Uid.Proc p = u.getProcessStatsLocked(procName);
10168                p.mUserTime = p.mLoadedUserTime = in.readLong();
10169                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
10170                p.mForegroundTime = p.mLoadedForegroundTime = in.readLong();
10171                p.mStarts = p.mLoadedStarts = in.readInt();
10172                p.mNumCrashes = p.mLoadedNumCrashes = in.readInt();
10173                p.mNumAnrs = p.mLoadedNumAnrs = in.readInt();
10174                p.readExcessivePowerFromParcelLocked(in);
10175            }
10176
10177            NP = in.readInt();
10178            if (NP > 10000) {
10179                throw new ParcelFormatException("File corrupt: too many packages " + NP);
10180            }
10181            for (int ip = 0; ip < NP; ip++) {
10182                String pkgName = in.readString();
10183                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
10184                final int NWA = in.readInt();
10185                if (NWA > 1000) {
10186                    throw new ParcelFormatException("File corrupt: too many wakeup alarms " + NWA);
10187                }
10188                p.mWakeupAlarms.clear();
10189                for (int iwa=0; iwa<NWA; iwa++) {
10190                    String tag = in.readString();
10191                    Counter c = new Counter(mOnBatteryTimeBase);
10192                    c.readSummaryFromParcelLocked(in);
10193                    p.mWakeupAlarms.put(tag, c);
10194                }
10195                NS = in.readInt();
10196                if (NS > 1000) {
10197                    throw new ParcelFormatException("File corrupt: too many services " + NS);
10198                }
10199                for (int is = 0; is < NS; is++) {
10200                    String servName = in.readString();
10201                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
10202                    s.mStartTime = s.mLoadedStartTime = in.readLong();
10203                    s.mStarts = s.mLoadedStarts = in.readInt();
10204                    s.mLaunches = s.mLoadedLaunches = in.readInt();
10205                }
10206            }
10207        }
10208    }
10209
10210    /**
10211     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
10212     * disk.  This format does not allow a lossless round-trip.
10213     *
10214     * @param out the Parcel to be written to.
10215     */
10216    public void writeSummaryToParcel(Parcel out, boolean inclHistory) {
10217        pullPendingStateUpdatesLocked();
10218
10219        // Pull the clock time.  This may update the time and make a new history entry
10220        // if we had originally pulled a time before the RTC was set.
10221        long startClockTime = getStartClockTime();
10222
10223        final long NOW_SYS = mClocks.uptimeMillis() * 1000;
10224        final long NOWREAL_SYS = mClocks.elapsedRealtime() * 1000;
10225
10226        out.writeInt(VERSION);
10227
10228        writeHistory(out, inclHistory, true);
10229
10230        out.writeInt(mStartCount);
10231        out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
10232        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
10233        out.writeLong(startClockTime);
10234        out.writeString(mStartPlatformVersion);
10235        out.writeString(mEndPlatformVersion);
10236        mOnBatteryTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
10237        mOnBatteryScreenOffTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
10238        out.writeInt(mDischargeUnplugLevel);
10239        out.writeInt(mDischargePlugLevel);
10240        out.writeInt(mDischargeCurrentLevel);
10241        out.writeInt(mCurrentBatteryLevel);
10242        out.writeInt(getLowDischargeAmountSinceCharge());
10243        out.writeInt(getHighDischargeAmountSinceCharge());
10244        out.writeInt(getDischargeAmountScreenOnSinceCharge());
10245        out.writeInt(getDischargeAmountScreenOffSinceCharge());
10246        mDischargeStepTracker.writeToParcel(out);
10247        mChargeStepTracker.writeToParcel(out);
10248        mDailyDischargeStepTracker.writeToParcel(out);
10249        mDailyChargeStepTracker.writeToParcel(out);
10250        if (mDailyPackageChanges != null) {
10251            final int NPKG = mDailyPackageChanges.size();
10252            out.writeInt(NPKG);
10253            for (int i=0; i<NPKG; i++) {
10254                PackageChange pc = mDailyPackageChanges.get(i);
10255                out.writeString(pc.mPackageName);
10256                out.writeInt(pc.mUpdate ? 1 : 0);
10257                out.writeInt(pc.mVersionCode);
10258            }
10259        } else {
10260            out.writeInt(0);
10261        }
10262        out.writeLong(mDailyStartTime);
10263        out.writeLong(mNextMinDailyDeadline);
10264        out.writeLong(mNextMaxDailyDeadline);
10265
10266        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10267        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
10268            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10269        }
10270        mInteractiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10271        mPowerSaveModeEnabledTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10272        out.writeLong(mLongestLightIdleTime);
10273        out.writeLong(mLongestFullIdleTime);
10274        mDeviceIdleModeLightTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10275        mDeviceIdleModeFullTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10276        mDeviceLightIdlingTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10277        mDeviceIdlingTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10278        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10279        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
10280            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10281        }
10282        mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10283        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
10284            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10285        }
10286        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
10287            mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
10288            mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
10289        }
10290        mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10291        mMobileRadioActivePerAppTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10292        mMobileRadioActiveAdjustedTime.writeSummaryFromParcelLocked(out);
10293        mMobileRadioActiveUnknownTime.writeSummaryFromParcelLocked(out);
10294        mMobileRadioActiveUnknownCount.writeSummaryFromParcelLocked(out);
10295        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10296        mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10297        for (int i=0; i<NUM_WIFI_STATES; i++) {
10298            mWifiStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10299        }
10300        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
10301            mWifiSupplStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10302        }
10303        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
10304            mWifiSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10305        }
10306        mWifiActivity.writeSummaryToParcel(out);
10307        mBluetoothActivity.writeSummaryToParcel(out);
10308        mModemActivity.writeSummaryToParcel(out);
10309        out.writeInt(mHasWifiReporting ? 1 : 0);
10310        out.writeInt(mHasBluetoothReporting ? 1 : 0);
10311        out.writeInt(mHasModemReporting ? 1 : 0);
10312
10313        out.writeInt(mNumConnectivityChange);
10314        mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10315        mCameraOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10316        mBluetoothScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10317
10318        out.writeInt(mKernelWakelockStats.size());
10319        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
10320            Timer kwlt = ent.getValue();
10321            if (kwlt != null) {
10322                out.writeInt(1);
10323                out.writeString(ent.getKey());
10324                kwlt.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10325            } else {
10326                out.writeInt(0);
10327            }
10328        }
10329
10330        out.writeInt(mWakeupReasonStats.size());
10331        for (Map.Entry<String, SamplingTimer> ent : mWakeupReasonStats.entrySet()) {
10332            SamplingTimer timer = ent.getValue();
10333            if (timer != null) {
10334                out.writeInt(1);
10335                out.writeString(ent.getKey());
10336                timer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10337            } else {
10338                out.writeInt(0);
10339            }
10340        }
10341
10342        final int NU = mUidStats.size();
10343        out.writeInt(NU);
10344        for (int iu = 0; iu < NU; iu++) {
10345            out.writeInt(mUidStats.keyAt(iu));
10346            Uid u = mUidStats.valueAt(iu);
10347
10348            if (u.mWifiRunningTimer != null) {
10349                out.writeInt(1);
10350                u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10351            } else {
10352                out.writeInt(0);
10353            }
10354            if (u.mFullWifiLockTimer != null) {
10355                out.writeInt(1);
10356                u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10357            } else {
10358                out.writeInt(0);
10359            }
10360            if (u.mWifiScanTimer != null) {
10361                out.writeInt(1);
10362                u.mWifiScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10363            } else {
10364                out.writeInt(0);
10365            }
10366            for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
10367                if (u.mWifiBatchedScanTimer[i] != null) {
10368                    out.writeInt(1);
10369                    u.mWifiBatchedScanTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10370                } else {
10371                    out.writeInt(0);
10372                }
10373            }
10374            if (u.mWifiMulticastTimer != null) {
10375                out.writeInt(1);
10376                u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10377            } else {
10378                out.writeInt(0);
10379            }
10380            if (u.mAudioTurnedOnTimer != null) {
10381                out.writeInt(1);
10382                u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10383            } else {
10384                out.writeInt(0);
10385            }
10386            if (u.mVideoTurnedOnTimer != null) {
10387                out.writeInt(1);
10388                u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10389            } else {
10390                out.writeInt(0);
10391            }
10392            if (u.mFlashlightTurnedOnTimer != null) {
10393                out.writeInt(1);
10394                u.mFlashlightTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10395            } else {
10396                out.writeInt(0);
10397            }
10398            if (u.mCameraTurnedOnTimer != null) {
10399                out.writeInt(1);
10400                u.mCameraTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10401            } else {
10402                out.writeInt(0);
10403            }
10404            if (u.mForegroundActivityTimer != null) {
10405                out.writeInt(1);
10406                u.mForegroundActivityTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10407            } else {
10408                out.writeInt(0);
10409            }
10410            if (u.mBluetoothScanTimer != null) {
10411                out.writeInt(1);
10412                u.mBluetoothScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10413            } else {
10414                out.writeInt(0);
10415            }
10416            for (int i = 0; i < Uid.NUM_PROCESS_STATE; i++) {
10417                if (u.mProcessStateTimer[i] != null) {
10418                    out.writeInt(1);
10419                    u.mProcessStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10420                } else {
10421                    out.writeInt(0);
10422                }
10423            }
10424            if (u.mVibratorOnTimer != null) {
10425                out.writeInt(1);
10426                u.mVibratorOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10427            } else {
10428                out.writeInt(0);
10429            }
10430
10431            if (u.mUserActivityCounters == null) {
10432                out.writeInt(0);
10433            } else {
10434                out.writeInt(1);
10435                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
10436                    u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
10437                }
10438            }
10439
10440            if (u.mNetworkByteActivityCounters == null) {
10441                out.writeInt(0);
10442            } else {
10443                out.writeInt(1);
10444                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
10445                    u.mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
10446                    u.mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
10447                }
10448                u.mMobileRadioActiveTime.writeSummaryFromParcelLocked(out);
10449                u.mMobileRadioActiveCount.writeSummaryFromParcelLocked(out);
10450            }
10451
10452            u.mUserCpuTime.writeSummaryFromParcelLocked(out);
10453            u.mSystemCpuTime.writeSummaryFromParcelLocked(out);
10454            u.mCpuPower.writeSummaryFromParcelLocked(out);
10455
10456            if (u.mCpuClusterSpeed != null) {
10457                out.writeInt(1);
10458                out.writeInt(u.mCpuClusterSpeed.length);
10459                for (LongSamplingCounter[] cpuSpeeds : u.mCpuClusterSpeed) {
10460                    if (cpuSpeeds != null) {
10461                        out.writeInt(1);
10462                        out.writeInt(cpuSpeeds.length);
10463                        for (LongSamplingCounter c : cpuSpeeds) {
10464                            if (c != null) {
10465                                out.writeInt(1);
10466                                c.writeSummaryFromParcelLocked(out);
10467                            } else {
10468                                out.writeInt(0);
10469                            }
10470                        }
10471                    } else {
10472                        out.writeInt(0);
10473                    }
10474                }
10475            } else {
10476                out.writeInt(0);
10477            }
10478
10479            final ArrayMap<String, Uid.Wakelock> wakeStats = u.mWakelockStats.getMap();
10480            int NW = wakeStats.size();
10481            out.writeInt(NW);
10482            for (int iw=0; iw<NW; iw++) {
10483                out.writeString(wakeStats.keyAt(iw));
10484                Uid.Wakelock wl = wakeStats.valueAt(iw);
10485                if (wl.mTimerFull != null) {
10486                    out.writeInt(1);
10487                    wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10488                } else {
10489                    out.writeInt(0);
10490                }
10491                if (wl.mTimerPartial != null) {
10492                    out.writeInt(1);
10493                    wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10494                } else {
10495                    out.writeInt(0);
10496                }
10497                if (wl.mTimerWindow != null) {
10498                    out.writeInt(1);
10499                    wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10500                } else {
10501                    out.writeInt(0);
10502                }
10503                if (wl.mTimerDraw != null) {
10504                    out.writeInt(1);
10505                    wl.mTimerDraw.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10506                } else {
10507                    out.writeInt(0);
10508                }
10509            }
10510
10511            final ArrayMap<String, StopwatchTimer> syncStats = u.mSyncStats.getMap();
10512            int NS = syncStats.size();
10513            out.writeInt(NS);
10514            for (int is=0; is<NS; is++) {
10515                out.writeString(syncStats.keyAt(is));
10516                syncStats.valueAt(is).writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10517            }
10518
10519            final ArrayMap<String, StopwatchTimer> jobStats = u.mJobStats.getMap();
10520            int NJ = jobStats.size();
10521            out.writeInt(NJ);
10522            for (int ij=0; ij<NJ; ij++) {
10523                out.writeString(jobStats.keyAt(ij));
10524                jobStats.valueAt(ij).writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10525            }
10526
10527            int NSE = u.mSensorStats.size();
10528            out.writeInt(NSE);
10529            for (int ise=0; ise<NSE; ise++) {
10530                out.writeInt(u.mSensorStats.keyAt(ise));
10531                Uid.Sensor se = u.mSensorStats.valueAt(ise);
10532                if (se.mTimer != null) {
10533                    out.writeInt(1);
10534                    se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
10535                } else {
10536                    out.writeInt(0);
10537                }
10538            }
10539
10540            int NP = u.mProcessStats.size();
10541            out.writeInt(NP);
10542            for (int ip=0; ip<NP; ip++) {
10543                out.writeString(u.mProcessStats.keyAt(ip));
10544                Uid.Proc ps = u.mProcessStats.valueAt(ip);
10545                out.writeLong(ps.mUserTime);
10546                out.writeLong(ps.mSystemTime);
10547                out.writeLong(ps.mForegroundTime);
10548                out.writeInt(ps.mStarts);
10549                out.writeInt(ps.mNumCrashes);
10550                out.writeInt(ps.mNumAnrs);
10551                ps.writeExcessivePowerToParcelLocked(out);
10552            }
10553
10554            NP = u.mPackageStats.size();
10555            out.writeInt(NP);
10556            if (NP > 0) {
10557                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
10558                    : u.mPackageStats.entrySet()) {
10559                    out.writeString(ent.getKey());
10560                    Uid.Pkg ps = ent.getValue();
10561                    final int NWA = ps.mWakeupAlarms.size();
10562                    out.writeInt(NWA);
10563                    for (int iwa=0; iwa<NWA; iwa++) {
10564                        out.writeString(ps.mWakeupAlarms.keyAt(iwa));
10565                        ps.mWakeupAlarms.valueAt(iwa).writeSummaryFromParcelLocked(out);
10566                    }
10567                    NS = ps.mServiceStats.size();
10568                    out.writeInt(NS);
10569                    for (int is=0; is<NS; is++) {
10570                        out.writeString(ps.mServiceStats.keyAt(is));
10571                        BatteryStatsImpl.Uid.Pkg.Serv ss = ps.mServiceStats.valueAt(is);
10572                        long time = ss.getStartTimeToNowLocked(
10573                                mOnBatteryTimeBase.getUptime(NOW_SYS));
10574                        out.writeLong(time);
10575                        out.writeInt(ss.mStarts);
10576                        out.writeInt(ss.mLaunches);
10577                    }
10578                }
10579            }
10580        }
10581    }
10582
10583    public void readFromParcel(Parcel in) {
10584        readFromParcelLocked(in);
10585    }
10586
10587    void readFromParcelLocked(Parcel in) {
10588        int magic = in.readInt();
10589        if (magic != MAGIC) {
10590            throw new ParcelFormatException("Bad magic number: #" + Integer.toHexString(magic));
10591        }
10592
10593        readHistory(in, false);
10594
10595        mStartCount = in.readInt();
10596        mStartClockTime = in.readLong();
10597        mStartPlatformVersion = in.readString();
10598        mEndPlatformVersion = in.readString();
10599        mUptime = in.readLong();
10600        mUptimeStart = in.readLong();
10601        mRealtime = in.readLong();
10602        mRealtimeStart = in.readLong();
10603        mOnBattery = in.readInt() != 0;
10604        mOnBatteryInternal = false; // we are no longer really running.
10605        mOnBatteryTimeBase.readFromParcel(in);
10606        mOnBatteryScreenOffTimeBase.readFromParcel(in);
10607
10608        mScreenState = Display.STATE_UNKNOWN;
10609        mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase, in);
10610        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
10611            mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
10612                    mOnBatteryTimeBase, in);
10613        }
10614        mInteractive = false;
10615        mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase, in);
10616        mPhoneOn = false;
10617        mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
10618                mOnBatteryTimeBase, in);
10619        mLongestLightIdleTime = in.readLong();
10620        mLongestFullIdleTime = in.readLong();
10621        mDeviceIdleModeLightTimer = new StopwatchTimer(mClocks, null, -14, null,
10622                mOnBatteryTimeBase, in);
10623        mDeviceIdleModeFullTimer = new StopwatchTimer(mClocks, null, -11, null,
10624                mOnBatteryTimeBase, in);
10625        mDeviceLightIdlingTimer = new StopwatchTimer(mClocks, null, -15, null,
10626                mOnBatteryTimeBase, in);
10627        mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase, in);
10628        mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase, in);
10629        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
10630            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i,
10631                    null, mOnBatteryTimeBase, in);
10632        }
10633        mPhoneSignalScanningTimer = new StopwatchTimer(mClocks, null, -200+1, null,
10634                mOnBatteryTimeBase, in);
10635        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
10636            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClocks, null, -300-i,
10637                    null, mOnBatteryTimeBase, in);
10638        }
10639        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
10640            mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
10641            mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
10642        }
10643        mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
10644        mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null,
10645                mOnBatteryTimeBase, in);
10646        mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
10647                mOnBatteryTimeBase, in);
10648        mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
10649        mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
10650        mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
10651        mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
10652        mWifiOn = false;
10653        mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase, in);
10654        mGlobalWifiRunning = false;
10655        mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null,
10656                mOnBatteryTimeBase, in);
10657        for (int i=0; i<NUM_WIFI_STATES; i++) {
10658            mWifiStateTimer[i] = new StopwatchTimer(mClocks, null, -600-i,
10659                    null, mOnBatteryTimeBase, in);
10660        }
10661        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
10662            mWifiSupplStateTimer[i] = new StopwatchTimer(mClocks, null, -700-i,
10663                    null, mOnBatteryTimeBase, in);
10664        }
10665        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
10666            mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i,
10667                    null, mOnBatteryTimeBase, in);
10668        }
10669
10670        mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
10671                NUM_WIFI_TX_LEVELS, in);
10672        mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
10673                NUM_BT_TX_LEVELS, in);
10674        mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
10675                ModemActivityInfo.TX_POWER_LEVELS, in);
10676        mHasWifiReporting = in.readInt() != 0;
10677        mHasBluetoothReporting = in.readInt() != 0;
10678        mHasModemReporting = in.readInt() != 0;
10679
10680        mNumConnectivityChange = in.readInt();
10681        mLoadedNumConnectivityChange = in.readInt();
10682        mUnpluggedNumConnectivityChange = in.readInt();
10683        mAudioOnNesting = 0;
10684        mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
10685        mVideoOnNesting = 0;
10686        mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
10687        mFlashlightOnNesting = 0;
10688        mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase, in);
10689        mCameraOnNesting = 0;
10690        mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase, in);
10691        mBluetoothScanNesting = 0;
10692        mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase, in);
10693        mDischargeUnplugLevel = in.readInt();
10694        mDischargePlugLevel = in.readInt();
10695        mDischargeCurrentLevel = in.readInt();
10696        mCurrentBatteryLevel = in.readInt();
10697        mLowDischargeAmountSinceCharge = in.readInt();
10698        mHighDischargeAmountSinceCharge = in.readInt();
10699        mDischargeAmountScreenOn = in.readInt();
10700        mDischargeAmountScreenOnSinceCharge = in.readInt();
10701        mDischargeAmountScreenOff = in.readInt();
10702        mDischargeAmountScreenOffSinceCharge = in.readInt();
10703        mDischargeStepTracker.readFromParcel(in);
10704        mChargeStepTracker.readFromParcel(in);
10705        mLastWriteTime = in.readLong();
10706
10707        mKernelWakelockStats.clear();
10708        int NKW = in.readInt();
10709        for (int ikw = 0; ikw < NKW; ikw++) {
10710            if (in.readInt() != 0) {
10711                String wakelockName = in.readString();
10712                SamplingTimer kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase, in);
10713                mKernelWakelockStats.put(wakelockName, kwlt);
10714            }
10715        }
10716
10717        mWakeupReasonStats.clear();
10718        int NWR = in.readInt();
10719        for (int iwr = 0; iwr < NWR; iwr++) {
10720            if (in.readInt() != 0) {
10721                String reasonName = in.readString();
10722                SamplingTimer timer = new SamplingTimer(mClocks, mOnBatteryTimeBase, in);
10723                mWakeupReasonStats.put(reasonName, timer);
10724            }
10725        }
10726
10727        mPartialTimers.clear();
10728        mFullTimers.clear();
10729        mWindowTimers.clear();
10730        mWifiRunningTimers.clear();
10731        mFullWifiLockTimers.clear();
10732        mWifiScanTimers.clear();
10733        mWifiBatchedScanTimers.clear();
10734        mWifiMulticastTimers.clear();
10735        mAudioTurnedOnTimers.clear();
10736        mVideoTurnedOnTimers.clear();
10737        mFlashlightTurnedOnTimers.clear();
10738        mCameraTurnedOnTimers.clear();
10739
10740        int numUids = in.readInt();
10741        mUidStats.clear();
10742        for (int i = 0; i < numUids; i++) {
10743            int uid = in.readInt();
10744            Uid u = new Uid(this, uid);
10745            u.readFromParcelLocked(mOnBatteryTimeBase, mOnBatteryScreenOffTimeBase, in);
10746            mUidStats.append(uid, u);
10747        }
10748    }
10749
10750    public void writeToParcel(Parcel out, int flags) {
10751        writeToParcelLocked(out, true, flags);
10752    }
10753
10754    public void writeToParcelWithoutUids(Parcel out, int flags) {
10755        writeToParcelLocked(out, false, flags);
10756    }
10757
10758    @SuppressWarnings("unused")
10759    void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
10760        // Need to update with current kernel wake lock counts.
10761        pullPendingStateUpdatesLocked();
10762
10763        // Pull the clock time.  This may update the time and make a new history entry
10764        // if we had originally pulled a time before the RTC was set.
10765        long startClockTime = getStartClockTime();
10766
10767        final long uSecUptime = mClocks.uptimeMillis() * 1000;
10768        final long uSecRealtime = mClocks.elapsedRealtime() * 1000;
10769        final long batteryRealtime = mOnBatteryTimeBase.getRealtime(uSecRealtime);
10770        final long batteryScreenOffRealtime = mOnBatteryScreenOffTimeBase.getRealtime(uSecRealtime);
10771
10772        out.writeInt(MAGIC);
10773
10774        writeHistory(out, true, false);
10775
10776        out.writeInt(mStartCount);
10777        out.writeLong(startClockTime);
10778        out.writeString(mStartPlatformVersion);
10779        out.writeString(mEndPlatformVersion);
10780        out.writeLong(mUptime);
10781        out.writeLong(mUptimeStart);
10782        out.writeLong(mRealtime);
10783        out.writeLong(mRealtimeStart);
10784        out.writeInt(mOnBattery ? 1 : 0);
10785        mOnBatteryTimeBase.writeToParcel(out, uSecUptime, uSecRealtime);
10786        mOnBatteryScreenOffTimeBase.writeToParcel(out, uSecUptime, uSecRealtime);
10787
10788        mScreenOnTimer.writeToParcel(out, uSecRealtime);
10789        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
10790            mScreenBrightnessTimer[i].writeToParcel(out, uSecRealtime);
10791        }
10792        mInteractiveTimer.writeToParcel(out, uSecRealtime);
10793        mPowerSaveModeEnabledTimer.writeToParcel(out, uSecRealtime);
10794        out.writeLong(mLongestLightIdleTime);
10795        out.writeLong(mLongestFullIdleTime);
10796        mDeviceIdleModeLightTimer.writeToParcel(out, uSecRealtime);
10797        mDeviceIdleModeFullTimer.writeToParcel(out, uSecRealtime);
10798        mDeviceLightIdlingTimer.writeToParcel(out, uSecRealtime);
10799        mDeviceIdlingTimer.writeToParcel(out, uSecRealtime);
10800        mPhoneOnTimer.writeToParcel(out, uSecRealtime);
10801        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
10802            mPhoneSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
10803        }
10804        mPhoneSignalScanningTimer.writeToParcel(out, uSecRealtime);
10805        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
10806            mPhoneDataConnectionsTimer[i].writeToParcel(out, uSecRealtime);
10807        }
10808        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
10809            mNetworkByteActivityCounters[i].writeToParcel(out);
10810            mNetworkPacketActivityCounters[i].writeToParcel(out);
10811        }
10812        mMobileRadioActiveTimer.writeToParcel(out, uSecRealtime);
10813        mMobileRadioActivePerAppTimer.writeToParcel(out, uSecRealtime);
10814        mMobileRadioActiveAdjustedTime.writeToParcel(out);
10815        mMobileRadioActiveUnknownTime.writeToParcel(out);
10816        mMobileRadioActiveUnknownCount.writeToParcel(out);
10817        mWifiOnTimer.writeToParcel(out, uSecRealtime);
10818        mGlobalWifiRunningTimer.writeToParcel(out, uSecRealtime);
10819        for (int i=0; i<NUM_WIFI_STATES; i++) {
10820            mWifiStateTimer[i].writeToParcel(out, uSecRealtime);
10821        }
10822        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
10823            mWifiSupplStateTimer[i].writeToParcel(out, uSecRealtime);
10824        }
10825        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
10826            mWifiSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
10827        }
10828        mWifiActivity.writeToParcel(out, 0);
10829        mBluetoothActivity.writeToParcel(out, 0);
10830        mModemActivity.writeToParcel(out, 0);
10831        out.writeInt(mHasWifiReporting ? 1 : 0);
10832        out.writeInt(mHasBluetoothReporting ? 1 : 0);
10833        out.writeInt(mHasModemReporting ? 1 : 0);
10834
10835        out.writeInt(mNumConnectivityChange);
10836        out.writeInt(mLoadedNumConnectivityChange);
10837        out.writeInt(mUnpluggedNumConnectivityChange);
10838        mFlashlightOnTimer.writeToParcel(out, uSecRealtime);
10839        mCameraOnTimer.writeToParcel(out, uSecRealtime);
10840        mBluetoothScanTimer.writeToParcel(out, uSecRealtime);
10841        out.writeInt(mDischargeUnplugLevel);
10842        out.writeInt(mDischargePlugLevel);
10843        out.writeInt(mDischargeCurrentLevel);
10844        out.writeInt(mCurrentBatteryLevel);
10845        out.writeInt(mLowDischargeAmountSinceCharge);
10846        out.writeInt(mHighDischargeAmountSinceCharge);
10847        out.writeInt(mDischargeAmountScreenOn);
10848        out.writeInt(mDischargeAmountScreenOnSinceCharge);
10849        out.writeInt(mDischargeAmountScreenOff);
10850        out.writeInt(mDischargeAmountScreenOffSinceCharge);
10851        mDischargeStepTracker.writeToParcel(out);
10852        mChargeStepTracker.writeToParcel(out);
10853        out.writeLong(mLastWriteTime);
10854
10855        if (inclUids) {
10856            out.writeInt(mKernelWakelockStats.size());
10857            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
10858                SamplingTimer kwlt = ent.getValue();
10859                if (kwlt != null) {
10860                    out.writeInt(1);
10861                    out.writeString(ent.getKey());
10862                    kwlt.writeToParcel(out, uSecRealtime);
10863                } else {
10864                    out.writeInt(0);
10865                }
10866            }
10867            out.writeInt(mWakeupReasonStats.size());
10868            for (Map.Entry<String, SamplingTimer> ent : mWakeupReasonStats.entrySet()) {
10869                SamplingTimer timer = ent.getValue();
10870                if (timer != null) {
10871                    out.writeInt(1);
10872                    out.writeString(ent.getKey());
10873                    timer.writeToParcel(out, uSecRealtime);
10874                } else {
10875                    out.writeInt(0);
10876                }
10877            }
10878        } else {
10879            out.writeInt(0);
10880        }
10881
10882        if (inclUids) {
10883            int size = mUidStats.size();
10884            out.writeInt(size);
10885            for (int i = 0; i < size; i++) {
10886                out.writeInt(mUidStats.keyAt(i));
10887                Uid uid = mUidStats.valueAt(i);
10888
10889                uid.writeToParcelLocked(out, uSecRealtime);
10890            }
10891        } else {
10892            out.writeInt(0);
10893        }
10894    }
10895
10896    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
10897        new Parcelable.Creator<BatteryStatsImpl>() {
10898        public BatteryStatsImpl createFromParcel(Parcel in) {
10899            return new BatteryStatsImpl(in);
10900        }
10901
10902        public BatteryStatsImpl[] newArray(int size) {
10903            return new BatteryStatsImpl[size];
10904        }
10905    };
10906
10907    public void prepareForDumpLocked() {
10908        // Need to retrieve current kernel wake lock stats before printing.
10909        pullPendingStateUpdatesLocked();
10910
10911        // Pull the clock time.  This may update the time and make a new history entry
10912        // if we had originally pulled a time before the RTC was set.
10913        getStartClockTime();
10914    }
10915
10916    public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
10917        if (DEBUG) {
10918            pw.println("mOnBatteryTimeBase:");
10919            mOnBatteryTimeBase.dump(pw, "  ");
10920            pw.println("mOnBatteryScreenOffTimeBase:");
10921            mOnBatteryScreenOffTimeBase.dump(pw, "  ");
10922            Printer pr = new PrintWriterPrinter(pw);
10923            pr.println("*** Screen timer:");
10924            mScreenOnTimer.logState(pr, "  ");
10925            for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
10926                pr.println("*** Screen brightness #" + i + ":");
10927                mScreenBrightnessTimer[i].logState(pr, "  ");
10928            }
10929            pr.println("*** Interactive timer:");
10930            mInteractiveTimer.logState(pr, "  ");
10931            pr.println("*** Power save mode timer:");
10932            mPowerSaveModeEnabledTimer.logState(pr, "  ");
10933            pr.println("*** Device idle mode light timer:");
10934            mDeviceIdleModeLightTimer.logState(pr, "  ");
10935            pr.println("*** Device idle mode full timer:");
10936            mDeviceIdleModeFullTimer.logState(pr, "  ");
10937            pr.println("*** Device light idling timer:");
10938            mDeviceLightIdlingTimer.logState(pr, "  ");
10939            pr.println("*** Device idling timer:");
10940            mDeviceIdlingTimer.logState(pr, "  ");
10941            pr.println("*** Phone timer:");
10942            mPhoneOnTimer.logState(pr, "  ");
10943            for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
10944                pr.println("*** Phone signal strength #" + i + ":");
10945                mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
10946            }
10947            pr.println("*** Signal scanning :");
10948            mPhoneSignalScanningTimer.logState(pr, "  ");
10949            for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
10950                pr.println("*** Data connection type #" + i + ":");
10951                mPhoneDataConnectionsTimer[i].logState(pr, "  ");
10952            }
10953            pr.println("*** mMobileRadioPowerState=" + mMobileRadioPowerState);
10954            pr.println("*** Mobile network active timer:");
10955            mMobileRadioActiveTimer.logState(pr, "  ");
10956            pr.println("*** Mobile network active adjusted timer:");
10957            mMobileRadioActiveAdjustedTime.logState(pr, "  ");
10958            pr.println("*** mWifiRadioPowerState=" + mWifiRadioPowerState);
10959            pr.println("*** Wifi timer:");
10960            mWifiOnTimer.logState(pr, "  ");
10961            pr.println("*** WifiRunning timer:");
10962            mGlobalWifiRunningTimer.logState(pr, "  ");
10963            for (int i=0; i<NUM_WIFI_STATES; i++) {
10964                pr.println("*** Wifi state #" + i + ":");
10965                mWifiStateTimer[i].logState(pr, "  ");
10966            }
10967            for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
10968                pr.println("*** Wifi suppl state #" + i + ":");
10969                mWifiSupplStateTimer[i].logState(pr, "  ");
10970            }
10971            for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
10972                pr.println("*** Wifi signal strength #" + i + ":");
10973                mWifiSignalStrengthsTimer[i].logState(pr, "  ");
10974            }
10975            pr.println("*** Flashlight timer:");
10976            mFlashlightOnTimer.logState(pr, "  ");
10977            pr.println("*** Camera timer:");
10978            mCameraOnTimer.logState(pr, "  ");
10979        }
10980        super.dumpLocked(context, pw, flags, reqUid, histStart);
10981    }
10982}
10983