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