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