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