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