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