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