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