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