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