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