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