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