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