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