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