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