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