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