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