BatteryStatsImpl.java revision 3bee5af8162c177f8c8f4199489a401058ab26a9
1f933441648ef6a71dee783d733aac17b9508b452Andreas Huber/*
2f933441648ef6a71dee783d733aac17b9508b452Andreas Huber * Copyright (C) 2006-2007 The Android Open Source Project
3f933441648ef6a71dee783d733aac17b9508b452Andreas Huber *
4f933441648ef6a71dee783d733aac17b9508b452Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
5f933441648ef6a71dee783d733aac17b9508b452Andreas Huber * you may not use this file except in compliance with the License.
6f933441648ef6a71dee783d733aac17b9508b452Andreas Huber * You may obtain a copy of the License at
7f933441648ef6a71dee783d733aac17b9508b452Andreas Huber *
8f933441648ef6a71dee783d733aac17b9508b452Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
9f933441648ef6a71dee783d733aac17b9508b452Andreas Huber *
10f933441648ef6a71dee783d733aac17b9508b452Andreas Huber * Unless required by applicable law or agreed to in writing, software
11f933441648ef6a71dee783d733aac17b9508b452Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
12f933441648ef6a71dee783d733aac17b9508b452Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f933441648ef6a71dee783d733aac17b9508b452Andreas Huber * See the License for the specific language governing permissions and
14f933441648ef6a71dee783d733aac17b9508b452Andreas Huber * limitations under the License.
15f933441648ef6a71dee783d733aac17b9508b452Andreas Huber */
16f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
17f933441648ef6a71dee783d733aac17b9508b452Andreas Huberpackage com.android.internal.os;
18f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
19f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport com.android.internal.util.JournaledFile;
20f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
21f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport android.bluetooth.BluetoothHeadset;
225bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.net.TrafficStats;
235bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.os.BatteryManager;
24f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport android.os.BatteryStats;
2543c3e6ce02215ca99d506458f596cb1211639f29Andreas Huberimport android.os.Parcel;
26f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport android.os.ParcelFormatException;
275bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.os.Parcelable;
285bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.os.Process;
295bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.os.SystemClock;
305bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.telephony.ServiceState;
31f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport android.telephony.SignalStrength;
323831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huberimport android.telephony.TelephonyManager;
33f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport android.util.Log;
34f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport android.util.PrintWriterPrinter;
35f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport android.util.Printer;
36f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport android.util.Slog;
37f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport android.util.SparseArray;
38f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
39f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport java.io.BufferedReader;
401173118eace0e9e347cb007f0da817cee87579edGlenn Kastenimport java.io.File;
41f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport java.io.FileInputStream;
42f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport java.io.FileOutputStream;
43f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport java.io.FileReader;
44f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport java.io.IOException;
45f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport java.io.PrintWriter;
46f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport java.util.ArrayList;
479b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huberimport java.util.HashMap;
489b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huberimport java.util.Iterator;
49f933441648ef6a71dee783d733aac17b9508b452Andreas Huberimport java.util.Map;
505bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport java.util.concurrent.atomic.AtomicInteger;
511aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
52f933441648ef6a71dee783d733aac17b9508b452Andreas Huber/**
531aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber * All information we are collecting about things that can happen that impact
541aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber * battery life.  All times are represented in microseconds except where indicated
551aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber * otherwise.
56f933441648ef6a71dee783d733aac17b9508b452Andreas Huber */
57f933441648ef6a71dee783d733aac17b9508b452Andreas Huberpublic final class BatteryStatsImpl extends BatteryStats {
58f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private static final String TAG = "BatteryStatsImpl";
59f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private static final boolean DEBUG = false;
60f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private static final boolean DEBUG_HISTORY = false;
619b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber
629b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber    // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
639b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber    private static final int MAGIC = 0xBA757475; // 'BATSTATS'
649b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber
659b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber    // Current on-disk Parcel version
6643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    private static final int VERSION = 49;
6743c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber
68f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    // Maximum number of items we will record in the history.
69f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private static final int MAX_HISTORY_ITEMS = 1000;
70f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
71f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    // The maximum number of names wakelocks we will keep track of
72f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    // per uid; once the limit is reached, we batch the remaining wakelocks
735bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    // in to one common name.
745bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    private static final int MAX_WAKELOCKS_PER_UID = 20;
755bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
765bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    private static final String BATCHED_WAKELOCK_NAME = "*overflow*";
775bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
785bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    private static int sNumSpeedSteps;
795bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
80f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private final JournaledFile mFile;
819b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber
82f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    /**
83f933441648ef6a71dee783d733aac17b9508b452Andreas Huber     * The statistics we have collected organized by uids.
84f933441648ef6a71dee783d733aac17b9508b452Andreas Huber     */
85f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    final SparseArray<BatteryStatsImpl.Uid> mUidStats =
861173118eace0e9e347cb007f0da817cee87579edGlenn Kasten        new SparseArray<BatteryStatsImpl.Uid>();
871173118eace0e9e347cb007f0da817cee87579edGlenn Kasten
881173118eace0e9e347cb007f0da817cee87579edGlenn Kasten    // A set of pools of currently active timers.  When a timer is queried, we will divide the
891173118eace0e9e347cb007f0da817cee87579edGlenn Kasten    // elapsed time by the number of active timers to arrive at that timer's share of the time.
901173118eace0e9e347cb007f0da817cee87579edGlenn Kasten    // In order to do this, we must refresh each timer whenever the number of active timers
911173118eace0e9e347cb007f0da817cee87579edGlenn Kasten    // changes.
921173118eace0e9e347cb007f0da817cee87579edGlenn Kasten    final ArrayList<StopwatchTimer> mPartialTimers = new ArrayList<StopwatchTimer>();
931173118eace0e9e347cb007f0da817cee87579edGlenn Kasten    final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<StopwatchTimer>();
941173118eace0e9e347cb007f0da817cee87579edGlenn Kasten    final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<StopwatchTimer>();
951173118eace0e9e347cb007f0da817cee87579edGlenn Kasten    final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers
96f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            = new SparseArray<ArrayList<StopwatchTimer>>();
97f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
98f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    // These are the objects that will want to do something when the device
99f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    // is unplugged from power.
100f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    final ArrayList<Unpluggable> mUnpluggables = new ArrayList<Unpluggable>();
101f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
102f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    boolean mShuttingDown;
103f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
104f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    long mHistoryBaseTime;
105f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    boolean mHaveBatteryLevel = false;
106f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    boolean mRecordingHistory = true;
107f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    int mNumHistoryItems;
108f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    HistoryItem mHistory;
10943c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    HistoryItem mHistoryEnd;
110b408222bd9479c291874b607acae1425d6154fe7Andreas Huber    HistoryItem mHistoryCache;
11143c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    final HistoryItem mHistoryCur = new HistoryItem();
11243c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber
11343c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    int mStartCount;
114b408222bd9479c291874b607acae1425d6154fe7Andreas Huber
11543c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    long mBatteryUptime;
11643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    long mBatteryLastUptime;
1171aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    long mBatteryRealtime;
1181aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    long mBatteryLastRealtime;
1191aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
1201aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    long mUptime;
12143c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    long mUptimeStart;
12243c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    long mLastUptime;
12343c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    long mRealtime;
12443c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    long mRealtimeStart;
12543c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    long mLastRealtime;
12643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber
12753df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber    boolean mScreenOn;
1281aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    StopwatchTimer mScreenOnTimer;
12953df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber
13053df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber    int mScreenBrightnessBin = -1;
1311aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
1321aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
13353df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber    Counter mInputEventCounter;
13453df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber
13553df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber    boolean mPhoneOn;
1361aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    StopwatchTimer mPhoneOnTimer;
1371aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
1381aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    boolean mAudioOn;
13953df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber    StopwatchTimer mAudioOnTimer;
14053df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber
14153df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber    boolean mVideoOn;
14253df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber    StopwatchTimer mVideoOnTimer;
14353df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber
14453df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber    int mPhoneSignalStrengthBin = -1;
14553df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber    final StopwatchTimer[] mPhoneSignalStrengthsTimer =
14653df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber            new StopwatchTimer[NUM_SIGNAL_STRENGTH_BINS];
147f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
148f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    StopwatchTimer mPhoneSignalScanningTimer;
149f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
150f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    int mPhoneDataConnectionType = -1;
1511aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    final StopwatchTimer[] mPhoneDataConnectionsTimer =
152f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            new StopwatchTimer[NUM_DATA_CONNECTION_TYPES];
153f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
154f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    boolean mWifiOn;
1555bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    StopwatchTimer mWifiOnTimer;
1565bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    int mWifiOnUid = -1;
157f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
1585bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    boolean mWifiRunning;
159f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    StopwatchTimer mWifiRunningTimer;
160f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
161f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    boolean mBluetoothOn;
1621173118eace0e9e347cb007f0da817cee87579edGlenn Kasten    StopwatchTimer mBluetoothOnTimer;
163f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
1641173118eace0e9e347cb007f0da817cee87579edGlenn Kasten    /** Bluetooth headset object */
165f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    BluetoothHeadset mBtHeadset;
166f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
1671173118eace0e9e347cb007f0da817cee87579edGlenn Kasten    /**
168f933441648ef6a71dee783d733aac17b9508b452Andreas Huber     * These provide time bases that discount the time the device is plugged
1691173118eace0e9e347cb007f0da817cee87579edGlenn Kasten     * in to power.
170f933441648ef6a71dee783d733aac17b9508b452Andreas Huber     */
171f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    boolean mOnBattery;
172f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    boolean mOnBatteryInternal;
173f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    long mTrackBatteryPastUptime;
174f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    long mTrackBatteryUptimeStart;
1751aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    long mTrackBatteryPastRealtime;
176f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    long mTrackBatteryRealtimeStart;
177f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
178f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    long mUnpluggedBatteryUptime;
179f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    long mUnpluggedBatteryRealtime;
180f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
181f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    /*
182f933441648ef6a71dee783d733aac17b9508b452Andreas Huber     * These keep track of battery levels (1-100) at the last plug event and the last unplug event.
183f933441648ef6a71dee783d733aac17b9508b452Andreas Huber     */
184f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    int mDischargeStartLevel;
185f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    int mDischargeUnplugLevel;
18643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    int mDischargeCurrentLevel;
18743c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    int mLowDischargeAmountSinceCharge;
1881aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    int mHighDischargeAmountSinceCharge;
1891aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
19032f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber    long mLastWriteTime = 0; // Milliseconds
19132f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber
1921aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    // Mobile data transferred while on battery
1935bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    private long[] mMobileDataTx = new long[4];
194f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private long[] mMobileDataRx = new long[4];
195f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private long[] mTotalDataTx = new long[4];
196f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private long[] mTotalDataRx = new long[4];
197f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
198f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private long mRadioDataUptime;
199f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private long mRadioDataStart;
200f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
2011aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    private int mBluetoothPingCount;
202f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private int mBluetoothPingStart = -1;
203f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
204f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private int mPhoneServiceState = -1;
205f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
206f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    /*
2071aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber     * Holds a SamplingTimer associated with each kernel wakelock name being tracked.
2081aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber     */
2091aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    private final HashMap<String, SamplingTimer> mKernelWakelockStats =
2101aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            new HashMap<String, SamplingTimer>();
2111aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
2121aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    public Map<String, ? extends SamplingTimer> getKernelWakelockStats() {
2131aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        return mKernelWakelockStats;
2145bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    }
2155bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
21643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    private static int sKernelWakelockUpdateVersion = 0;
21743c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber
21843c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
2195bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        Process.PROC_TAB_TERM|Process.PROC_OUT_STRING,                // 0: name
220f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        Process.PROC_TAB_TERM|Process.PROC_OUT_LONG,                  // 1: count
221f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        Process.PROC_TAB_TERM,
2225bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        Process.PROC_TAB_TERM,
223f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        Process.PROC_TAB_TERM,
224f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        Process.PROC_TAB_TERM|Process.PROC_OUT_LONG,                  // 5: totalTime
2255bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    };
2261aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
2271aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    private final String[] mProcWakelocksName = new String[3];
2281aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    private final long[] mProcWakelocksData = new long[3];
2291aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
2301aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber    /*
231f933441648ef6a71dee783d733aac17b9508b452Andreas Huber     * Used as a buffer for reading in data from /proc/wakelocks before it is processed and added
232f933441648ef6a71dee783d733aac17b9508b452Andreas Huber     * to mKernelWakelockStats.
233f933441648ef6a71dee783d733aac17b9508b452Andreas Huber     */
234f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private final Map<String, KernelWakelockStats> mProcWakelockFileStats =
235f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            new HashMap<String, KernelWakelockStats>();
2365bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
237f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private HashMap<String, Integer> mUidCache = new HashMap<String, Integer>();
238f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
239f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    // For debugging
240f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    public BatteryStatsImpl() {
241f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        mFile = null;
242f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    }
243f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
244f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    public static interface Unpluggable {
245f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        void unplug(long batteryUptime, long batteryRealtime);
246f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        void plug(long batteryUptime, long batteryRealtime);
247f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    }
248f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
249f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    /**
250f933441648ef6a71dee783d733aac17b9508b452Andreas Huber     * State for keeping track of counting information.
251f933441648ef6a71dee783d733aac17b9508b452Andreas Huber     */
252f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    public static class Counter extends BatteryStats.Counter implements Unpluggable {
253f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        final AtomicInteger mCount = new AtomicInteger();
254f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        final ArrayList<Unpluggable> mUnpluggables;
255f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        int mLoadedCount;
2565bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        int mLastCount;
2575bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        int mUnpluggedCount;
2585bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        int mPluggedCount;
2595bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
260f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        Counter(ArrayList<Unpluggable> unpluggables, Parcel in) {
261f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mUnpluggables = unpluggables;
262f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mPluggedCount = in.readInt();
263f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mCount.set(mPluggedCount);
2641aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            mLoadedCount = in.readInt();
26553df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber            mLastCount = 0;
266f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mUnpluggedCount = in.readInt();
2671aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            unpluggables.add(this);
268f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
269f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
2701aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        Counter(ArrayList<Unpluggable> unpluggables) {
271f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mUnpluggables = unpluggables;
272f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            unpluggables.add(this);
273f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
2741aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
275f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        public void writeToParcel(Parcel out) {
2761aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            out.writeInt(mCount.get());
2771aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            out.writeInt(mLoadedCount);
27853df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber            out.writeInt(mUnpluggedCount);
279f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
28053df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber
281f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        public void unplug(long batteryUptime, long batteryRealtime) {
28253df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber            mUnpluggedCount = mPluggedCount;
28353df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber            mCount.set(mPluggedCount);
28453df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber        }
28553df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber
28653df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber        public void plug(long batteryUptime, long batteryRealtime) {
287f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mPluggedCount = mCount.get();
2883831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber        }
2893831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber
2902c2814b900a61fa07ddfff860b143fbbe9c740e9Andreas Huber        /**
29131e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber         * Writes a possibly null Counter to a Parcel.
29231e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber         *
29331e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber         * @param out the Parcel to be written to.
2942c2814b900a61fa07ddfff860b143fbbe9c740e9Andreas Huber         * @param counter a Counter, or null.
29531e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber         */
29631e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber        public static void writeCounterToParcel(Parcel out, Counter counter) {
2972c2814b900a61fa07ddfff860b143fbbe9c740e9Andreas Huber            if (counter == null) {
29831e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber                out.writeInt(0); // indicates null
29931e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber                return;
3002c2814b900a61fa07ddfff860b143fbbe9c740e9Andreas Huber            }
30131e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber            out.writeInt(1); // indicates non-null
30231e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber
30331e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber            counter.writeToParcel(out);
3043831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber        }
30531e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber
30631e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber        @Override
30731e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber        public int getCountLocked(int which) {
30831e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber            int val;
30931e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber            if (which == STATS_LAST) {
31031e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber                val = mLastCount;
31131e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber            } else {
31231e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber                val = mCount.get();
31331e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber                if (which == STATS_SINCE_UNPLUGGED) {
31431e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber                    val -= mUnpluggedCount;
31531e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber                } else if (which != STATS_SINCE_CHARGED) {
31631e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber                    val -= mLoadedCount;
31731e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber                }
31831e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber            }
31931e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber
32031e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber            return val;
32131e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber        }
32231e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber
32331e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber        public void logState(Printer pw, String prefix) {
32431e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber            pw.println(prefix + "mCount=" + mCount.get()
32531e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber                    + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
32631e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber                    + " mUnpluggedCount=" + mUnpluggedCount
32731e2508c75018145a8238925ff1a08cbde4e799aAndreas Huber                    + " mPluggedCount=" + mPluggedCount);
3283831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber        }
3291aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
3303831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber        void stepAtomic() {
3313831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            mCount.incrementAndGet();
3323831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber        }
3333831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber
3343831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber        /**
3353831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber         * Clear state of this counter.
3363831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber         */
3373831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber        void reset(boolean detachIfReset) {
3383831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            mCount.set(0);
3393831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            mLoadedCount = mLastCount = mPluggedCount = mUnpluggedCount = 0;
3403831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            if (detachIfReset) {
3413831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber                detach();
3423831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            }
343f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
344f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
345f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        void detach() {
346f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mUnpluggables.remove(this);
347f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
348f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
349f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        void writeSummaryFromParcelLocked(Parcel out) {
350f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            int count = mCount.get();
351f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            out.writeInt(count);
352f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
353f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
354f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        void readSummaryFromParcelLocked(Parcel in) {
355f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mLoadedCount = in.readInt();
356f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mCount.set(mLoadedCount);
357f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mLastCount = 0;
358f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mUnpluggedCount = mPluggedCount = mLoadedCount;
359f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
360f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    }
361f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
362f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    public static class SamplingCounter extends Counter {
363f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
364f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        SamplingCounter(ArrayList<Unpluggable> unpluggables, Parcel in) {
365f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            super(unpluggables, in);
366f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
3671aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
368f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        SamplingCounter(ArrayList<Unpluggable> unpluggables) {
369f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            super(unpluggables);
370f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
371f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
372f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        public void addCountAtomic(long count) {
37343c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            mCount.addAndGet((int)count);
37443c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber        }
37543c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    }
37643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber
37743c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    /**
37843c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber     * State for keeping track of timing information.
37943c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber     */
38043c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber    public static abstract class Timer extends BatteryStats.Timer implements Unpluggable {
38143c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber        final int mType;
38243c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber        final ArrayList<Unpluggable> mUnpluggables;
383f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
384f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        int mCount;
385f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        int mLoadedCount;
386f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        int mLastCount;
387f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        int mUnpluggedCount;
388f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
3891aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        // Times are in microseconds for better accuracy when dividing by the
390f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        // lock count, and are in "battery realtime" units.
391f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
392f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        /**
393f933441648ef6a71dee783d733aac17b9508b452Andreas Huber         * The total time we have accumulated since the start of the original
394f933441648ef6a71dee783d733aac17b9508b452Andreas Huber         * boot, to the last time something interesting happened in the
395f933441648ef6a71dee783d733aac17b9508b452Andreas Huber         * current run.
396f933441648ef6a71dee783d733aac17b9508b452Andreas Huber         */
397f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        long mTotalTime;
398f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
3991aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        /**
4001aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * The total time we loaded for the previous runs.  Subtract this from
4011aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * mTotalTime to find the time for the current run of the system.
4021aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         */
4031aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        long mLoadedTime;
4041aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
4051aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        /**
4061aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * The run time of the last run of the system, as loaded from the
4071aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * saved data.
4081aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         */
4091aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        long mLastTime;
4101aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
4111aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        /**
4121aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * The value of mTotalTime when unplug() was last called.  Subtract
4131aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * this from mTotalTime to find the time since the last unplug from
4141aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * power.
4151aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         */
4161aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        long mUnpluggedTime;
4171aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
4181aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        /**
4191aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * Constructs from a parcel.
4201aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * @param type
4211aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * @param unpluggables
4221aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * @param powerType
4231aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * @param in
4241aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         */
4251aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        Timer(int type, ArrayList<Unpluggable> unpluggables, Parcel in) {
4261aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            mType = type;
4271aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            mUnpluggables = unpluggables;
4281aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
4291aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            mCount = in.readInt();
43043c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            mLoadedCount = in.readInt();
43143c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            mLastCount = 0;
43243c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            mUnpluggedCount = in.readInt();
43343c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            mTotalTime = in.readLong();
43443c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            mLoadedTime = in.readLong();
43522fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber            mLastTime = 0;
43643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            mUnpluggedTime = in.readLong();
43743c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            unpluggables.add(this);
43843c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber        }
43943c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber
44043c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber        Timer(int type, ArrayList<Unpluggable> unpluggables) {
44143c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            mType = type;
44243c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            mUnpluggables = unpluggables;
44343c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            unpluggables.add(this);
44443c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber        }
44543c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber
44643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber        protected abstract long computeRunTimeLocked(long curBatteryRealtime);
44743c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber
44843c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber        protected abstract int computeCurrentCountLocked();
44943c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber
450b408222bd9479c291874b607acae1425d6154fe7Andreas Huber        /**
451b408222bd9479c291874b607acae1425d6154fe7Andreas Huber         * Clear state of this timer.  Returns true if the timer is inactive
452b408222bd9479c291874b607acae1425d6154fe7Andreas Huber         * so can be completely dropped.
453b408222bd9479c291874b607acae1425d6154fe7Andreas Huber         */
454b408222bd9479c291874b607acae1425d6154fe7Andreas Huber        boolean reset(boolean detachIfReset) {
455b408222bd9479c291874b607acae1425d6154fe7Andreas Huber            mTotalTime = mLoadedTime = mLastTime = 0;
456b408222bd9479c291874b607acae1425d6154fe7Andreas Huber            mCount = mLoadedCount = mLastCount = 0;
457b408222bd9479c291874b607acae1425d6154fe7Andreas Huber            if (detachIfReset) {
458b408222bd9479c291874b607acae1425d6154fe7Andreas Huber                detach();
459b408222bd9479c291874b607acae1425d6154fe7Andreas Huber            }
460b408222bd9479c291874b607acae1425d6154fe7Andreas Huber            return true;
461b408222bd9479c291874b607acae1425d6154fe7Andreas Huber        }
462b408222bd9479c291874b607acae1425d6154fe7Andreas Huber
463b408222bd9479c291874b607acae1425d6154fe7Andreas Huber        void detach() {
464f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mUnpluggables.remove(this);
465f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
466f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
467f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        public void writeToParcel(Parcel out, long batteryRealtime) {
468f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            out.writeInt(mCount);
469f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            out.writeInt(mLoadedCount);
4703831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            out.writeInt(mUnpluggedCount);
4713831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            out.writeLong(computeRunTimeLocked(batteryRealtime));
4723831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            out.writeLong(mLoadedTime);
4733831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            out.writeLong(mUnpluggedTime);
4743831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber        }
4753831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber
4763831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber        public void unplug(long batteryUptime, long batteryRealtime) {
4773831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            if (DEBUG && mType < 0) {
4783831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber                Log.v(TAG, "unplug #" + mType + ": realtime=" + batteryRealtime
4791aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                        + " old mUnpluggedTime=" + mUnpluggedTime
4803831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber                        + " old mUnpluggedCount=" + mUnpluggedCount);
4813831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            }
4823831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            mUnpluggedTime = computeRunTimeLocked(batteryRealtime);
48322fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber            mUnpluggedCount = mCount;
4843831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            if (DEBUG && mType < 0) {
4853831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber                Log.v(TAG, "unplug #" + mType
4863831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber                        + ": new mUnpluggedTime=" + mUnpluggedTime
48722fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber                        + " new mUnpluggedCount=" + mUnpluggedCount);
4883831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            }
4893831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber        }
4903831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber
4913831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber        public void plug(long batteryUptime, long batteryRealtime) {
4923831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber            if (DEBUG && mType < 0) {
493f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime
4941aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                        + " old mTotalTime=" + mTotalTime);
4951aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            }
4961aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            mTotalTime = computeRunTimeLocked(batteryRealtime);
4971aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            mCount = computeCurrentCountLocked();
4981aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            if (DEBUG && mType < 0) {
4991aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                Log.v(TAG, "plug #" + mType
5001aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                        + ": new mTotalTime=" + mTotalTime);
5011aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            }
50222fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber        }
5031aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
5041aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        /**
5051aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * Writes a possibly null Timer to a Parcel.
5061aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         *
5071aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * @param out the Parcel to be written to.
5081aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         * @param timer a Timer, or null.
5091aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber         */
5101aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        public static void writeTimerToParcel(Parcel out, Timer timer,
5111aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                long batteryRealtime) {
5121aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            if (timer == null) {
5131aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                out.writeInt(0); // indicates null
51443c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber                return;
51543c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            }
51643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            out.writeInt(1); // indicates non-null
51743c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber
51843c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            timer.writeToParcel(out, batteryRealtime);
51943c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber        }
5201aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
5211aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        @Override
5221aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        public long getTotalTimeLocked(long batteryRealtime, int which) {
5231aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            long val;
5241aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            if (which == STATS_LAST) {
525f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                val = mLastTime;
5261aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            } else {
5271aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                val = computeRunTimeLocked(batteryRealtime);
5281aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                if (which == STATS_SINCE_UNPLUGGED) {
5291aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                    val -= mUnpluggedTime;
5301aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                } else if (which != STATS_SINCE_CHARGED) {
5311aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                    val -= mLoadedTime;
532f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                }
533f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            }
5345bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
535f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            return val;
536f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
537f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
538f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        @Override
5395bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        public int getCountLocked(int which) {
540f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            int val;
5415bc087c573c70c84c6a39946457590b42d392a33Andreas Huber            if (which == STATS_LAST) {
542f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                val = mLastCount;
543f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            } else {
544f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                val = computeCurrentCountLocked();
545f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                if (which == STATS_SINCE_UNPLUGGED) {
546f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                    val -= mUnpluggedCount;
547f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                } else if (which != STATS_SINCE_CHARGED) {
548f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                    val -= mLoadedCount;
5491173118eace0e9e347cb007f0da817cee87579edGlenn Kasten                }
5501173118eace0e9e347cb007f0da817cee87579edGlenn Kasten            }
551f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
552f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            return val;
5535bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        }
554f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
55543c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber        public void logState(Printer pw, String prefix) {
55643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            pw.println(prefix + " mCount=" + mCount
55743c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber                    + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
55843c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber                    + " mUnpluggedCount=" + mUnpluggedCount);
55943c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            pw.println(prefix + "mTotalTime=" + mTotalTime
56043c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber                    + " mLoadedTime=" + mLoadedTime);
56143c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            pw.println(prefix + "mLastTime=" + mLastTime
56243c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber                    + " mUnpluggedTime=" + mUnpluggedTime);
563f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
564f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
565f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
566f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
567f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            long runTime = computeRunTimeLocked(batteryRealtime);
568f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            // Divide by 1000 for backwards compatibility
569f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            out.writeLong((runTime + 500) / 1000);
57053df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber            out.writeInt(mCount);
57153df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber        }
572f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
573f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        void readSummaryFromParcelLocked(Parcel in) {
574f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            // Multiply by 1000 for backwards compatibility
575f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mTotalTime = mLoadedTime = in.readLong() * 1000;
576f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mLastTime = 0;
577f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mUnpluggedTime = mTotalTime;
5785bc087c573c70c84c6a39946457590b42d392a33Andreas Huber            mCount = mLoadedCount = in.readInt();
579f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mLastCount = 0;
580f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mUnpluggedCount = mCount;
581f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
582f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    }
583f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
5845bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    public static final class SamplingTimer extends Timer {
5855bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
5865bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        /**
5875bc087c573c70c84c6a39946457590b42d392a33Andreas Huber         * The most recent reported count from /proc/wakelocks.
5885bc087c573c70c84c6a39946457590b42d392a33Andreas Huber         */
58953df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber        int mCurrentReportedCount;
5901aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
59153df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber        /**
59253df1a460bcfdd129ca2bc416dee2009e35c042eAndreas Huber         * The reported count from /proc/wakelocks when unplug() was last
59332f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber         * called.
59432f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber         */
59532f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        int mUnpluggedReportedCount;
59632f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber
59732f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        /**
59832f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber         * The most recent reported total_time from /proc/wakelocks.
59932f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber         */
60032f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        long mCurrentReportedTotalTime;
60132f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber
60232f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber
60332f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        /**
60432f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber         * The reported total_time from /proc/wakelocks when unplug() was last
60532f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber         * called.
60632f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber         */
60732f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        long mUnpluggedReportedTotalTime;
60832f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber
60932f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        /**
61032f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber         * Whether we are currently in a discharge cycle.
61132f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber         */
61232f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        boolean mInDischarge;
61332f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber
61432f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        /**
61532f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber         * Whether we are currently recording reported values.
61632f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber         */
61732f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        boolean mTrackingReportedValues;
6181aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
619f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        /*
620f933441648ef6a71dee783d733aac17b9508b452Andreas Huber         * A sequnce counter, incremented once for each update of the stats.
621f933441648ef6a71dee783d733aac17b9508b452Andreas Huber         */
622f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        int mUpdateVersion;
623f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
624f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge, Parcel in) {
625f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            super(0, unpluggables, in);
62643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            mCurrentReportedCount = in.readInt();
627f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mUnpluggedReportedCount = in.readInt();
628f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mCurrentReportedTotalTime = in.readLong();
629f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mUnpluggedReportedTotalTime = in.readLong();
630f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mTrackingReportedValues = in.readInt() == 1;
6311aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            mInDischarge = inDischarge;
632f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
633f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
634f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge,
635f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                boolean trackReportedValues) {
636f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            super(0, unpluggables);
637f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mTrackingReportedValues = trackReportedValues;
638f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mInDischarge = inDischarge;
639f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
640f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
641f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        public void setStale() {
642f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mTrackingReportedValues = false;
64343c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber            mUnpluggedReportedTotalTime = 0;
644f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mUnpluggedReportedCount = 0;
645f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
646f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
647f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        public void setUpdateVersion(int version) {
648f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mUpdateVersion = version;
649f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
650f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
651f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        public int getUpdateVersion() {
652f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            return mUpdateVersion;
65332f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        }
65432f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber
65532f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        public void updateCurrentReportedCount(int count) {
65632f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber            if (mInDischarge && mUnpluggedReportedCount == 0) {
65732f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber                // Updating the reported value for the first time.
65832f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber                mUnpluggedReportedCount = count;
65932f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber                // If we are receiving an update update mTrackingReportedValues;
66032f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber                mTrackingReportedValues = true;
66132f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber            }
66232f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber            mCurrentReportedCount = count;
66332f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        }
66432f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber
66532f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        public void updateCurrentReportedTotalTime(long totalTime) {
66632f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber            if (mInDischarge && mUnpluggedReportedTotalTime == 0) {
66732f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber                // Updating the reported value for the first time.
66832f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber                mUnpluggedReportedTotalTime = totalTime;
66932f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber                // If we are receiving an update update mTrackingReportedValues;
67032f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber                mTrackingReportedValues = true;
67132f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber            }
67232f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber            mCurrentReportedTotalTime = totalTime;
67332f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        }
674f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
675f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        public void unplug(long batteryUptime, long batteryRealtime) {
676f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            super.unplug(batteryUptime, batteryRealtime);
677f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            if (mTrackingReportedValues) {
67843c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber                mUnpluggedReportedTotalTime = mCurrentReportedTotalTime;
679f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                mUnpluggedReportedCount = mCurrentReportedCount;
680f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            }
681f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mInDischarge = true;
68243c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber        }
683f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
68443c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber        public void plug(long batteryUptime, long batteryRealtime) {
685f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            super.plug(batteryUptime, batteryRealtime);
686f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mInDischarge = false;
687f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
68843c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber
689f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        public void logState(Printer pw, String prefix) {
690f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            super.logState(pw, prefix);
6911aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount
6921aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                    + " mUnpluggedReportedCount=" + mUnpluggedReportedCount
6931aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                    + " mCurrentReportedTotalTime=" + mCurrentReportedTotalTime
69443c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber                    + " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTime);
6951aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        }
6961aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
6971aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        protected long computeRunTimeLocked(long curBatteryRealtime) {
6981aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            return mTotalTime + (mInDischarge && mTrackingReportedValues
6991aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                    ? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0);
7001aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        }
7011aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
7021aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        protected int computeCurrentCountLocked() {
7031aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            return mCount + (mInDischarge && mTrackingReportedValues
7041aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber                    ? mCurrentReportedCount - mUnpluggedReportedCount : 0);
7051aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        }
7061aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
7071aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        public void writeToParcel(Parcel out, long batteryRealtime) {
7081aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            super.writeToParcel(out, batteryRealtime);
7091aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            out.writeInt(mCurrentReportedCount);
7101aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            out.writeInt(mUnpluggedReportedCount);
7111aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            out.writeLong(mCurrentReportedTotalTime);
7121aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            out.writeLong(mUnpluggedReportedTotalTime);
7131aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            out.writeInt(mTrackingReportedValues ? 1 : 0);
7141aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        }
7151aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
7161aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        boolean reset(boolean detachIfReset) {
7171aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            super.reset(detachIfReset);
7181aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            setStale();
7191aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            return true;
7201aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        }
7211aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber
7221aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber        void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
7231aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            super.writeSummaryFromParcelLocked(out, batteryRealtime);
7241aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            out.writeLong(mCurrentReportedTotalTime);
7251aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            out.writeInt(mCurrentReportedCount);
7261aef211b4e5dc952081727bfd2318b2cb5ca4506Andreas Huber            out.writeInt(mTrackingReportedValues ? 1 : 0);
727f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
728
729        void readSummaryFromParcelLocked(Parcel in) {
730            super.readSummaryFromParcelLocked(in);
731            mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong();
732            mUnpluggedReportedCount = mCurrentReportedCount = in.readInt();
733            mTrackingReportedValues = in.readInt() == 1;
734        }
735    }
736
737    /**
738     * State for keeping track of timing information.
739     */
740    public static final class StopwatchTimer extends Timer {
741        final ArrayList<StopwatchTimer> mTimerPool;
742        int mNesting;
743
744        /**
745         * The last time at which we updated the timer.  If mNesting is > 0,
746         * subtract this from the current battery time to find the amount of
747         * time we have been running since we last computed an update.
748         */
749        long mUpdateTime;
750
751        /**
752         * The total time at which the timer was acquired, to determine if
753         * was actually held for an interesting duration.
754         */
755        long mAcquireTime;
756
757        long mTimeout;
758
759        StopwatchTimer(int type, ArrayList<StopwatchTimer> timerPool,
760                ArrayList<Unpluggable> unpluggables, Parcel in) {
761            super(type, unpluggables, in);
762            mTimerPool = timerPool;
763            mUpdateTime = in.readLong();
764        }
765
766        StopwatchTimer(int type, ArrayList<StopwatchTimer> timerPool,
767                ArrayList<Unpluggable> unpluggables) {
768            super(type, unpluggables);
769            mTimerPool = timerPool;
770        }
771
772        void setTimeout(long timeout) {
773            mTimeout = timeout;
774        }
775
776        public void writeToParcel(Parcel out, long batteryRealtime) {
777            super.writeToParcel(out, batteryRealtime);
778            out.writeLong(mUpdateTime);
779        }
780
781        public void plug(long batteryUptime, long batteryRealtime) {
782            if (mNesting > 0) {
783                if (DEBUG && mType < 0) {
784                    Log.v(TAG, "old mUpdateTime=" + mUpdateTime);
785                }
786                super.plug(batteryUptime, batteryRealtime);
787                mUpdateTime = batteryRealtime;
788                if (DEBUG && mType < 0) {
789                    Log.v(TAG, "new mUpdateTime=" + mUpdateTime);
790                }
791            }
792        }
793
794        public void logState(Printer pw, String prefix) {
795            super.logState(pw, prefix);
796            pw.println(prefix + "mNesting=" + mNesting + "mUpdateTime=" + mUpdateTime
797                    + " mAcquireTime=" + mAcquireTime);
798        }
799
800        void startRunningLocked(BatteryStatsImpl stats) {
801            if (mNesting++ == 0) {
802                mUpdateTime = stats.getBatteryRealtimeLocked(
803                        SystemClock.elapsedRealtime() * 1000);
804                if (mTimerPool != null) {
805                    // Accumulate time to all currently active timers before adding
806                    // this new one to the pool.
807                    refreshTimersLocked(stats, mTimerPool);
808                    // Add this timer to the active pool
809                    mTimerPool.add(this);
810                }
811                // Increment the count
812                mCount++;
813                mAcquireTime = mTotalTime;
814                if (DEBUG && mType < 0) {
815                    Log.v(TAG, "start #" + mType + ": mUpdateTime=" + mUpdateTime
816                            + " mTotalTime=" + mTotalTime + " mCount=" + mCount
817                            + " mAcquireTime=" + mAcquireTime);
818                }
819            }
820        }
821
822        boolean isRunningLocked() {
823            return mNesting > 0;
824        }
825
826        void stopRunningLocked(BatteryStatsImpl stats) {
827            // Ignore attempt to stop a timer that isn't running
828            if (mNesting == 0) {
829                return;
830            }
831            if (--mNesting == 0) {
832                if (mTimerPool != null) {
833                    // Accumulate time to all active counters, scaled by the total
834                    // active in the pool, before taking this one out of the pool.
835                    refreshTimersLocked(stats, mTimerPool);
836                    // Remove this timer from the active pool
837                    mTimerPool.remove(this);
838                } else {
839                    final long realtime = SystemClock.elapsedRealtime() * 1000;
840                    final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
841                    mNesting = 1;
842                    mTotalTime = computeRunTimeLocked(batteryRealtime);
843                    mNesting = 0;
844                }
845
846                if (DEBUG && mType < 0) {
847                    Log.v(TAG, "stop #" + mType + ": mUpdateTime=" + mUpdateTime
848                            + " mTotalTime=" + mTotalTime + " mCount=" + mCount
849                            + " mAcquireTime=" + mAcquireTime);
850                }
851
852                if (mTotalTime == mAcquireTime) {
853                    // If there was no change in the time, then discard this
854                    // count.  A somewhat cheezy strategy, but hey.
855                    mCount--;
856                }
857            }
858        }
859
860        // Update the total time for all other running Timers with the same type as this Timer
861        // due to a change in timer count
862        private static void refreshTimersLocked(final BatteryStatsImpl stats,
863                final ArrayList<StopwatchTimer> pool) {
864            final long realtime = SystemClock.elapsedRealtime() * 1000;
865            final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
866            final int N = pool.size();
867            for (int i=N-1; i>= 0; i--) {
868                final StopwatchTimer t = pool.get(i);
869                long heldTime = batteryRealtime - t.mUpdateTime;
870                if (heldTime > 0) {
871                    t.mTotalTime += heldTime / N;
872                }
873                t.mUpdateTime = batteryRealtime;
874            }
875        }
876
877        @Override
878        protected long computeRunTimeLocked(long curBatteryRealtime) {
879            if (mTimeout > 0 && curBatteryRealtime > mUpdateTime + mTimeout) {
880                curBatteryRealtime = mUpdateTime + mTimeout;
881            }
882            return mTotalTime + (mNesting > 0
883                    ? (curBatteryRealtime - mUpdateTime)
884                            / (mTimerPool != null ? mTimerPool.size() : 1)
885                    : 0);
886        }
887
888        @Override
889        protected int computeCurrentCountLocked() {
890            return mCount;
891        }
892
893        boolean reset(boolean detachIfReset) {
894            boolean canDetach = mNesting <= 0;
895            super.reset(canDetach && detachIfReset);
896            return canDetach;
897        }
898
899        void detach() {
900            super.detach();
901            if (mTimerPool != null) {
902                mTimerPool.remove(this);
903            }
904        }
905
906        void readSummaryFromParcelLocked(Parcel in) {
907            super.readSummaryFromParcelLocked(in);
908            mNesting = 0;
909        }
910    }
911
912    private final Map<String, KernelWakelockStats> readKernelWakelockStats() {
913
914        byte[] buffer = new byte[4096];
915        int len;
916
917        try {
918            FileInputStream is = new FileInputStream("/proc/wakelocks");
919            len = is.read(buffer);
920            is.close();
921
922            if (len > 0) {
923                int i;
924                for (i=0; i<len; i++) {
925                    if (buffer[i] == '\0') {
926                        len = i;
927                        break;
928                    }
929                }
930            }
931        } catch (java.io.FileNotFoundException e) {
932            return null;
933        } catch (java.io.IOException e) {
934            return null;
935        }
936
937        return parseProcWakelocks(buffer, len);
938    }
939
940    private final Map<String, KernelWakelockStats> parseProcWakelocks(
941            byte[] wlBuffer, int len) {
942        String name;
943        int count;
944        long totalTime;
945        int startIndex, endIndex;
946        int numUpdatedWlNames = 0;
947
948        // Advance past the first line.
949        int i;
950        for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++);
951        startIndex = endIndex = i + 1;
952
953        synchronized(this) {
954            Map<String, KernelWakelockStats> m = mProcWakelockFileStats;
955
956            sKernelWakelockUpdateVersion++;
957            while (endIndex < len) {
958                for (endIndex=startIndex;
959                        endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
960                        endIndex++);
961                // Don't go over the end of the buffer
962                if (endIndex < len) {
963                    endIndex++; // endIndex is an exclusive upper bound.
964                }
965
966                String[] nameStringArray = mProcWakelocksName;
967                long[] wlData = mProcWakelocksData;
968                // Stomp out any bad characters since this is from a circular buffer
969                // A corruption is seen sometimes that results in the vm crashing
970                // This should prevent crashes and the line will probably fail to parse
971                for (int j = startIndex; j < endIndex; j++) {
972                    if ((wlBuffer[j] & 0x80) != 0) wlBuffer[j] = (byte) '?';
973                }
974                boolean parsed = Process.parseProcLine(wlBuffer, startIndex, endIndex,
975                        PROC_WAKELOCKS_FORMAT, nameStringArray, wlData, null);
976
977                name = nameStringArray[0];
978                count = (int) wlData[1];
979                // convert nanoseconds to microseconds with rounding.
980                totalTime = (wlData[2] + 500) / 1000;
981
982                if (parsed && name.length() > 0) {
983                    if (!m.containsKey(name)) {
984                        m.put(name, new KernelWakelockStats(count, totalTime,
985                                sKernelWakelockUpdateVersion));
986                        numUpdatedWlNames++;
987                    } else {
988                        KernelWakelockStats kwlStats = m.get(name);
989                        if (kwlStats.mVersion == sKernelWakelockUpdateVersion) {
990                            kwlStats.mCount += count;
991                            kwlStats.mTotalTime += totalTime;
992                        } else {
993                            kwlStats.mCount = count;
994                            kwlStats.mTotalTime = totalTime;
995                            kwlStats.mVersion = sKernelWakelockUpdateVersion;
996                            numUpdatedWlNames++;
997                        }
998                    }
999                }
1000                startIndex = endIndex;
1001            }
1002
1003            if (m.size() != numUpdatedWlNames) {
1004                // Don't report old data.
1005                Iterator<KernelWakelockStats> itr = m.values().iterator();
1006                while (itr.hasNext()) {
1007                    if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
1008                        itr.remove();
1009                    }
1010                }
1011            }
1012            return m;
1013        }
1014    }
1015
1016    private class KernelWakelockStats {
1017        public int mCount;
1018        public long mTotalTime;
1019        public int mVersion;
1020
1021        KernelWakelockStats(int count, long totalTime, int version) {
1022            mCount = count;
1023            mTotalTime = totalTime;
1024            mVersion = version;
1025        }
1026    }
1027
1028    /*
1029     * Get the KernelWakelockTimer associated with name, and create a new one if one
1030     * doesn't already exist.
1031     */
1032    public SamplingTimer getKernelWakelockTimerLocked(String name) {
1033        SamplingTimer kwlt = mKernelWakelockStats.get(name);
1034        if (kwlt == null) {
1035            kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
1036                    true /* track reported values */);
1037            mKernelWakelockStats.put(name, kwlt);
1038        }
1039        return kwlt;
1040    }
1041
1042    private void doDataPlug(long[] dataTransfer, long currentBytes) {
1043        dataTransfer[STATS_LAST] = dataTransfer[STATS_SINCE_UNPLUGGED];
1044        dataTransfer[STATS_SINCE_UNPLUGGED] = -1;
1045    }
1046
1047    private void doDataUnplug(long[] dataTransfer, long currentBytes) {
1048        dataTransfer[STATS_SINCE_UNPLUGGED] = currentBytes;
1049    }
1050
1051    /**
1052     * Radio uptime in microseconds when transferring data. This value is very approximate.
1053     * @return
1054     */
1055    private long getCurrentRadioDataUptime() {
1056        try {
1057            File awakeTimeFile = new File("/sys/devices/virtual/net/rmnet0/awake_time_ms");
1058            if (!awakeTimeFile.exists()) return 0;
1059            BufferedReader br = new BufferedReader(new FileReader(awakeTimeFile));
1060            String line = br.readLine();
1061            br.close();
1062            return Long.parseLong(line) * 1000;
1063        } catch (NumberFormatException nfe) {
1064            // Nothing
1065        } catch (IOException ioe) {
1066            // Nothing
1067        }
1068        return 0;
1069    }
1070
1071    /**
1072     * @deprecated use getRadioDataUptime
1073     */
1074    public long getRadioDataUptimeMs() {
1075        return getRadioDataUptime() / 1000;
1076    }
1077
1078    /**
1079     * Returns the duration that the cell radio was up for data transfers.
1080     */
1081    public long getRadioDataUptime() {
1082        if (mRadioDataStart == -1) {
1083            return mRadioDataUptime;
1084        } else {
1085            return getCurrentRadioDataUptime() - mRadioDataStart;
1086        }
1087    }
1088
1089    private int getCurrentBluetoothPingCount() {
1090        if (mBtHeadset != null) {
1091            return mBtHeadset.getBatteryUsageHint();
1092        }
1093        return -1;
1094    }
1095
1096    public int getBluetoothPingCount() {
1097        if (mBluetoothPingStart == -1) {
1098            return mBluetoothPingCount;
1099        } else if (mBtHeadset != null) {
1100            return getCurrentBluetoothPingCount() - mBluetoothPingStart;
1101        }
1102        return 0;
1103    }
1104
1105    public void setBtHeadset(BluetoothHeadset headset) {
1106        if (headset != null && mBtHeadset == null && isOnBattery() && mBluetoothPingStart == -1) {
1107            mBluetoothPingStart = getCurrentBluetoothPingCount();
1108        }
1109        mBtHeadset = headset;
1110    }
1111
1112    void addHistoryRecordLocked(long curTime) {
1113        if (!mHaveBatteryLevel || !mRecordingHistory) {
1114            return;
1115        }
1116        if (mNumHistoryItems >= MAX_HISTORY_ITEMS) {
1117            // Once we've reached the maximum number of items, we only
1118            // record changes to the battery level.
1119            if (mHistoryEnd != null && mHistoryEnd.batteryLevel
1120                    == mHistoryCur.batteryLevel) {
1121                return;
1122            }
1123        }
1124        addHistoryRecordLocked(curTime, HistoryItem.CMD_UPDATE);
1125    }
1126
1127    void addHistoryRecordLocked(long curTime, byte cmd) {
1128        HistoryItem rec = mHistoryCache;
1129        if (rec != null) {
1130            mHistoryCache = rec.next;
1131        } else {
1132            rec = new HistoryItem();
1133        }
1134        rec.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
1135
1136        addHistoryRecordLocked(rec);
1137    }
1138
1139    void addHistoryRecordLocked(HistoryItem rec) {
1140        mNumHistoryItems++;
1141        rec.next = null;
1142        if (mHistoryEnd != null) {
1143            mHistoryEnd.next = rec;
1144            mHistoryEnd = rec;
1145        } else {
1146            mHistory = mHistoryEnd = rec;
1147        }
1148    }
1149
1150    void clearHistoryLocked() {
1151        if (mHistory != null) {
1152            mHistoryEnd.next = mHistoryCache;
1153            mHistoryCache = mHistory;
1154            mHistory = mHistoryEnd = null;
1155        }
1156        mNumHistoryItems = 0;
1157        mHistoryBaseTime = 0;
1158    }
1159
1160    public void doUnplugLocked(long batteryUptime, long batteryRealtime) {
1161        for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
1162            Uid u = mUidStats.valueAt(iu);
1163            u.mStartedTcpBytesReceived = TrafficStats.getUidRxBytes(u.mUid);
1164            u.mStartedTcpBytesSent = TrafficStats.getUidTxBytes(u.mUid);
1165            u.mTcpBytesReceivedAtLastUnplug = u.mCurrentTcpBytesReceived;
1166            u.mTcpBytesSentAtLastUnplug = u.mCurrentTcpBytesSent;
1167        }
1168        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
1169            mUnpluggables.get(i).unplug(batteryUptime, batteryRealtime);
1170        }
1171        // Track total mobile data
1172        doDataUnplug(mMobileDataRx, TrafficStats.getMobileRxBytes());
1173        doDataUnplug(mMobileDataTx, TrafficStats.getMobileTxBytes());
1174        doDataUnplug(mTotalDataRx, TrafficStats.getTotalRxBytes());
1175        doDataUnplug(mTotalDataTx, TrafficStats.getTotalTxBytes());
1176        // Track radio awake time
1177        mRadioDataStart = getCurrentRadioDataUptime();
1178        mRadioDataUptime = 0;
1179        // Track bt headset ping count
1180        mBluetoothPingStart = getCurrentBluetoothPingCount();
1181        mBluetoothPingCount = 0;
1182    }
1183
1184    public void doPlugLocked(long batteryUptime, long batteryRealtime) {
1185        for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
1186            Uid u = mUidStats.valueAt(iu);
1187            if (u.mStartedTcpBytesReceived >= 0) {
1188                u.mCurrentTcpBytesReceived = u.computeCurrentTcpBytesReceived();
1189                u.mStartedTcpBytesReceived = -1;
1190            }
1191            if (u.mStartedTcpBytesSent >= 0) {
1192                u.mCurrentTcpBytesSent = u.computeCurrentTcpBytesSent();
1193                u.mStartedTcpBytesSent = -1;
1194            }
1195        }
1196        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
1197            mUnpluggables.get(i).plug(batteryUptime, batteryRealtime);
1198        }
1199        doDataPlug(mMobileDataRx, TrafficStats.getMobileRxBytes());
1200        doDataPlug(mMobileDataTx, TrafficStats.getMobileTxBytes());
1201        doDataPlug(mTotalDataRx, TrafficStats.getTotalRxBytes());
1202        doDataPlug(mTotalDataTx, TrafficStats.getTotalTxBytes());
1203        // Track radio awake time
1204        mRadioDataUptime = getRadioDataUptime();
1205        mRadioDataStart = -1;
1206
1207        // Track bt headset ping count
1208        mBluetoothPingCount = getBluetoothPingCount();
1209        mBluetoothPingStart = -1;
1210    }
1211
1212    int mGpsNesting;
1213
1214    public void noteStartGpsLocked(int uid) {
1215        if (mGpsNesting == 0) {
1216            mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
1217            if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
1218                    + Integer.toHexString(mHistoryCur.states));
1219            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1220        }
1221        mGpsNesting++;
1222        getUidStatsLocked(uid).noteStartGps();
1223    }
1224
1225    public void noteStopGpsLocked(int uid) {
1226        mGpsNesting--;
1227        if (mGpsNesting == 0) {
1228            mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
1229            if (DEBUG_HISTORY) Slog.v(TAG, "Stop GPS to: "
1230                    + Integer.toHexString(mHistoryCur.states));
1231            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1232        }
1233        getUidStatsLocked(uid).noteStopGps();
1234    }
1235
1236    public void noteScreenOnLocked() {
1237        if (!mScreenOn) {
1238            mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
1239            if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
1240                    + Integer.toHexString(mHistoryCur.states));
1241            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1242            mScreenOn = true;
1243            mScreenOnTimer.startRunningLocked(this);
1244            if (mScreenBrightnessBin >= 0) {
1245                mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
1246            }
1247        }
1248    }
1249
1250    public void noteScreenOffLocked() {
1251        if (mScreenOn) {
1252            mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
1253            if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
1254                    + Integer.toHexString(mHistoryCur.states));
1255            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1256            mScreenOn = false;
1257            mScreenOnTimer.stopRunningLocked(this);
1258            if (mScreenBrightnessBin >= 0) {
1259                mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
1260            }
1261        }
1262    }
1263
1264    public void noteScreenBrightnessLocked(int brightness) {
1265        // Bin the brightness.
1266        int bin = brightness / (256/NUM_SCREEN_BRIGHTNESS_BINS);
1267        if (bin < 0) bin = 0;
1268        else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
1269        if (mScreenBrightnessBin != bin) {
1270            mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_BRIGHTNESS_MASK)
1271                    | (bin << HistoryItem.STATE_BRIGHTNESS_SHIFT);
1272            if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
1273                    + Integer.toHexString(mHistoryCur.states));
1274            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1275            if (mScreenOn) {
1276                if (mScreenBrightnessBin >= 0) {
1277                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
1278                }
1279                mScreenBrightnessTimer[bin].startRunningLocked(this);
1280            }
1281            mScreenBrightnessBin = bin;
1282        }
1283    }
1284
1285    public void noteInputEventAtomic() {
1286        mInputEventCounter.stepAtomic();
1287    }
1288
1289    public void noteUserActivityLocked(int uid, int event) {
1290        getUidStatsLocked(uid).noteUserActivityLocked(event);
1291    }
1292
1293    public void notePhoneOnLocked() {
1294        if (!mPhoneOn) {
1295            mHistoryCur.states |= HistoryItem.STATE_PHONE_IN_CALL_FLAG;
1296            if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
1297                    + Integer.toHexString(mHistoryCur.states));
1298            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1299            mPhoneOn = true;
1300            mPhoneOnTimer.startRunningLocked(this);
1301        }
1302    }
1303
1304    public void notePhoneOffLocked() {
1305        if (mPhoneOn) {
1306            mHistoryCur.states &= ~HistoryItem.STATE_PHONE_IN_CALL_FLAG;
1307            if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
1308                    + Integer.toHexString(mHistoryCur.states));
1309            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1310            mPhoneOn = false;
1311            mPhoneOnTimer.stopRunningLocked(this);
1312        }
1313    }
1314
1315    void stopAllSignalStrengthTimersLocked(int except) {
1316        for (int i = 0; i < NUM_SIGNAL_STRENGTH_BINS; i++) {
1317            if (i == except) {
1318                continue;
1319            }
1320            while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
1321                mPhoneSignalStrengthsTimer[i].stopRunningLocked(this);
1322            }
1323        }
1324    }
1325
1326    /**
1327     * Telephony stack updates the phone state.
1328     * @param state phone state from ServiceState.getState()
1329     */
1330    public void notePhoneStateLocked(int state) {
1331        boolean scanning = false;
1332
1333        int bin = mPhoneSignalStrengthBin;
1334
1335        // If the phone is powered off, stop all timers.
1336        if (state == ServiceState.STATE_POWER_OFF) {
1337            stopAllSignalStrengthTimersLocked(-1);
1338
1339        // If we're back in service or continuing in service, restart the old timer.
1340        } if (state == ServiceState.STATE_IN_SERVICE) {
1341            if (bin == -1) bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1342            if (!mPhoneSignalStrengthsTimer[bin].isRunningLocked()) {
1343                mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
1344            }
1345
1346        // If we're out of service, we are in the lowest signal strength
1347        // bin and have the scanning bit set.
1348        } else if (state == ServiceState.STATE_OUT_OF_SERVICE) {
1349            scanning = true;
1350            mPhoneSignalStrengthBin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1351            stopAllSignalStrengthTimersLocked(mPhoneSignalStrengthBin);
1352            if (!mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].isRunningLocked()) {
1353                mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].startRunningLocked(this);
1354            }
1355            if (!mPhoneSignalScanningTimer.isRunningLocked()) {
1356                mHistoryCur.states |= HistoryItem.STATE_PHONE_SCANNING_FLAG;
1357                if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: "
1358                        + Integer.toHexString(mHistoryCur.states));
1359                addHistoryRecordLocked(SystemClock.elapsedRealtime());
1360                mPhoneSignalScanningTimer.startRunningLocked(this);
1361            }
1362        }
1363
1364        if (!scanning) {
1365            // If we are no longer scanning, then stop the scanning timer.
1366            if (mPhoneSignalScanningTimer.isRunningLocked()) {
1367                mHistoryCur.states &= ~HistoryItem.STATE_PHONE_SCANNING_FLAG;
1368                if (DEBUG_HISTORY) Slog.v(TAG, "Phone stopped scanning to: "
1369                        + Integer.toHexString(mHistoryCur.states));
1370                addHistoryRecordLocked(SystemClock.elapsedRealtime());
1371                mPhoneSignalScanningTimer.stopRunningLocked(this);
1372            }
1373        }
1374
1375        if (mPhoneServiceState != state) {
1376            mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_PHONE_STATE_MASK)
1377                    | (state << HistoryItem.STATE_PHONE_STATE_SHIFT);
1378            if (DEBUG_HISTORY) Slog.v(TAG, "Phone state " + bin + " to: "
1379                    + Integer.toHexString(mHistoryCur.states));
1380            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1381            mPhoneServiceState = state;
1382        }
1383    }
1384
1385    public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
1386        // Bin the strength.
1387        int bin;
1388        if (mPhoneServiceState == ServiceState.STATE_POWER_OFF
1389                || mPhoneServiceState == ServiceState.STATE_OUT_OF_SERVICE) {
1390            // Ignore any signal strength changes when radio was turned off or out of service.
1391            return;
1392        }
1393        if (!signalStrength.isGsm()) {
1394            int dBm = signalStrength.getCdmaDbm();
1395            if (dBm >= -75) bin = SIGNAL_STRENGTH_GREAT;
1396            else if (dBm >= -85) bin = SIGNAL_STRENGTH_GOOD;
1397            else if (dBm >= -95)  bin = SIGNAL_STRENGTH_MODERATE;
1398            else if (dBm >= -100)  bin = SIGNAL_STRENGTH_POOR;
1399            else bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1400        } else {
1401            int asu = signalStrength.getGsmSignalStrength();
1402            if (asu < 0 || asu >= 99) bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
1403            else if (asu >= 16) bin = SIGNAL_STRENGTH_GREAT;
1404            else if (asu >= 8)  bin = SIGNAL_STRENGTH_GOOD;
1405            else if (asu >= 4)  bin = SIGNAL_STRENGTH_MODERATE;
1406            else bin = SIGNAL_STRENGTH_POOR;
1407        }
1408        if (mPhoneSignalStrengthBin != bin) {
1409            mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_SIGNAL_STRENGTH_MASK)
1410                    | (bin << HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT);
1411            if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + bin + " to: "
1412                    + Integer.toHexString(mHistoryCur.states));
1413            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1414            if (mPhoneSignalStrengthBin >= 0) {
1415                mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this);
1416            }
1417            mPhoneSignalStrengthBin = bin;
1418            mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
1419        }
1420    }
1421
1422    public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData) {
1423        int bin = DATA_CONNECTION_NONE;
1424        if (hasData) {
1425            switch (dataType) {
1426                case TelephonyManager.NETWORK_TYPE_EDGE:
1427                    bin = DATA_CONNECTION_EDGE;
1428                    break;
1429                case TelephonyManager.NETWORK_TYPE_GPRS:
1430                    bin = DATA_CONNECTION_GPRS;
1431                    break;
1432                case TelephonyManager.NETWORK_TYPE_UMTS:
1433                    bin = DATA_CONNECTION_UMTS;
1434                    break;
1435                case TelephonyManager.NETWORK_TYPE_CDMA:
1436                    bin = DATA_CONNECTION_CDMA;
1437                    break;
1438                case TelephonyManager.NETWORK_TYPE_EVDO_0:
1439                    bin = DATA_CONNECTION_EVDO_0;
1440                    break;
1441                case TelephonyManager.NETWORK_TYPE_EVDO_A:
1442                    bin = DATA_CONNECTION_EVDO_A;
1443                    break;
1444                case TelephonyManager.NETWORK_TYPE_1xRTT:
1445                    bin = DATA_CONNECTION_1xRTT;
1446                    break;
1447                case TelephonyManager.NETWORK_TYPE_HSDPA:
1448                    bin = DATA_CONNECTION_HSDPA;
1449                    break;
1450                case TelephonyManager.NETWORK_TYPE_HSUPA:
1451                    bin = DATA_CONNECTION_HSUPA;
1452                    break;
1453                case TelephonyManager.NETWORK_TYPE_HSPA:
1454                    bin = DATA_CONNECTION_HSPA;
1455                    break;
1456                case TelephonyManager.NETWORK_TYPE_IDEN:
1457                    bin = DATA_CONNECTION_IDEN;
1458                    break;
1459                case TelephonyManager.NETWORK_TYPE_EVDO_B:
1460                    bin = DATA_CONNECTION_EVDO_B;
1461                    break;
1462                default:
1463                    bin = DATA_CONNECTION_OTHER;
1464                    break;
1465            }
1466        }
1467        if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
1468        if (mPhoneDataConnectionType != bin) {
1469            mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
1470                    | (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
1471            if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
1472                    + Integer.toHexString(mHistoryCur.states));
1473            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1474            if (mPhoneDataConnectionType >= 0) {
1475                mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this);
1476            }
1477            mPhoneDataConnectionType = bin;
1478            mPhoneDataConnectionsTimer[bin].startRunningLocked(this);
1479        }
1480    }
1481
1482    public void noteWifiOnLocked(int uid) {
1483        if (!mWifiOn) {
1484            mHistoryCur.states |= HistoryItem.STATE_WIFI_ON_FLAG;
1485            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
1486                    + Integer.toHexString(mHistoryCur.states));
1487            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1488            mWifiOn = true;
1489            mWifiOnTimer.startRunningLocked(this);
1490        }
1491        if (mWifiOnUid != uid) {
1492            if (mWifiOnUid >= 0) {
1493                getUidStatsLocked(mWifiOnUid).noteWifiTurnedOffLocked();
1494            }
1495            mWifiOnUid = uid;
1496            getUidStatsLocked(uid).noteWifiTurnedOnLocked();
1497        }
1498    }
1499
1500    public void noteWifiOffLocked(int uid) {
1501        if (mWifiOn) {
1502            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_ON_FLAG;
1503            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
1504                    + Integer.toHexString(mHistoryCur.states));
1505            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1506            mWifiOn = false;
1507            mWifiOnTimer.stopRunningLocked(this);
1508        }
1509        if (mWifiOnUid >= 0) {
1510            getUidStatsLocked(mWifiOnUid).noteWifiTurnedOffLocked();
1511            mWifiOnUid = -1;
1512        }
1513    }
1514
1515    public void noteAudioOnLocked(int uid) {
1516        if (!mAudioOn) {
1517            mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
1518            if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
1519                    + Integer.toHexString(mHistoryCur.states));
1520            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1521            mAudioOn = true;
1522            mAudioOnTimer.startRunningLocked(this);
1523        }
1524        getUidStatsLocked(uid).noteAudioTurnedOnLocked();
1525    }
1526
1527    public void noteAudioOffLocked(int uid) {
1528        if (mAudioOn) {
1529            mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
1530            if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
1531                    + Integer.toHexString(mHistoryCur.states));
1532            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1533            mAudioOn = false;
1534            mAudioOnTimer.stopRunningLocked(this);
1535        }
1536        getUidStatsLocked(uid).noteAudioTurnedOffLocked();
1537    }
1538
1539    public void noteVideoOnLocked(int uid) {
1540        if (!mVideoOn) {
1541            mHistoryCur.states |= HistoryItem.STATE_VIDEO_ON_FLAG;
1542            if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
1543                    + Integer.toHexString(mHistoryCur.states));
1544            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1545            mVideoOn = true;
1546            mVideoOnTimer.startRunningLocked(this);
1547        }
1548        getUidStatsLocked(uid).noteVideoTurnedOnLocked();
1549    }
1550
1551    public void noteVideoOffLocked(int uid) {
1552        if (mVideoOn) {
1553            mHistoryCur.states &= ~HistoryItem.STATE_VIDEO_ON_FLAG;
1554            if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
1555                    + Integer.toHexString(mHistoryCur.states));
1556            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1557            mVideoOn = false;
1558            mVideoOnTimer.stopRunningLocked(this);
1559        }
1560        getUidStatsLocked(uid).noteVideoTurnedOffLocked();
1561    }
1562
1563    public void noteWifiRunningLocked() {
1564        if (!mWifiRunning) {
1565            mHistoryCur.states |= HistoryItem.STATE_WIFI_RUNNING_FLAG;
1566            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
1567                    + Integer.toHexString(mHistoryCur.states));
1568            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1569            mWifiRunning = true;
1570            mWifiRunningTimer.startRunningLocked(this);
1571        }
1572    }
1573
1574    public void noteWifiStoppedLocked() {
1575        if (mWifiRunning) {
1576            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RUNNING_FLAG;
1577            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
1578                    + Integer.toHexString(mHistoryCur.states));
1579            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1580            mWifiRunning = false;
1581            mWifiRunningTimer.stopRunningLocked(this);
1582        }
1583    }
1584
1585    public void noteBluetoothOnLocked() {
1586        if (!mBluetoothOn) {
1587            mHistoryCur.states |= HistoryItem.STATE_BLUETOOTH_ON_FLAG;
1588            if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth on to: "
1589                    + Integer.toHexString(mHistoryCur.states));
1590            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1591            mBluetoothOn = true;
1592            mBluetoothOnTimer.startRunningLocked(this);
1593        }
1594    }
1595
1596    public void noteBluetoothOffLocked() {
1597        if (mBluetoothOn) {
1598            mHistoryCur.states &= ~HistoryItem.STATE_BLUETOOTH_ON_FLAG;
1599            if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth off to: "
1600                    + Integer.toHexString(mHistoryCur.states));
1601            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1602            mBluetoothOn = false;
1603            mBluetoothOnTimer.stopRunningLocked(this);
1604        }
1605    }
1606
1607    int mWifiFullLockNesting = 0;
1608
1609    public void noteFullWifiLockAcquiredLocked(int uid) {
1610        if (mWifiFullLockNesting == 0) {
1611            mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
1612            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
1613                    + Integer.toHexString(mHistoryCur.states));
1614            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1615        }
1616        mWifiFullLockNesting++;
1617        getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
1618    }
1619
1620    public void noteFullWifiLockReleasedLocked(int uid) {
1621        mWifiFullLockNesting--;
1622        if (mWifiFullLockNesting == 0) {
1623            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
1624            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
1625                    + Integer.toHexString(mHistoryCur.states));
1626            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1627        }
1628        getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
1629    }
1630
1631    int mWifiScanLockNesting = 0;
1632
1633    public void noteScanWifiLockAcquiredLocked(int uid) {
1634        if (mWifiScanLockNesting == 0) {
1635            mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_LOCK_FLAG;
1636            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock on to: "
1637                    + Integer.toHexString(mHistoryCur.states));
1638            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1639        }
1640        mWifiScanLockNesting++;
1641        getUidStatsLocked(uid).noteScanWifiLockAcquiredLocked();
1642    }
1643
1644    public void noteScanWifiLockReleasedLocked(int uid) {
1645        mWifiScanLockNesting--;
1646        if (mWifiScanLockNesting == 0) {
1647            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_LOCK_FLAG;
1648            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock off to: "
1649                    + Integer.toHexString(mHistoryCur.states));
1650            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1651        }
1652        getUidStatsLocked(uid).noteScanWifiLockReleasedLocked();
1653    }
1654
1655    int mWifiMulticastNesting = 0;
1656
1657    public void noteWifiMulticastEnabledLocked(int uid) {
1658        if (mWifiMulticastNesting == 0) {
1659            mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
1660            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
1661                    + Integer.toHexString(mHistoryCur.states));
1662            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1663        }
1664        mWifiMulticastNesting++;
1665        getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
1666    }
1667
1668    public void noteWifiMulticastDisabledLocked(int uid) {
1669        mWifiMulticastNesting--;
1670        if (mWifiMulticastNesting == 0) {
1671            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
1672            if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
1673                    + Integer.toHexString(mHistoryCur.states));
1674            addHistoryRecordLocked(SystemClock.elapsedRealtime());
1675        }
1676        getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
1677    }
1678
1679    @Override public long getScreenOnTime(long batteryRealtime, int which) {
1680        return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
1681    }
1682
1683    @Override public long getScreenBrightnessTime(int brightnessBin,
1684            long batteryRealtime, int which) {
1685        return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
1686                batteryRealtime, which);
1687    }
1688
1689    @Override public int getInputEventCount(int which) {
1690        return mInputEventCounter.getCountLocked(which);
1691    }
1692
1693    @Override public long getPhoneOnTime(long batteryRealtime, int which) {
1694        return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
1695    }
1696
1697    @Override public long getPhoneSignalStrengthTime(int strengthBin,
1698            long batteryRealtime, int which) {
1699        return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
1700                batteryRealtime, which);
1701    }
1702
1703    @Override public long getPhoneSignalScanningTime(
1704            long batteryRealtime, int which) {
1705        return mPhoneSignalScanningTimer.getTotalTimeLocked(
1706                batteryRealtime, which);
1707    }
1708
1709    @Override public int getPhoneSignalStrengthCount(int dataType, int which) {
1710        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
1711    }
1712
1713    @Override public long getPhoneDataConnectionTime(int dataType,
1714            long batteryRealtime, int which) {
1715        return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
1716                batteryRealtime, which);
1717    }
1718
1719    @Override public int getPhoneDataConnectionCount(int dataType, int which) {
1720        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
1721    }
1722
1723    @Override public long getWifiOnTime(long batteryRealtime, int which) {
1724        return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
1725    }
1726
1727    @Override public long getWifiRunningTime(long batteryRealtime, int which) {
1728        return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
1729    }
1730
1731    @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
1732        return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
1733    }
1734
1735    @Override public boolean getIsOnBattery() {
1736        return mOnBattery;
1737    }
1738
1739    @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
1740        return mUidStats;
1741    }
1742
1743    /**
1744     * The statistics associated with a particular uid.
1745     */
1746    public final class Uid extends BatteryStats.Uid {
1747
1748        final int mUid;
1749        long mLoadedTcpBytesReceived;
1750        long mLoadedTcpBytesSent;
1751        long mCurrentTcpBytesReceived;
1752        long mCurrentTcpBytesSent;
1753        long mTcpBytesReceivedAtLastUnplug;
1754        long mTcpBytesSentAtLastUnplug;
1755
1756        // These are not saved/restored when parcelling, since we want
1757        // to return from the parcel with a snapshot of the state.
1758        long mStartedTcpBytesReceived = -1;
1759        long mStartedTcpBytesSent = -1;
1760
1761        boolean mWifiTurnedOn;
1762        StopwatchTimer mWifiTurnedOnTimer;
1763
1764        boolean mFullWifiLockOut;
1765        StopwatchTimer mFullWifiLockTimer;
1766
1767        boolean mScanWifiLockOut;
1768        StopwatchTimer mScanWifiLockTimer;
1769
1770        boolean mWifiMulticastEnabled;
1771        StopwatchTimer mWifiMulticastTimer;
1772
1773        boolean mAudioTurnedOn;
1774        StopwatchTimer mAudioTurnedOnTimer;
1775
1776        boolean mVideoTurnedOn;
1777        StopwatchTimer mVideoTurnedOnTimer;
1778
1779        Counter[] mUserActivityCounters;
1780
1781        /**
1782         * The statistics we have collected for this uid's wake locks.
1783         */
1784        final HashMap<String, Wakelock> mWakelockStats = new HashMap<String, Wakelock>();
1785
1786        /**
1787         * The statistics we have collected for this uid's sensor activations.
1788         */
1789        final HashMap<Integer, Sensor> mSensorStats = new HashMap<Integer, Sensor>();
1790
1791        /**
1792         * The statistics we have collected for this uid's processes.
1793         */
1794        final HashMap<String, Proc> mProcessStats = new HashMap<String, Proc>();
1795
1796        /**
1797         * The statistics we have collected for this uid's processes.
1798         */
1799        final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
1800
1801        public Uid(int uid) {
1802            mUid = uid;
1803            mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables);
1804            mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables);
1805            mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables);
1806            mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
1807                    null, mUnpluggables);
1808            mAudioTurnedOnTimer = new StopwatchTimer(AUDIO_TURNED_ON, null, mUnpluggables);
1809            mVideoTurnedOnTimer = new StopwatchTimer(VIDEO_TURNED_ON, null, mUnpluggables);
1810        }
1811
1812        @Override
1813        public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
1814            return mWakelockStats;
1815        }
1816
1817        @Override
1818        public Map<Integer, ? extends BatteryStats.Uid.Sensor> getSensorStats() {
1819            return mSensorStats;
1820        }
1821
1822        @Override
1823        public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
1824            return mProcessStats;
1825        }
1826
1827        @Override
1828        public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
1829            return mPackageStats;
1830        }
1831
1832        @Override
1833        public int getUid() {
1834            return mUid;
1835        }
1836
1837        @Override
1838        public long getTcpBytesReceived(int which) {
1839            if (which == STATS_LAST) {
1840                return mLoadedTcpBytesReceived;
1841            } else {
1842                long current = computeCurrentTcpBytesReceived();
1843                if (which == STATS_SINCE_UNPLUGGED) {
1844                    current -= mTcpBytesReceivedAtLastUnplug;
1845                } else if (which == STATS_SINCE_CHARGED) {
1846                    current += mLoadedTcpBytesReceived;
1847                }
1848                return current;
1849            }
1850        }
1851
1852        public long computeCurrentTcpBytesReceived() {
1853            return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
1854                    ? (TrafficStats.getUidRxBytes(mUid) - mStartedTcpBytesReceived) : 0);
1855        }
1856
1857        @Override
1858        public long getTcpBytesSent(int which) {
1859            if (which == STATS_LAST) {
1860                return mLoadedTcpBytesSent;
1861            } else {
1862                long current = computeCurrentTcpBytesSent();
1863                if (which == STATS_SINCE_UNPLUGGED) {
1864                    current -= mTcpBytesSentAtLastUnplug;
1865                } else if (which == STATS_SINCE_CHARGED) {
1866                    current += mLoadedTcpBytesSent;
1867                }
1868                return current;
1869            }
1870        }
1871
1872        @Override
1873        public void noteWifiTurnedOnLocked() {
1874            if (!mWifiTurnedOn) {
1875                mWifiTurnedOn = true;
1876                if (mWifiTurnedOnTimer == null) {
1877                    mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON,
1878                            null, mUnpluggables);
1879                }
1880                mWifiTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
1881            }
1882        }
1883
1884        @Override
1885        public void noteWifiTurnedOffLocked() {
1886            if (mWifiTurnedOn) {
1887                mWifiTurnedOn = false;
1888                mWifiTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
1889            }
1890        }
1891
1892        @Override
1893        public void noteFullWifiLockAcquiredLocked() {
1894            if (!mFullWifiLockOut) {
1895                mFullWifiLockOut = true;
1896                if (mFullWifiLockTimer == null) {
1897                    mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK,
1898                            null, mUnpluggables);
1899                }
1900                mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
1901            }
1902        }
1903
1904        @Override
1905        public void noteFullWifiLockReleasedLocked() {
1906            if (mFullWifiLockOut) {
1907                mFullWifiLockOut = false;
1908                mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
1909            }
1910        }
1911
1912        @Override
1913        public void noteScanWifiLockAcquiredLocked() {
1914            if (!mScanWifiLockOut) {
1915                mScanWifiLockOut = true;
1916                if (mScanWifiLockTimer == null) {
1917                    mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK,
1918                            null, mUnpluggables);
1919                }
1920                mScanWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
1921            }
1922        }
1923
1924        @Override
1925        public void noteScanWifiLockReleasedLocked() {
1926            if (mScanWifiLockOut) {
1927                mScanWifiLockOut = false;
1928                mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
1929            }
1930        }
1931
1932        @Override
1933        public void noteWifiMulticastEnabledLocked() {
1934            if (!mWifiMulticastEnabled) {
1935                mWifiMulticastEnabled = true;
1936                if (mWifiMulticastTimer == null) {
1937                    mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
1938                            null, mUnpluggables);
1939                }
1940                mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
1941            }
1942        }
1943
1944        @Override
1945        public void noteWifiMulticastDisabledLocked() {
1946            if (mWifiMulticastEnabled) {
1947                mWifiMulticastEnabled = false;
1948                mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
1949            }
1950        }
1951
1952        @Override
1953        public void noteAudioTurnedOnLocked() {
1954            if (!mAudioTurnedOn) {
1955                mAudioTurnedOn = true;
1956                if (mAudioTurnedOnTimer == null) {
1957                    mAudioTurnedOnTimer = new StopwatchTimer(AUDIO_TURNED_ON,
1958                            null, mUnpluggables);
1959                }
1960                mAudioTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
1961            }
1962        }
1963
1964        @Override
1965        public void noteAudioTurnedOffLocked() {
1966            if (mAudioTurnedOn) {
1967                mAudioTurnedOn = false;
1968                mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
1969            }
1970        }
1971
1972        @Override
1973        public void noteVideoTurnedOnLocked() {
1974            if (!mVideoTurnedOn) {
1975                mVideoTurnedOn = true;
1976                if (mVideoTurnedOnTimer == null) {
1977                    mVideoTurnedOnTimer = new StopwatchTimer(VIDEO_TURNED_ON,
1978                            null, mUnpluggables);
1979                }
1980                mVideoTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
1981            }
1982        }
1983
1984        @Override
1985        public void noteVideoTurnedOffLocked() {
1986            if (mVideoTurnedOn) {
1987                mVideoTurnedOn = false;
1988                mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
1989            }
1990        }
1991
1992        @Override
1993        public long getWifiTurnedOnTime(long batteryRealtime, int which) {
1994            if (mWifiTurnedOnTimer == null) {
1995                return 0;
1996            }
1997            return mWifiTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
1998        }
1999
2000        @Override
2001        public long getFullWifiLockTime(long batteryRealtime, int which) {
2002            if (mFullWifiLockTimer == null) {
2003                return 0;
2004            }
2005            return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
2006        }
2007
2008        @Override
2009        public long getScanWifiLockTime(long batteryRealtime, int which) {
2010            if (mScanWifiLockTimer == null) {
2011                return 0;
2012            }
2013            return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
2014        }
2015
2016        @Override
2017        public long getWifiMulticastTime(long batteryRealtime, int which) {
2018            if (mWifiMulticastTimer == null) {
2019                return 0;
2020            }
2021            return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime,
2022                                                          which);
2023        }
2024
2025        @Override
2026        public long getAudioTurnedOnTime(long batteryRealtime, int which) {
2027            if (mAudioTurnedOnTimer == null) {
2028                return 0;
2029            }
2030            return mAudioTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
2031        }
2032
2033        @Override
2034        public long getVideoTurnedOnTime(long batteryRealtime, int which) {
2035            if (mVideoTurnedOnTimer == null) {
2036                return 0;
2037            }
2038            return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
2039        }
2040
2041        @Override
2042        public void noteUserActivityLocked(int type) {
2043            if (mUserActivityCounters == null) {
2044                initUserActivityLocked();
2045            }
2046            if (type < 0) type = 0;
2047            else if (type >= NUM_USER_ACTIVITY_TYPES) type = NUM_USER_ACTIVITY_TYPES-1;
2048            mUserActivityCounters[type].stepAtomic();
2049        }
2050
2051        @Override
2052        public boolean hasUserActivity() {
2053            return mUserActivityCounters != null;
2054        }
2055
2056        @Override
2057        public int getUserActivityCount(int type, int which) {
2058            if (mUserActivityCounters == null) {
2059                return 0;
2060            }
2061            return mUserActivityCounters[type].getCountLocked(which);
2062        }
2063
2064        void initUserActivityLocked() {
2065            mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
2066            for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2067                mUserActivityCounters[i] = new Counter(mUnpluggables);
2068            }
2069        }
2070
2071        public long computeCurrentTcpBytesSent() {
2072            return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
2073                    ? (TrafficStats.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
2074        }
2075
2076        /**
2077         * Clear all stats for this uid.  Returns true if the uid is completely
2078         * inactive so can be dropped.
2079         */
2080        boolean reset() {
2081            boolean active = false;
2082
2083            if (mWifiTurnedOnTimer != null) {
2084                active |= !mWifiTurnedOnTimer.reset(false);
2085                active |= mWifiTurnedOn;
2086            }
2087            if (mFullWifiLockTimer != null) {
2088                active |= !mFullWifiLockTimer.reset(false);
2089                active |= mFullWifiLockOut;
2090            }
2091            if (mScanWifiLockTimer != null) {
2092                active |= !mScanWifiLockTimer.reset(false);
2093                active |= mScanWifiLockOut;
2094            }
2095            if (mWifiMulticastTimer != null) {
2096                active |= !mWifiMulticastTimer.reset(false);
2097                active |= mWifiMulticastEnabled;
2098            }
2099            if (mAudioTurnedOnTimer != null) {
2100                active |= !mAudioTurnedOnTimer.reset(false);
2101                active |= mAudioTurnedOn;
2102            }
2103            if (mVideoTurnedOnTimer != null) {
2104                active |= !mVideoTurnedOnTimer.reset(false);
2105                active |= mVideoTurnedOn;
2106            }
2107
2108            mLoadedTcpBytesReceived = mLoadedTcpBytesSent = 0;
2109            mCurrentTcpBytesReceived = mCurrentTcpBytesSent = 0;
2110
2111            if (mUserActivityCounters != null) {
2112                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2113                    mUserActivityCounters[i].reset(false);
2114                }
2115            }
2116
2117            if (mWakelockStats.size() > 0) {
2118                Iterator<Map.Entry<String, Wakelock>> it = mWakelockStats.entrySet().iterator();
2119                while (it.hasNext()) {
2120                    Map.Entry<String, Wakelock> wakelockEntry = it.next();
2121                    Wakelock wl = wakelockEntry.getValue();
2122                    if (wl.reset()) {
2123                        it.remove();
2124                    } else {
2125                        active = true;
2126                    }
2127                }
2128            }
2129            if (mSensorStats.size() > 0) {
2130                Iterator<Map.Entry<Integer, Sensor>> it = mSensorStats.entrySet().iterator();
2131                while (it.hasNext()) {
2132                    Map.Entry<Integer, Sensor> sensorEntry = it.next();
2133                    Sensor s = sensorEntry.getValue();
2134                    if (s.reset()) {
2135                        it.remove();
2136                    } else {
2137                        active = true;
2138                    }
2139                }
2140            }
2141            if (mProcessStats.size() > 0) {
2142                Iterator<Map.Entry<String, Proc>> it = mProcessStats.entrySet().iterator();
2143                while (it.hasNext()) {
2144                    Map.Entry<String, Proc> procEntry = it.next();
2145                    procEntry.getValue().detach();
2146                }
2147                mProcessStats.clear();
2148            }
2149            if (mPackageStats.size() > 0) {
2150                Iterator<Map.Entry<String, Pkg>> it = mPackageStats.entrySet().iterator();
2151                while (it.hasNext()) {
2152                    Map.Entry<String, Pkg> pkgEntry = it.next();
2153                    Pkg p = pkgEntry.getValue();
2154                    p.detach();
2155                    if (p.mServiceStats.size() > 0) {
2156                        Iterator<Map.Entry<String, Pkg.Serv>> it2
2157                                = p.mServiceStats.entrySet().iterator();
2158                        while (it2.hasNext()) {
2159                            Map.Entry<String, Pkg.Serv> servEntry = it2.next();
2160                            servEntry.getValue().detach();
2161                        }
2162                    }
2163                }
2164                mPackageStats.clear();
2165            }
2166
2167            if (!active) {
2168                if (mWifiTurnedOnTimer != null) {
2169                    mWifiTurnedOnTimer.detach();
2170                }
2171                if (mFullWifiLockTimer != null) {
2172                    mFullWifiLockTimer.detach();
2173                }
2174                if (mScanWifiLockTimer != null) {
2175                    mScanWifiLockTimer.detach();
2176                }
2177                if (mWifiMulticastTimer != null) {
2178                    mWifiMulticastTimer.detach();
2179                }
2180                if (mAudioTurnedOnTimer != null) {
2181                    mAudioTurnedOnTimer.detach();
2182                }
2183                if (mVideoTurnedOnTimer != null) {
2184                    mVideoTurnedOnTimer.detach();
2185                }
2186                if (mUserActivityCounters != null) {
2187                    for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2188                        mUserActivityCounters[i].detach();
2189                    }
2190                }
2191            }
2192
2193            return !active;
2194        }
2195
2196        void writeToParcelLocked(Parcel out, long batteryRealtime) {
2197            out.writeInt(mWakelockStats.size());
2198            for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
2199                out.writeString(wakelockEntry.getKey());
2200                Uid.Wakelock wakelock = wakelockEntry.getValue();
2201                wakelock.writeToParcelLocked(out, batteryRealtime);
2202            }
2203
2204            out.writeInt(mSensorStats.size());
2205            for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
2206                out.writeInt(sensorEntry.getKey());
2207                Uid.Sensor sensor = sensorEntry.getValue();
2208                sensor.writeToParcelLocked(out, batteryRealtime);
2209            }
2210
2211            out.writeInt(mProcessStats.size());
2212            for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
2213                out.writeString(procEntry.getKey());
2214                Uid.Proc proc = procEntry.getValue();
2215                proc.writeToParcelLocked(out);
2216            }
2217
2218            out.writeInt(mPackageStats.size());
2219            for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
2220                out.writeString(pkgEntry.getKey());
2221                Uid.Pkg pkg = pkgEntry.getValue();
2222                pkg.writeToParcelLocked(out);
2223            }
2224
2225            out.writeLong(mLoadedTcpBytesReceived);
2226            out.writeLong(mLoadedTcpBytesSent);
2227            out.writeLong(computeCurrentTcpBytesReceived());
2228            out.writeLong(computeCurrentTcpBytesSent());
2229            out.writeLong(mTcpBytesReceivedAtLastUnplug);
2230            out.writeLong(mTcpBytesSentAtLastUnplug);
2231            if (mWifiTurnedOnTimer != null) {
2232                out.writeInt(1);
2233                mWifiTurnedOnTimer.writeToParcel(out, batteryRealtime);
2234            } else {
2235                out.writeInt(0);
2236            }
2237            if (mFullWifiLockTimer != null) {
2238                out.writeInt(1);
2239                mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
2240            } else {
2241                out.writeInt(0);
2242            }
2243            if (mScanWifiLockTimer != null) {
2244                out.writeInt(1);
2245                mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
2246            } else {
2247                out.writeInt(0);
2248            }
2249            if (mWifiMulticastTimer != null) {
2250                out.writeInt(1);
2251                mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
2252            } else {
2253                out.writeInt(0);
2254            }
2255            if (mAudioTurnedOnTimer != null) {
2256                out.writeInt(1);
2257                mAudioTurnedOnTimer.writeToParcel(out, batteryRealtime);
2258            } else {
2259                out.writeInt(0);
2260            }
2261            if (mVideoTurnedOnTimer != null) {
2262                out.writeInt(1);
2263                mVideoTurnedOnTimer.writeToParcel(out, batteryRealtime);
2264            } else {
2265                out.writeInt(0);
2266            }
2267            if (mUserActivityCounters != null) {
2268                out.writeInt(1);
2269                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2270                    mUserActivityCounters[i].writeToParcel(out);
2271                }
2272            } else {
2273                out.writeInt(0);
2274            }
2275        }
2276
2277        void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
2278            int numWakelocks = in.readInt();
2279            mWakelockStats.clear();
2280            for (int j = 0; j < numWakelocks; j++) {
2281                String wakelockName = in.readString();
2282                Uid.Wakelock wakelock = new Wakelock();
2283                wakelock.readFromParcelLocked(unpluggables, in);
2284                if (mWakelockStats.size() < MAX_WAKELOCKS_PER_UID) {
2285                    // We will just drop some random set of wakelocks if
2286                    // the previous run of the system was an older version
2287                    // that didn't impose a limit.
2288                    mWakelockStats.put(wakelockName, wakelock);
2289                }
2290            }
2291
2292            int numSensors = in.readInt();
2293            mSensorStats.clear();
2294            for (int k = 0; k < numSensors; k++) {
2295                int sensorNumber = in.readInt();
2296                Uid.Sensor sensor = new Sensor(sensorNumber);
2297                sensor.readFromParcelLocked(mUnpluggables, in);
2298                mSensorStats.put(sensorNumber, sensor);
2299            }
2300
2301            int numProcs = in.readInt();
2302            mProcessStats.clear();
2303            for (int k = 0; k < numProcs; k++) {
2304                String processName = in.readString();
2305                Uid.Proc proc = new Proc();
2306                proc.readFromParcelLocked(in);
2307                mProcessStats.put(processName, proc);
2308            }
2309
2310            int numPkgs = in.readInt();
2311            mPackageStats.clear();
2312            for (int l = 0; l < numPkgs; l++) {
2313                String packageName = in.readString();
2314                Uid.Pkg pkg = new Pkg();
2315                pkg.readFromParcelLocked(in);
2316                mPackageStats.put(packageName, pkg);
2317            }
2318
2319            mLoadedTcpBytesReceived = in.readLong();
2320            mLoadedTcpBytesSent = in.readLong();
2321            mCurrentTcpBytesReceived = in.readLong();
2322            mCurrentTcpBytesSent = in.readLong();
2323            mTcpBytesReceivedAtLastUnplug = in.readLong();
2324            mTcpBytesSentAtLastUnplug = in.readLong();
2325            mWifiTurnedOn = false;
2326            if (in.readInt() != 0) {
2327                mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON,
2328                        null, mUnpluggables, in);
2329            } else {
2330                mWifiTurnedOnTimer = null;
2331            }
2332            mFullWifiLockOut = false;
2333            if (in.readInt() != 0) {
2334                mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK,
2335                        null, mUnpluggables, in);
2336            } else {
2337                mFullWifiLockTimer = null;
2338            }
2339            mScanWifiLockOut = false;
2340            if (in.readInt() != 0) {
2341                mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK,
2342                        null, mUnpluggables, in);
2343            } else {
2344                mScanWifiLockTimer = null;
2345            }
2346            mWifiMulticastEnabled = false;
2347            if (in.readInt() != 0) {
2348                mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
2349                        null, mUnpluggables, in);
2350            } else {
2351                mWifiMulticastTimer = null;
2352            }
2353            mAudioTurnedOn = false;
2354            if (in.readInt() != 0) {
2355                mAudioTurnedOnTimer = new StopwatchTimer(AUDIO_TURNED_ON,
2356                        null, mUnpluggables, in);
2357            } else {
2358                mAudioTurnedOnTimer = null;
2359            }
2360            mVideoTurnedOn = false;
2361            if (in.readInt() != 0) {
2362                mVideoTurnedOnTimer = new StopwatchTimer(VIDEO_TURNED_ON,
2363                        null, mUnpluggables, in);
2364            } else {
2365                mVideoTurnedOnTimer = null;
2366            }
2367            if (in.readInt() != 0) {
2368                mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
2369                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
2370                    mUserActivityCounters[i] = new Counter(mUnpluggables, in);
2371                }
2372            } else {
2373                mUserActivityCounters = null;
2374            }
2375        }
2376
2377        /**
2378         * The statistics associated with a particular wake lock.
2379         */
2380        public final class Wakelock extends BatteryStats.Uid.Wakelock {
2381            /**
2382             * How long (in ms) this uid has been keeping the device partially awake.
2383             */
2384            StopwatchTimer mTimerPartial;
2385
2386            /**
2387             * How long (in ms) this uid has been keeping the device fully awake.
2388             */
2389            StopwatchTimer mTimerFull;
2390
2391            /**
2392             * How long (in ms) this uid has had a window keeping the device awake.
2393             */
2394            StopwatchTimer mTimerWindow;
2395
2396            /**
2397             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
2398             * proper timer pool from the given BatteryStatsImpl object.
2399             *
2400             * @param in the Parcel to be read from.
2401             * return a new Timer, or null.
2402             */
2403            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
2404                    ArrayList<Unpluggable> unpluggables, Parcel in) {
2405                if (in.readInt() == 0) {
2406                    return null;
2407                }
2408
2409                return new StopwatchTimer(type, pool, unpluggables, in);
2410            }
2411
2412            boolean reset() {
2413                boolean wlactive = false;
2414                if (mTimerFull != null) {
2415                    wlactive |= !mTimerFull.reset(false);
2416                }
2417                if (mTimerPartial != null) {
2418                    wlactive |= !mTimerPartial.reset(false);
2419                }
2420                if (mTimerWindow != null) {
2421                    wlactive |= !mTimerWindow.reset(false);
2422                }
2423                if (!wlactive) {
2424                    if (mTimerFull != null) {
2425                        mTimerFull.detach();
2426                        mTimerFull = null;
2427                    }
2428                    if (mTimerPartial != null) {
2429                        mTimerPartial.detach();
2430                        mTimerPartial = null;
2431                    }
2432                    if (mTimerWindow != null) {
2433                        mTimerWindow.detach();
2434                        mTimerWindow = null;
2435                    }
2436                }
2437                return !wlactive;
2438            }
2439
2440            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
2441                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
2442                        mPartialTimers, unpluggables, in);
2443                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
2444                        mFullTimers, unpluggables, in);
2445                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
2446                        mWindowTimers, unpluggables, in);
2447            }
2448
2449            void writeToParcelLocked(Parcel out, long batteryRealtime) {
2450                Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
2451                Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
2452                Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
2453            }
2454
2455            @Override
2456            public Timer getWakeTime(int type) {
2457                switch (type) {
2458                case WAKE_TYPE_FULL: return mTimerFull;
2459                case WAKE_TYPE_PARTIAL: return mTimerPartial;
2460                case WAKE_TYPE_WINDOW: return mTimerWindow;
2461                default: throw new IllegalArgumentException("type = " + type);
2462                }
2463            }
2464        }
2465
2466        public final class Sensor extends BatteryStats.Uid.Sensor {
2467            final int mHandle;
2468            StopwatchTimer mTimer;
2469
2470            public Sensor(int handle) {
2471                mHandle = handle;
2472            }
2473
2474            private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
2475                    Parcel in) {
2476                if (in.readInt() == 0) {
2477                    return null;
2478                }
2479
2480                ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
2481                if (pool == null) {
2482                    pool = new ArrayList<StopwatchTimer>();
2483                    mSensorTimers.put(mHandle, pool);
2484                }
2485                return new StopwatchTimer(0, pool, unpluggables, in);
2486            }
2487
2488            boolean reset() {
2489                if (mTimer.reset(true)) {
2490                    mTimer = null;
2491                    return true;
2492                }
2493                return false;
2494            }
2495
2496            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
2497                mTimer = readTimerFromParcel(unpluggables, in);
2498            }
2499
2500            void writeToParcelLocked(Parcel out, long batteryRealtime) {
2501                Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
2502            }
2503
2504            @Override
2505            public Timer getSensorTime() {
2506                return mTimer;
2507            }
2508
2509            @Override
2510            public int getHandle() {
2511                return mHandle;
2512            }
2513        }
2514
2515        /**
2516         * The statistics associated with a particular process.
2517         */
2518        public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
2519            /**
2520             * Total time (in 1/100 sec) spent executing in user code.
2521             */
2522            long mUserTime;
2523
2524            /**
2525             * Total time (in 1/100 sec) spent executing in kernel code.
2526             */
2527            long mSystemTime;
2528
2529            /**
2530             * Number of times the process has been started.
2531             */
2532            int mStarts;
2533
2534            /**
2535             * Amount of time the process was running in the foreground.
2536             */
2537            long mForegroundTime;
2538
2539            /**
2540             * The amount of user time loaded from a previous save.
2541             */
2542            long mLoadedUserTime;
2543
2544            /**
2545             * The amount of system time loaded from a previous save.
2546             */
2547            long mLoadedSystemTime;
2548
2549            /**
2550             * The number of times the process has started from a previous save.
2551             */
2552            int mLoadedStarts;
2553
2554            /**
2555             * The amount of foreground time loaded from a previous save.
2556             */
2557            long mLoadedForegroundTime;
2558
2559            /**
2560             * The amount of user time loaded from the previous run.
2561             */
2562            long mLastUserTime;
2563
2564            /**
2565             * The amount of system time loaded from the previous run.
2566             */
2567            long mLastSystemTime;
2568
2569            /**
2570             * The number of times the process has started from the previous run.
2571             */
2572            int mLastStarts;
2573
2574            /**
2575             * The amount of foreground time loaded from the previous run
2576             */
2577            long mLastForegroundTime;
2578
2579            /**
2580             * The amount of user time when last unplugged.
2581             */
2582            long mUnpluggedUserTime;
2583
2584            /**
2585             * The amount of system time when last unplugged.
2586             */
2587            long mUnpluggedSystemTime;
2588
2589            /**
2590             * The number of times the process has started before unplugged.
2591             */
2592            int mUnpluggedStarts;
2593
2594            /**
2595             * The amount of foreground time since unplugged.
2596             */
2597            long mUnpluggedForegroundTime;
2598
2599            SamplingCounter[] mSpeedBins;
2600
2601            Proc() {
2602                mUnpluggables.add(this);
2603                mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
2604            }
2605
2606            public void unplug(long batteryUptime, long batteryRealtime) {
2607                mUnpluggedUserTime = mUserTime;
2608                mUnpluggedSystemTime = mSystemTime;
2609                mUnpluggedStarts = mStarts;
2610                mUnpluggedForegroundTime = mForegroundTime;
2611            }
2612
2613            public void plug(long batteryUptime, long batteryRealtime) {
2614            }
2615
2616            void detach() {
2617                mUnpluggables.remove(this);
2618                for (int i = 0; i < mSpeedBins.length; i++) {
2619                    SamplingCounter c = mSpeedBins[i];
2620                    if (c != null) {
2621                        mUnpluggables.remove(c);
2622                        mSpeedBins[i] = null;
2623                    }
2624                }
2625            }
2626
2627            void writeToParcelLocked(Parcel out) {
2628                out.writeLong(mUserTime);
2629                out.writeLong(mSystemTime);
2630                out.writeLong(mForegroundTime);
2631                out.writeInt(mStarts);
2632                out.writeLong(mLoadedUserTime);
2633                out.writeLong(mLoadedSystemTime);
2634                out.writeLong(mLoadedForegroundTime);
2635                out.writeInt(mLoadedStarts);
2636                out.writeLong(mUnpluggedUserTime);
2637                out.writeLong(mUnpluggedSystemTime);
2638                out.writeLong(mUnpluggedForegroundTime);
2639                out.writeInt(mUnpluggedStarts);
2640
2641                out.writeInt(mSpeedBins.length);
2642                for (int i = 0; i < mSpeedBins.length; i++) {
2643                    SamplingCounter c = mSpeedBins[i];
2644                    if (c != null) {
2645                        out.writeInt(1);
2646                        c.writeToParcel(out);
2647                    } else {
2648                        out.writeInt(0);
2649                    }
2650                }
2651            }
2652
2653            void readFromParcelLocked(Parcel in) {
2654                mUserTime = in.readLong();
2655                mSystemTime = in.readLong();
2656                mForegroundTime = in.readLong();
2657                mStarts = in.readInt();
2658                mLoadedUserTime = in.readLong();
2659                mLoadedSystemTime = in.readLong();
2660                mLoadedForegroundTime = in.readLong();
2661                mLoadedStarts = in.readInt();
2662                mLastUserTime = 0;
2663                mLastSystemTime = 0;
2664                mLastForegroundTime = 0;
2665                mLastStarts = 0;
2666                mUnpluggedUserTime = in.readLong();
2667                mUnpluggedSystemTime = in.readLong();
2668                mUnpluggedForegroundTime = in.readLong();
2669                mUnpluggedStarts = in.readInt();
2670
2671                int bins = in.readInt();
2672                int steps = getCpuSpeedSteps();
2673                mSpeedBins = new SamplingCounter[bins >= steps ? bins : steps];
2674                for (int i = 0; i < bins; i++) {
2675                    if (in.readInt() != 0) {
2676                        mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
2677                    }
2678                }
2679            }
2680
2681            public BatteryStatsImpl getBatteryStats() {
2682                return BatteryStatsImpl.this;
2683            }
2684
2685            public void addCpuTimeLocked(int utime, int stime) {
2686                mUserTime += utime;
2687                mSystemTime += stime;
2688            }
2689
2690            public void addForegroundTimeLocked(long ttime) {
2691                mForegroundTime += ttime;
2692            }
2693
2694            public void incStartsLocked() {
2695                mStarts++;
2696            }
2697
2698            @Override
2699            public long getUserTime(int which) {
2700                long val;
2701                if (which == STATS_LAST) {
2702                    val = mLastUserTime;
2703                } else {
2704                    val = mUserTime;
2705                    if (which == STATS_CURRENT) {
2706                        val -= mLoadedUserTime;
2707                    } else if (which == STATS_SINCE_UNPLUGGED) {
2708                        val -= mUnpluggedUserTime;
2709                    }
2710                }
2711                return val;
2712            }
2713
2714            @Override
2715            public long getSystemTime(int which) {
2716                long val;
2717                if (which == STATS_LAST) {
2718                    val = mLastSystemTime;
2719                } else {
2720                    val = mSystemTime;
2721                    if (which == STATS_CURRENT) {
2722                        val -= mLoadedSystemTime;
2723                    } else if (which == STATS_SINCE_UNPLUGGED) {
2724                        val -= mUnpluggedSystemTime;
2725                    }
2726                }
2727                return val;
2728            }
2729
2730            @Override
2731            public long getForegroundTime(int which) {
2732                long val;
2733                if (which == STATS_LAST) {
2734                    val = mLastForegroundTime;
2735                } else {
2736                    val = mForegroundTime;
2737                    if (which == STATS_CURRENT) {
2738                        val -= mLoadedForegroundTime;
2739                    } else if (which == STATS_SINCE_UNPLUGGED) {
2740                        val -= mUnpluggedForegroundTime;
2741                    }
2742                }
2743                return val;
2744            }
2745
2746            @Override
2747            public int getStarts(int which) {
2748                int val;
2749                if (which == STATS_LAST) {
2750                    val = mLastStarts;
2751                } else {
2752                    val = mStarts;
2753                    if (which == STATS_CURRENT) {
2754                        val -= mLoadedStarts;
2755                    } else if (which == STATS_SINCE_UNPLUGGED) {
2756                        val -= mUnpluggedStarts;
2757                    }
2758                }
2759                return val;
2760            }
2761
2762            /* Called by ActivityManagerService when CPU times are updated. */
2763            public void addSpeedStepTimes(long[] values) {
2764                for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
2765                    long amt = values[i];
2766                    if (amt != 0) {
2767                        SamplingCounter c = mSpeedBins[i];
2768                        if (c == null) {
2769                            mSpeedBins[i] = c = new SamplingCounter(mUnpluggables);
2770                        }
2771                        c.addCountAtomic(values[i]);
2772                    }
2773                }
2774            }
2775
2776            @Override
2777            public long getTimeAtCpuSpeedStep(int speedStep, int which) {
2778                if (speedStep < mSpeedBins.length) {
2779                    SamplingCounter c = mSpeedBins[speedStep];
2780                    return c != null ? c.getCountLocked(which) : 0;
2781                } else {
2782                    return 0;
2783                }
2784            }
2785        }
2786
2787        /**
2788         * The statistics associated with a particular package.
2789         */
2790        public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
2791            /**
2792             * Number of times this package has done something that could wake up the
2793             * device from sleep.
2794             */
2795            int mWakeups;
2796
2797            /**
2798             * Number of things that could wake up the device loaded from a
2799             * previous save.
2800             */
2801            int mLoadedWakeups;
2802
2803            /**
2804             * Number of things that could wake up the device as of the
2805             * last run.
2806             */
2807            int mLastWakeups;
2808
2809            /**
2810             * Number of things that could wake up the device as of the
2811             * last run.
2812             */
2813            int mUnpluggedWakeups;
2814
2815            /**
2816             * The statics we have collected for this package's services.
2817             */
2818            final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
2819
2820            Pkg() {
2821                mUnpluggables.add(this);
2822            }
2823
2824            public void unplug(long batteryUptime, long batteryRealtime) {
2825                mUnpluggedWakeups = mWakeups;
2826            }
2827
2828            public void plug(long batteryUptime, long batteryRealtime) {
2829            }
2830
2831            void detach() {
2832                mUnpluggables.remove(this);
2833            }
2834
2835            void readFromParcelLocked(Parcel in) {
2836                mWakeups = in.readInt();
2837                mLoadedWakeups = in.readInt();
2838                mLastWakeups = 0;
2839                mUnpluggedWakeups = in.readInt();
2840
2841                int numServs = in.readInt();
2842                mServiceStats.clear();
2843                for (int m = 0; m < numServs; m++) {
2844                    String serviceName = in.readString();
2845                    Uid.Pkg.Serv serv = new Serv();
2846                    mServiceStats.put(serviceName, serv);
2847
2848                    serv.readFromParcelLocked(in);
2849                }
2850            }
2851
2852            void writeToParcelLocked(Parcel out) {
2853                out.writeInt(mWakeups);
2854                out.writeInt(mLoadedWakeups);
2855                out.writeInt(mUnpluggedWakeups);
2856
2857                out.writeInt(mServiceStats.size());
2858                for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
2859                    out.writeString(servEntry.getKey());
2860                    Uid.Pkg.Serv serv = servEntry.getValue();
2861
2862                    serv.writeToParcelLocked(out);
2863                }
2864            }
2865
2866            @Override
2867            public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
2868                return mServiceStats;
2869            }
2870
2871            @Override
2872            public int getWakeups(int which) {
2873                int val;
2874                if (which == STATS_LAST) {
2875                    val = mLastWakeups;
2876                } else {
2877                    val = mWakeups;
2878                    if (which == STATS_CURRENT) {
2879                        val -= mLoadedWakeups;
2880                    } else if (which == STATS_SINCE_UNPLUGGED) {
2881                        val -= mUnpluggedWakeups;
2882                    }
2883                }
2884
2885                return val;
2886            }
2887
2888            /**
2889             * The statistics associated with a particular service.
2890             */
2891            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
2892                /**
2893                 * Total time (ms in battery uptime) the service has been left started.
2894                 */
2895                long mStartTime;
2896
2897                /**
2898                 * If service has been started and not yet stopped, this is
2899                 * when it was started.
2900                 */
2901                long mRunningSince;
2902
2903                /**
2904                 * True if we are currently running.
2905                 */
2906                boolean mRunning;
2907
2908                /**
2909                 * Total number of times startService() has been called.
2910                 */
2911                int mStarts;
2912
2913                /**
2914                 * Total time (ms in battery uptime) the service has been left launched.
2915                 */
2916                long mLaunchedTime;
2917
2918                /**
2919                 * If service has been launched and not yet exited, this is
2920                 * when it was launched (ms in battery uptime).
2921                 */
2922                long mLaunchedSince;
2923
2924                /**
2925                 * True if we are currently launched.
2926                 */
2927                boolean mLaunched;
2928
2929                /**
2930                 * Total number times the service has been launched.
2931                 */
2932                int mLaunches;
2933
2934                /**
2935                 * The amount of time spent started loaded from a previous save
2936                 * (ms in battery uptime).
2937                 */
2938                long mLoadedStartTime;
2939
2940                /**
2941                 * The number of starts loaded from a previous save.
2942                 */
2943                int mLoadedStarts;
2944
2945                /**
2946                 * The number of launches loaded from a previous save.
2947                 */
2948                int mLoadedLaunches;
2949
2950                /**
2951                 * The amount of time spent started as of the last run (ms
2952                 * in battery uptime).
2953                 */
2954                long mLastStartTime;
2955
2956                /**
2957                 * The number of starts as of the last run.
2958                 */
2959                int mLastStarts;
2960
2961                /**
2962                 * The number of launches as of the last run.
2963                 */
2964                int mLastLaunches;
2965
2966                /**
2967                 * The amount of time spent started when last unplugged (ms
2968                 * in battery uptime).
2969                 */
2970                long mUnpluggedStartTime;
2971
2972                /**
2973                 * The number of starts when last unplugged.
2974                 */
2975                int mUnpluggedStarts;
2976
2977                /**
2978                 * The number of launches when last unplugged.
2979                 */
2980                int mUnpluggedLaunches;
2981
2982                Serv() {
2983                    mUnpluggables.add(this);
2984                }
2985
2986                public void unplug(long batteryUptime, long batteryRealtime) {
2987                    mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
2988                    mUnpluggedStarts = mStarts;
2989                    mUnpluggedLaunches = mLaunches;
2990                }
2991
2992                public void plug(long batteryUptime, long batteryRealtime) {
2993                }
2994
2995                void detach() {
2996                    mUnpluggables.remove(this);
2997                }
2998
2999                void readFromParcelLocked(Parcel in) {
3000                    mStartTime = in.readLong();
3001                    mRunningSince = in.readLong();
3002                    mRunning = in.readInt() != 0;
3003                    mStarts = in.readInt();
3004                    mLaunchedTime = in.readLong();
3005                    mLaunchedSince = in.readLong();
3006                    mLaunched = in.readInt() != 0;
3007                    mLaunches = in.readInt();
3008                    mLoadedStartTime = in.readLong();
3009                    mLoadedStarts = in.readInt();
3010                    mLoadedLaunches = in.readInt();
3011                    mLastStartTime = 0;
3012                    mLastStarts = 0;
3013                    mLastLaunches = 0;
3014                    mUnpluggedStartTime = in.readLong();
3015                    mUnpluggedStarts = in.readInt();
3016                    mUnpluggedLaunches = in.readInt();
3017                }
3018
3019                void writeToParcelLocked(Parcel out) {
3020                    out.writeLong(mStartTime);
3021                    out.writeLong(mRunningSince);
3022                    out.writeInt(mRunning ? 1 : 0);
3023                    out.writeInt(mStarts);
3024                    out.writeLong(mLaunchedTime);
3025                    out.writeLong(mLaunchedSince);
3026                    out.writeInt(mLaunched ? 1 : 0);
3027                    out.writeInt(mLaunches);
3028                    out.writeLong(mLoadedStartTime);
3029                    out.writeInt(mLoadedStarts);
3030                    out.writeInt(mLoadedLaunches);
3031                    out.writeLong(mUnpluggedStartTime);
3032                    out.writeInt(mUnpluggedStarts);
3033                    out.writeInt(mUnpluggedLaunches);
3034                }
3035
3036                long getLaunchTimeToNowLocked(long batteryUptime) {
3037                    if (!mLaunched) return mLaunchedTime;
3038                    return mLaunchedTime + batteryUptime - mLaunchedSince;
3039                }
3040
3041                long getStartTimeToNowLocked(long batteryUptime) {
3042                    if (!mRunning) return mStartTime;
3043                    return mStartTime + batteryUptime - mRunningSince;
3044                }
3045
3046                public void startLaunchedLocked() {
3047                    if (!mLaunched) {
3048                        mLaunches++;
3049                        mLaunchedSince = getBatteryUptimeLocked();
3050                        mLaunched = true;
3051                    }
3052                }
3053
3054                public void stopLaunchedLocked() {
3055                    if (mLaunched) {
3056                        long time = getBatteryUptimeLocked() - mLaunchedSince;
3057                        if (time > 0) {
3058                            mLaunchedTime += time;
3059                        } else {
3060                            mLaunches--;
3061                        }
3062                        mLaunched = false;
3063                    }
3064                }
3065
3066                public void startRunningLocked() {
3067                    if (!mRunning) {
3068                        mStarts++;
3069                        mRunningSince = getBatteryUptimeLocked();
3070                        mRunning = true;
3071                    }
3072                }
3073
3074                public void stopRunningLocked() {
3075                    if (mRunning) {
3076                        long time = getBatteryUptimeLocked() - mRunningSince;
3077                        if (time > 0) {
3078                            mStartTime += time;
3079                        } else {
3080                            mStarts--;
3081                        }
3082                        mRunning = false;
3083                    }
3084                }
3085
3086                public BatteryStatsImpl getBatteryStats() {
3087                    return BatteryStatsImpl.this;
3088                }
3089
3090                @Override
3091                public int getLaunches(int which) {
3092                    int val;
3093
3094                    if (which == STATS_LAST) {
3095                        val = mLastLaunches;
3096                    } else {
3097                        val = mLaunches;
3098                        if (which == STATS_CURRENT) {
3099                            val -= mLoadedLaunches;
3100                        } else if (which == STATS_SINCE_UNPLUGGED) {
3101                            val -= mUnpluggedLaunches;
3102                        }
3103                    }
3104
3105                    return val;
3106                }
3107
3108                @Override
3109                public long getStartTime(long now, int which) {
3110                    long val;
3111                    if (which == STATS_LAST) {
3112                        val = mLastStartTime;
3113                    } else {
3114                        val = getStartTimeToNowLocked(now);
3115                        if (which == STATS_CURRENT) {
3116                            val -= mLoadedStartTime;
3117                        } else if (which == STATS_SINCE_UNPLUGGED) {
3118                            val -= mUnpluggedStartTime;
3119                        }
3120                    }
3121
3122                    return val;
3123                }
3124
3125                @Override
3126                public int getStarts(int which) {
3127                    int val;
3128                    if (which == STATS_LAST) {
3129                        val = mLastStarts;
3130                    } else {
3131                        val = mStarts;
3132                        if (which == STATS_CURRENT) {
3133                            val -= mLoadedStarts;
3134                        } else if (which == STATS_SINCE_UNPLUGGED) {
3135                            val -= mUnpluggedStarts;
3136                        }
3137                    }
3138
3139                    return val;
3140                }
3141            }
3142
3143            public BatteryStatsImpl getBatteryStats() {
3144                return BatteryStatsImpl.this;
3145            }
3146
3147            public void incWakeupsLocked() {
3148                mWakeups++;
3149            }
3150
3151            final Serv newServiceStatsLocked() {
3152                return new Serv();
3153            }
3154        }
3155
3156        /**
3157         * Retrieve the statistics object for a particular process, creating
3158         * if needed.
3159         */
3160        public Proc getProcessStatsLocked(String name) {
3161            Proc ps = mProcessStats.get(name);
3162            if (ps == null) {
3163                ps = new Proc();
3164                mProcessStats.put(name, ps);
3165            }
3166
3167            return ps;
3168        }
3169
3170        /**
3171         * Retrieve the statistics object for a particular service, creating
3172         * if needed.
3173         */
3174        public Pkg getPackageStatsLocked(String name) {
3175            Pkg ps = mPackageStats.get(name);
3176            if (ps == null) {
3177                ps = new Pkg();
3178                mPackageStats.put(name, ps);
3179            }
3180
3181            return ps;
3182        }
3183
3184        /**
3185         * Retrieve the statistics object for a particular service, creating
3186         * if needed.
3187         */
3188        public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
3189            Pkg ps = getPackageStatsLocked(pkg);
3190            Pkg.Serv ss = ps.mServiceStats.get(serv);
3191            if (ss == null) {
3192                ss = ps.newServiceStatsLocked();
3193                ps.mServiceStats.put(serv, ss);
3194            }
3195
3196            return ss;
3197        }
3198
3199        public StopwatchTimer getWakeTimerLocked(String name, int type) {
3200            Wakelock wl = mWakelockStats.get(name);
3201            if (wl == null) {
3202                if (mWakelockStats.size() > MAX_WAKELOCKS_PER_UID) {
3203                    name = BATCHED_WAKELOCK_NAME;
3204                    wl = mWakelockStats.get(name);
3205                }
3206                if (wl == null) {
3207                    wl = new Wakelock();
3208                    mWakelockStats.put(name, wl);
3209                }
3210            }
3211            StopwatchTimer t = null;
3212            switch (type) {
3213                case WAKE_TYPE_PARTIAL:
3214                    t = wl.mTimerPartial;
3215                    if (t == null) {
3216                        t = new StopwatchTimer(WAKE_TYPE_PARTIAL, mPartialTimers, mUnpluggables);
3217                        wl.mTimerPartial = t;
3218                    }
3219                    return t;
3220                case WAKE_TYPE_FULL:
3221                    t = wl.mTimerFull;
3222                    if (t == null) {
3223                        t = new StopwatchTimer(WAKE_TYPE_FULL, mFullTimers, mUnpluggables);
3224                        wl.mTimerFull = t;
3225                    }
3226                    return t;
3227                case WAKE_TYPE_WINDOW:
3228                    t = wl.mTimerWindow;
3229                    if (t == null) {
3230                        t = new StopwatchTimer(WAKE_TYPE_WINDOW, mWindowTimers, mUnpluggables);
3231                        wl.mTimerWindow = t;
3232                    }
3233                    return t;
3234                default:
3235                    throw new IllegalArgumentException("type=" + type);
3236            }
3237        }
3238
3239        public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
3240            Sensor se = mSensorStats.get(sensor);
3241            if (se == null) {
3242                if (!create) {
3243                    return null;
3244                }
3245                se = new Sensor(sensor);
3246                mSensorStats.put(sensor, se);
3247            }
3248            StopwatchTimer t = se.mTimer;
3249            if (t != null) {
3250                return t;
3251            }
3252            ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
3253            if (timers == null) {
3254                timers = new ArrayList<StopwatchTimer>();
3255                mSensorTimers.put(sensor, timers);
3256            }
3257            t = new StopwatchTimer(BatteryStats.SENSOR, timers, mUnpluggables);
3258            se.mTimer = t;
3259            return t;
3260        }
3261
3262        public void noteStartWakeLocked(String name, int type) {
3263            StopwatchTimer t = getWakeTimerLocked(name, type);
3264            if (t != null) {
3265                t.startRunningLocked(BatteryStatsImpl.this);
3266            }
3267        }
3268
3269        public void noteStopWakeLocked(String name, int type) {
3270            StopwatchTimer t = getWakeTimerLocked(name, type);
3271            if (t != null) {
3272                t.stopRunningLocked(BatteryStatsImpl.this);
3273            }
3274        }
3275
3276        public void noteStartSensor(int sensor) {
3277            StopwatchTimer t = getSensorTimerLocked(sensor, true);
3278            if (t != null) {
3279                t.startRunningLocked(BatteryStatsImpl.this);
3280            }
3281        }
3282
3283        public void noteStopSensor(int sensor) {
3284            // Don't create a timer if one doesn't already exist
3285            StopwatchTimer t = getSensorTimerLocked(sensor, false);
3286            if (t != null) {
3287                t.stopRunningLocked(BatteryStatsImpl.this);
3288            }
3289        }
3290
3291        public void noteStartGps() {
3292            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
3293            if (t != null) {
3294                t.startRunningLocked(BatteryStatsImpl.this);
3295            }
3296        }
3297
3298        public void noteStopGps() {
3299            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
3300            if (t != null) {
3301                t.stopRunningLocked(BatteryStatsImpl.this);
3302            }
3303        }
3304
3305        public BatteryStatsImpl getBatteryStats() {
3306            return BatteryStatsImpl.this;
3307        }
3308    }
3309
3310    public BatteryStatsImpl(String filename) {
3311        mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
3312        mStartCount++;
3313        mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables);
3314        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3315            mScreenBrightnessTimer[i] = new StopwatchTimer(-100-i, null, mUnpluggables);
3316        }
3317        mInputEventCounter = new Counter(mUnpluggables);
3318        mPhoneOnTimer = new StopwatchTimer(-2, null, mUnpluggables);
3319        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3320            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(-200-i, null, mUnpluggables);
3321        }
3322        mPhoneSignalScanningTimer = new StopwatchTimer(-200+1, null, mUnpluggables);
3323        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3324            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(-300-i, null, mUnpluggables);
3325        }
3326        mWifiOnTimer = new StopwatchTimer(-3, null, mUnpluggables);
3327        mWifiRunningTimer = new StopwatchTimer(-4, null, mUnpluggables);
3328        mBluetoothOnTimer = new StopwatchTimer(-5, null, mUnpluggables);
3329        mAudioOnTimer = new StopwatchTimer(-6, null, mUnpluggables);
3330        mVideoOnTimer = new StopwatchTimer(-7, null, mUnpluggables);
3331        mOnBattery = mOnBatteryInternal = false;
3332        initTimes();
3333        mTrackBatteryPastUptime = 0;
3334        mTrackBatteryPastRealtime = 0;
3335        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
3336        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
3337        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
3338        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
3339        mDischargeStartLevel = 0;
3340        mDischargeUnplugLevel = 0;
3341        mDischargeCurrentLevel = 0;
3342        mLowDischargeAmountSinceCharge = 0;
3343        mHighDischargeAmountSinceCharge = 0;
3344    }
3345
3346    public BatteryStatsImpl(Parcel p) {
3347        mFile = null;
3348        readFromParcel(p);
3349    }
3350
3351    public void setNumSpeedSteps(int steps) {
3352        if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
3353    }
3354
3355    public void setRadioScanningTimeout(long timeout) {
3356        if (mPhoneSignalScanningTimer != null) {
3357            mPhoneSignalScanningTimer.setTimeout(timeout);
3358        }
3359    }
3360
3361    @Override
3362    public HistoryItem getHistory() {
3363        return mHistory;
3364    }
3365
3366    @Override
3367    public int getStartCount() {
3368        return mStartCount;
3369    }
3370
3371    public boolean isOnBattery() {
3372        return mOnBattery;
3373    }
3374
3375    void initTimes() {
3376        mBatteryRealtime = mTrackBatteryPastUptime = 0;
3377        mBatteryUptime = mTrackBatteryPastRealtime = 0;
3378        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
3379        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
3380        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
3381        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
3382    }
3383
3384    public void resetAllStatsLocked() {
3385        mStartCount = 0;
3386        initTimes();
3387        mScreenOnTimer.reset(false);
3388        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3389            mScreenBrightnessTimer[i].reset(false);
3390        }
3391        mInputEventCounter.reset(false);
3392        mPhoneOnTimer.reset(false);
3393        mAudioOnTimer.reset(false);
3394        mVideoOnTimer.reset(false);
3395        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3396            mPhoneSignalStrengthsTimer[i].reset(false);
3397        }
3398        mPhoneSignalScanningTimer.reset(false);
3399        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3400            mPhoneDataConnectionsTimer[i].reset(false);
3401        }
3402        mWifiOnTimer.reset(false);
3403        mWifiRunningTimer.reset(false);
3404        mBluetoothOnTimer.reset(false);
3405
3406        for (int i=0; i<mUidStats.size(); i++) {
3407            if (mUidStats.valueAt(i).reset()) {
3408                mUidStats.remove(mUidStats.keyAt(i));
3409                i--;
3410            }
3411        }
3412
3413        if (mKernelWakelockStats.size() > 0) {
3414            for (SamplingTimer timer : mKernelWakelockStats.values()) {
3415                mUnpluggables.remove(timer);
3416            }
3417            mKernelWakelockStats.clear();
3418        }
3419
3420        clearHistoryLocked();
3421    }
3422
3423    void setOnBattery(boolean onBattery, int oldStatus, int level) {
3424        synchronized(this) {
3425            boolean doWrite = false;
3426            mOnBattery = mOnBatteryInternal = onBattery;
3427
3428            long uptime = SystemClock.uptimeMillis() * 1000;
3429            long mSecRealtime = SystemClock.elapsedRealtime();
3430            long realtime = mSecRealtime * 1000;
3431            if (onBattery) {
3432                // We will reset our status if we are unplugging after the
3433                // battery was last full, or the level is at 100, or
3434                // we have gone through a significant charge (from a very low
3435                // level to a now very high level).
3436                if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
3437                        || level >= 100
3438                        || (mDischargeCurrentLevel < 20 && level > 90)) {
3439                    doWrite = true;
3440                    resetAllStatsLocked();
3441                    mDischargeStartLevel = level;
3442                    mLowDischargeAmountSinceCharge = 0;
3443                    mHighDischargeAmountSinceCharge = 0;
3444                }
3445                updateKernelWakelocksLocked();
3446                mHistoryCur.batteryLevel = (byte)level;
3447                mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
3448                if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
3449                        + Integer.toHexString(mHistoryCur.states));
3450                addHistoryRecordLocked(mSecRealtime);
3451                mTrackBatteryUptimeStart = uptime;
3452                mTrackBatteryRealtimeStart = realtime;
3453                mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
3454                mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
3455                mDischargeCurrentLevel = mDischargeUnplugLevel = level;
3456                doUnplugLocked(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
3457            } else {
3458                updateKernelWakelocksLocked();
3459                mHistoryCur.batteryLevel = (byte)level;
3460                mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
3461                if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
3462                        + Integer.toHexString(mHistoryCur.states));
3463                addHistoryRecordLocked(mSecRealtime);
3464                mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
3465                mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
3466                mDischargeCurrentLevel = level;
3467                if (level < mDischargeUnplugLevel) {
3468                    mLowDischargeAmountSinceCharge = mDischargeUnplugLevel-level-1;
3469                    mHighDischargeAmountSinceCharge = mDischargeUnplugLevel-level;
3470                }
3471                doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
3472            }
3473            if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
3474                if (mFile != null) {
3475                    writeLocked();
3476                }
3477            }
3478        }
3479    }
3480
3481    // This should probably be exposed in the API, though it's not critical
3482    private static final int BATTERY_PLUGGED_NONE = 0;
3483
3484    public void setBatteryState(int status, int health, int plugType, int level,
3485            int temp, int volt) {
3486        boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
3487        int oldStatus = mHistoryCur.batteryStatus;
3488        if (!mHaveBatteryLevel) {
3489            mHaveBatteryLevel = true;
3490            // We start out assuming that the device is plugged in (not
3491            // on battery).  If our first report is now that we are indeed
3492            // plugged in, then twiddle our state to correctly reflect that
3493            // since we won't be going through the full setOnBattery().
3494            if (onBattery == mOnBattery) {
3495                if (onBattery) {
3496                    mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
3497                } else {
3498                    mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
3499                }
3500            }
3501            oldStatus = status;
3502        }
3503        if (onBattery) {
3504            mDischargeCurrentLevel = level;
3505            mRecordingHistory = true;
3506        }
3507        if (onBattery != mOnBattery) {
3508            mHistoryCur.batteryLevel = (byte)level;
3509            mHistoryCur.batteryStatus = (byte)status;
3510            mHistoryCur.batteryHealth = (byte)health;
3511            mHistoryCur.batteryPlugType = (byte)plugType;
3512            mHistoryCur.batteryTemperature = (char)temp;
3513            mHistoryCur.batteryVoltage = (char)volt;
3514            setOnBattery(onBattery, oldStatus, level);
3515        } else {
3516            boolean changed = false;
3517            if (mHistoryCur.batteryLevel != level) {
3518                mHistoryCur.batteryLevel = (byte)level;
3519                changed = true;
3520            }
3521            if (mHistoryCur.batteryStatus != status) {
3522                mHistoryCur.batteryStatus = (byte)status;
3523                changed = true;
3524            }
3525            if (mHistoryCur.batteryHealth != health) {
3526                mHistoryCur.batteryHealth = (byte)health;
3527                changed = true;
3528            }
3529            if (mHistoryCur.batteryPlugType != plugType) {
3530                mHistoryCur.batteryPlugType = (byte)plugType;
3531                changed = true;
3532            }
3533            if (mHistoryCur.batteryTemperature != temp) {
3534                mHistoryCur.batteryTemperature = (char)temp;
3535                changed = true;
3536            }
3537            if (mHistoryCur.batteryVoltage != volt) {
3538                mHistoryCur.batteryVoltage = (char)volt;
3539                changed = true;
3540            }
3541            if (changed) {
3542                addHistoryRecordLocked(SystemClock.elapsedRealtime());
3543            }
3544        }
3545        if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
3546            // We don't record history while we are plugged in and fully charged.
3547            // The next time we are unplugged, history will be cleared.
3548            mRecordingHistory = false;
3549        }
3550    }
3551
3552    public void updateKernelWakelocksLocked() {
3553        Map<String, KernelWakelockStats> m = readKernelWakelockStats();
3554
3555        if (m == null) {
3556            // Not crashing might make board bringup easier.
3557            Slog.w(TAG, "Couldn't get kernel wake lock stats");
3558            return;
3559        }
3560
3561        for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
3562            String name = ent.getKey();
3563            KernelWakelockStats kws = ent.getValue();
3564
3565            SamplingTimer kwlt = mKernelWakelockStats.get(name);
3566            if (kwlt == null) {
3567                kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
3568                        true /* track reported values */);
3569                mKernelWakelockStats.put(name, kwlt);
3570            }
3571            kwlt.updateCurrentReportedCount(kws.mCount);
3572            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
3573            kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
3574        }
3575
3576        if (m.size() != mKernelWakelockStats.size()) {
3577            // Set timers to stale if they didn't appear in /proc/wakelocks this time.
3578            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
3579                SamplingTimer st = ent.getValue();
3580                if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
3581                    st.setStale();
3582                }
3583            }
3584        }
3585    }
3586
3587    public long getAwakeTimeBattery() {
3588        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
3589    }
3590
3591    public long getAwakeTimePlugged() {
3592        return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
3593    }
3594
3595    @Override
3596    public long computeUptime(long curTime, int which) {
3597        switch (which) {
3598            case STATS_SINCE_CHARGED: return mUptime + (curTime-mUptimeStart);
3599            case STATS_LAST: return mLastUptime;
3600            case STATS_CURRENT: return (curTime-mUptimeStart);
3601            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
3602        }
3603        return 0;
3604    }
3605
3606    @Override
3607    public long computeRealtime(long curTime, int which) {
3608        switch (which) {
3609            case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
3610            case STATS_LAST: return mLastRealtime;
3611            case STATS_CURRENT: return (curTime-mRealtimeStart);
3612            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
3613        }
3614        return 0;
3615    }
3616
3617    @Override
3618    public long computeBatteryUptime(long curTime, int which) {
3619        switch (which) {
3620            case STATS_SINCE_CHARGED:
3621                return mBatteryUptime + getBatteryUptime(curTime);
3622            case STATS_LAST:
3623                return mBatteryLastUptime;
3624            case STATS_CURRENT:
3625                return getBatteryUptime(curTime);
3626            case STATS_SINCE_UNPLUGGED:
3627                return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
3628        }
3629        return 0;
3630    }
3631
3632    @Override
3633    public long computeBatteryRealtime(long curTime, int which) {
3634        switch (which) {
3635            case STATS_SINCE_CHARGED:
3636                return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
3637            case STATS_LAST:
3638                return mBatteryLastRealtime;
3639            case STATS_CURRENT:
3640                return getBatteryRealtimeLocked(curTime);
3641            case STATS_SINCE_UNPLUGGED:
3642                return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
3643        }
3644        return 0;
3645    }
3646
3647    long getBatteryUptimeLocked(long curTime) {
3648        long time = mTrackBatteryPastUptime;
3649        if (mOnBatteryInternal) {
3650            time += curTime - mTrackBatteryUptimeStart;
3651        }
3652        return time;
3653    }
3654
3655    long getBatteryUptimeLocked() {
3656        return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
3657    }
3658
3659    @Override
3660    public long getBatteryUptime(long curTime) {
3661        return getBatteryUptimeLocked(curTime);
3662    }
3663
3664    long getBatteryRealtimeLocked(long curTime) {
3665        long time = mTrackBatteryPastRealtime;
3666        if (mOnBatteryInternal) {
3667            time += curTime - mTrackBatteryRealtimeStart;
3668        }
3669        return time;
3670    }
3671
3672    @Override
3673    public long getBatteryRealtime(long curTime) {
3674        return getBatteryRealtimeLocked(curTime);
3675    }
3676
3677    private long getTcpBytes(long current, long[] dataBytes, int which) {
3678        if (which == STATS_LAST) {
3679            return dataBytes[STATS_LAST];
3680        } else {
3681            if (which == STATS_SINCE_UNPLUGGED) {
3682                if (dataBytes[STATS_SINCE_UNPLUGGED] < 0) {
3683                    return dataBytes[STATS_LAST];
3684                } else {
3685                    return current - dataBytes[STATS_SINCE_UNPLUGGED];
3686                }
3687            } else if (which == STATS_SINCE_CHARGED) {
3688                return (current - dataBytes[STATS_CURRENT]) + dataBytes[STATS_SINCE_CHARGED];
3689            }
3690            return current - dataBytes[STATS_CURRENT];
3691        }
3692    }
3693
3694    /** Only STATS_UNPLUGGED works properly */
3695    public long getMobileTcpBytesSent(int which) {
3696        return getTcpBytes(TrafficStats.getMobileTxBytes(), mMobileDataTx, which);
3697    }
3698
3699    /** Only STATS_UNPLUGGED works properly */
3700    public long getMobileTcpBytesReceived(int which) {
3701        return getTcpBytes(TrafficStats.getMobileRxBytes(), mMobileDataRx, which);
3702    }
3703
3704    /** Only STATS_UNPLUGGED works properly */
3705    public long getTotalTcpBytesSent(int which) {
3706        return getTcpBytes(TrafficStats.getTotalTxBytes(), mTotalDataTx, which);
3707    }
3708
3709    /** Only STATS_UNPLUGGED works properly */
3710    public long getTotalTcpBytesReceived(int which) {
3711        return getTcpBytes(TrafficStats.getTotalRxBytes(), mTotalDataRx, which);
3712    }
3713
3714    @Override
3715    public int getDischargeStartLevel() {
3716        synchronized(this) {
3717            return getDischargeStartLevelLocked();
3718        }
3719    }
3720
3721    public int getDischargeStartLevelLocked() {
3722            return mDischargeUnplugLevel;
3723    }
3724
3725    @Override
3726    public int getDischargeCurrentLevel() {
3727        synchronized(this) {
3728            return getDischargeCurrentLevelLocked();
3729        }
3730    }
3731
3732    public int getDischargeCurrentLevelLocked() {
3733            return mDischargeCurrentLevel;
3734    }
3735
3736    @Override
3737    public int getLowDischargeAmountSinceCharge() {
3738        synchronized(this) {
3739            return mLowDischargeAmountSinceCharge;
3740        }
3741    }
3742
3743    @Override
3744    public int getHighDischargeAmountSinceCharge() {
3745        synchronized(this) {
3746            return mHighDischargeAmountSinceCharge;
3747        }
3748    }
3749
3750    @Override
3751    public int getCpuSpeedSteps() {
3752        return sNumSpeedSteps;
3753    }
3754
3755    /**
3756     * Retrieve the statistics object for a particular uid, creating if needed.
3757     */
3758    public Uid getUidStatsLocked(int uid) {
3759        Uid u = mUidStats.get(uid);
3760        if (u == null) {
3761            u = new Uid(uid);
3762            mUidStats.put(uid, u);
3763        }
3764        return u;
3765    }
3766
3767    /**
3768     * Remove the statistics object for a particular uid.
3769     */
3770    public void removeUidStatsLocked(int uid) {
3771        mUidStats.remove(uid);
3772    }
3773
3774    /**
3775     * Retrieve the statistics object for a particular process, creating
3776     * if needed.
3777     */
3778    public Uid.Proc getProcessStatsLocked(int uid, String name) {
3779        Uid u = getUidStatsLocked(uid);
3780        return u.getProcessStatsLocked(name);
3781    }
3782
3783    /**
3784     * Retrieve the statistics object for a particular process, given
3785     * the name of the process.
3786     * @param name process name
3787     * @return the statistics object for the process
3788     */
3789    public Uid.Proc getProcessStatsLocked(String name, int pid) {
3790        int uid;
3791        if (mUidCache.containsKey(name)) {
3792            uid = mUidCache.get(name);
3793        } else {
3794            uid = Process.getUidForPid(pid);
3795            mUidCache.put(name, uid);
3796        }
3797        Uid u = getUidStatsLocked(uid);
3798        return u.getProcessStatsLocked(name);
3799    }
3800
3801    /**
3802     * Retrieve the statistics object for a particular process, creating
3803     * if needed.
3804     */
3805    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
3806        Uid u = getUidStatsLocked(uid);
3807        return u.getPackageStatsLocked(pkg);
3808    }
3809
3810    /**
3811     * Retrieve the statistics object for a particular service, creating
3812     * if needed.
3813     */
3814    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
3815        Uid u = getUidStatsLocked(uid);
3816        return u.getServiceStatsLocked(pkg, name);
3817    }
3818
3819    public void shutdownLocked() {
3820        writeLocked();
3821        mShuttingDown = true;
3822    }
3823
3824    public void writeLocked() {
3825        if (mFile == null) {
3826            Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
3827            return;
3828        }
3829
3830        if (mShuttingDown) {
3831            return;
3832        }
3833
3834        try {
3835            FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
3836            Parcel out = Parcel.obtain();
3837            writeSummaryToParcel(out);
3838            stream.write(out.marshall());
3839            out.recycle();
3840
3841            stream.flush();
3842            stream.close();
3843            mFile.commit();
3844
3845            mLastWriteTime = SystemClock.elapsedRealtime();
3846            return;
3847        } catch (IOException e) {
3848            Slog.w("BatteryStats", "Error writing battery statistics", e);
3849        }
3850        mFile.rollback();
3851    }
3852
3853    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
3854        int pos = 0;
3855        int avail = stream.available();
3856        byte[] data = new byte[avail];
3857        while (true) {
3858            int amt = stream.read(data, pos, data.length-pos);
3859            //Log.i("foo", "Read " + amt + " bytes at " + pos
3860            //        + " of avail " + data.length);
3861            if (amt <= 0) {
3862                //Log.i("foo", "**** FINISHED READING: pos=" + pos
3863                //        + " len=" + data.length);
3864                return data;
3865            }
3866            pos += amt;
3867            avail = stream.available();
3868            if (avail > data.length-pos) {
3869                byte[] newData = new byte[pos+avail];
3870                System.arraycopy(data, 0, newData, 0, pos);
3871                data = newData;
3872            }
3873        }
3874    }
3875
3876    public void readLocked() {
3877        if (mFile == null) {
3878            Slog.w("BatteryStats", "readLocked: no file associated with this instance");
3879            return;
3880        }
3881
3882        mUidStats.clear();
3883
3884        try {
3885            File file = mFile.chooseForRead();
3886            if (!file.exists()) {
3887                return;
3888            }
3889            FileInputStream stream = new FileInputStream(file);
3890
3891            byte[] raw = readFully(stream);
3892            Parcel in = Parcel.obtain();
3893            in.unmarshall(raw, 0, raw.length);
3894            in.setDataPosition(0);
3895            stream.close();
3896
3897            readSummaryFromParcel(in);
3898        } catch(java.io.IOException e) {
3899            Slog.e("BatteryStats", "Error reading battery statistics", e);
3900        }
3901
3902        addHistoryRecordLocked(SystemClock.elapsedRealtime(), HistoryItem.CMD_START);
3903    }
3904
3905    public int describeContents() {
3906        return 0;
3907    }
3908
3909    void readHistory(Parcel in) {
3910        mHistory = mHistoryEnd = mHistoryCache = null;
3911        mHistoryBaseTime = 0;
3912        long time;
3913        while ((time=in.readLong()) >= 0) {
3914            HistoryItem rec = new HistoryItem(time, in);
3915            addHistoryRecordLocked(rec);
3916            if (rec.time > mHistoryBaseTime) {
3917                mHistoryBaseTime = rec.time;
3918            }
3919        }
3920
3921        long oldnow = SystemClock.elapsedRealtime() - (5*60*100);
3922        if (oldnow > 0) {
3923            // If the system process has restarted, but not the entire
3924            // system, then the mHistoryBaseTime already accounts for
3925            // much of the elapsed time.  We thus want to adjust it back,
3926            // to avoid large gaps in the data.  We determine we are
3927            // in this case by arbitrarily saying it is so if at this
3928            // point in boot the elapsed time is already more than 5 seconds.
3929            mHistoryBaseTime -= oldnow;
3930        }
3931    }
3932
3933    void writeHistory(Parcel out) {
3934        HistoryItem rec = mHistory;
3935        while (rec != null) {
3936            if (rec.time >= 0) rec.writeToParcel(out, 0);
3937            rec = rec.next;
3938        }
3939        out.writeLong(-1);
3940    }
3941
3942    private void readSummaryFromParcel(Parcel in) {
3943        final int version = in.readInt();
3944        if (version != VERSION) {
3945            Slog.w("BatteryStats", "readFromParcel: version got " + version
3946                + ", expected " + VERSION + "; erasing old stats");
3947            return;
3948        }
3949
3950        readHistory(in);
3951
3952        mStartCount = in.readInt();
3953        mBatteryUptime = in.readLong();
3954        mBatteryRealtime = in.readLong();
3955        mUptime = in.readLong();
3956        mRealtime = in.readLong();
3957        mDischargeUnplugLevel = in.readInt();
3958        mDischargeCurrentLevel = in.readInt();
3959        mLowDischargeAmountSinceCharge = in.readInt();
3960        mHighDischargeAmountSinceCharge = in.readInt();
3961
3962        mStartCount++;
3963
3964        mScreenOn = false;
3965        mScreenOnTimer.readSummaryFromParcelLocked(in);
3966        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
3967            mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
3968        }
3969        mInputEventCounter.readSummaryFromParcelLocked(in);
3970        mPhoneOn = false;
3971        mPhoneOnTimer.readSummaryFromParcelLocked(in);
3972        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
3973            mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
3974        }
3975        mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
3976        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
3977            mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
3978        }
3979        mWifiOn = false;
3980        mWifiOnTimer.readSummaryFromParcelLocked(in);
3981        mWifiRunning = false;
3982        mWifiRunningTimer.readSummaryFromParcelLocked(in);
3983        mBluetoothOn = false;
3984        mBluetoothOnTimer.readSummaryFromParcelLocked(in);
3985
3986        int NKW = in.readInt();
3987        if (NKW > 10000) {
3988            Slog.w(TAG, "File corrupt: too many kernel wake locks " + NKW);
3989            return;
3990        }
3991        for (int ikw = 0; ikw < NKW; ikw++) {
3992            if (in.readInt() != 0) {
3993                String kwltName = in.readString();
3994                getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
3995            }
3996        }
3997
3998        sNumSpeedSteps = in.readInt();
3999
4000        final int NU = in.readInt();
4001        if (NU > 10000) {
4002            Slog.w(TAG, "File corrupt: too many uids " + NU);
4003            return;
4004        }
4005        for (int iu = 0; iu < NU; iu++) {
4006            int uid = in.readInt();
4007            Uid u = new Uid(uid);
4008            mUidStats.put(uid, u);
4009
4010            u.mWifiTurnedOn = false;
4011            if (in.readInt() != 0) {
4012                u.mWifiTurnedOnTimer.readSummaryFromParcelLocked(in);
4013            }
4014            u.mFullWifiLockOut = false;
4015            if (in.readInt() != 0) {
4016                u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
4017            }
4018            u.mScanWifiLockOut = false;
4019            if (in.readInt() != 0) {
4020                u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
4021            }
4022            u.mWifiMulticastEnabled = false;
4023            if (in.readInt() != 0) {
4024                u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
4025            }
4026            u.mAudioTurnedOn = false;
4027            if (in.readInt() != 0) {
4028                u.mAudioTurnedOnTimer.readSummaryFromParcelLocked(in);
4029            }
4030            u.mVideoTurnedOn = false;
4031            if (in.readInt() != 0) {
4032                u.mVideoTurnedOnTimer.readSummaryFromParcelLocked(in);
4033            }
4034
4035            if (in.readInt() != 0) {
4036                if (u.mUserActivityCounters == null) {
4037                    u.initUserActivityLocked();
4038                }
4039                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
4040                    u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
4041                }
4042            }
4043
4044            int NW = in.readInt();
4045            if (NW > 10000) {
4046                Slog.w(TAG, "File corrupt: too many wake locks " + NW);
4047                return;
4048            }
4049            for (int iw = 0; iw < NW; iw++) {
4050                String wlName = in.readString();
4051                if (in.readInt() != 0) {
4052                    u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
4053                }
4054                if (in.readInt() != 0) {
4055                    u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
4056                }
4057                if (in.readInt() != 0) {
4058                    u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
4059                }
4060            }
4061
4062            int NP = in.readInt();
4063            if (NP > 10000) {
4064                Slog.w(TAG, "File corrupt: too many sensors " + NP);
4065                return;
4066            }
4067            for (int is = 0; is < NP; is++) {
4068                int seNumber = in.readInt();
4069                if (in.readInt() != 0) {
4070                    u.getSensorTimerLocked(seNumber, true)
4071                            .readSummaryFromParcelLocked(in);
4072                }
4073            }
4074
4075            NP = in.readInt();
4076            if (NP > 10000) {
4077                Slog.w(TAG, "File corrupt: too many processes " + NP);
4078                return;
4079            }
4080            for (int ip = 0; ip < NP; ip++) {
4081                String procName = in.readString();
4082                Uid.Proc p = u.getProcessStatsLocked(procName);
4083                p.mUserTime = p.mLoadedUserTime = in.readLong();
4084                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
4085                p.mStarts = p.mLoadedStarts = in.readInt();
4086            }
4087
4088            NP = in.readInt();
4089            if (NP > 10000) {
4090                Slog.w(TAG, "File corrupt: too many packages " + NP);
4091                return;
4092            }
4093            for (int ip = 0; ip < NP; ip++) {
4094                String pkgName = in.readString();
4095                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
4096                p.mWakeups = p.mLoadedWakeups = in.readInt();
4097                final int NS = in.readInt();
4098                for (int is = 0; is < NS; is++) {
4099                    String servName = in.readString();
4100                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
4101                    s.mStartTime = s.mLoadedStartTime = in.readLong();
4102                    s.mStarts = s.mLoadedStarts = in.readInt();
4103                    s.mLaunches = s.mLoadedLaunches = in.readInt();
4104                }
4105            }
4106
4107            u.mLoadedTcpBytesReceived = in.readLong();
4108            u.mLoadedTcpBytesSent = in.readLong();
4109        }
4110    }
4111
4112    /**
4113     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
4114     * disk.  This format does not allow a lossless round-trip.
4115     *
4116     * @param out the Parcel to be written to.
4117     */
4118    public void writeSummaryToParcel(Parcel out) {
4119        final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
4120        final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
4121        final long NOW = getBatteryUptimeLocked(NOW_SYS);
4122        final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
4123
4124        out.writeInt(VERSION);
4125
4126        writeHistory(out);
4127
4128        out.writeInt(mStartCount);
4129        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_SINCE_CHARGED));
4130        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
4131        out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
4132        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
4133        out.writeInt(mDischargeUnplugLevel);
4134        out.writeInt(mDischargeCurrentLevel);
4135        out.writeInt(mLowDischargeAmountSinceCharge);
4136        out.writeInt(mHighDischargeAmountSinceCharge);
4137
4138        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4139        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4140            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
4141        }
4142        mInputEventCounter.writeSummaryFromParcelLocked(out);
4143        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4144        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
4145            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
4146        }
4147        mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4148        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4149            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
4150        }
4151        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4152        mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4153        mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4154
4155        out.writeInt(mKernelWakelockStats.size());
4156        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
4157            Timer kwlt = ent.getValue();
4158            if (kwlt != null) {
4159                out.writeInt(1);
4160                out.writeString(ent.getKey());
4161                ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
4162            } else {
4163                out.writeInt(0);
4164            }
4165        }
4166
4167        out.writeInt(sNumSpeedSteps);
4168        final int NU = mUidStats.size();
4169        out.writeInt(NU);
4170        for (int iu = 0; iu < NU; iu++) {
4171            out.writeInt(mUidStats.keyAt(iu));
4172            Uid u = mUidStats.valueAt(iu);
4173
4174            if (u.mWifiTurnedOnTimer != null) {
4175                out.writeInt(1);
4176                u.mWifiTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4177            } else {
4178                out.writeInt(0);
4179            }
4180            if (u.mFullWifiLockTimer != null) {
4181                out.writeInt(1);
4182                u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4183            } else {
4184                out.writeInt(0);
4185            }
4186            if (u.mScanWifiLockTimer != null) {
4187                out.writeInt(1);
4188                u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4189            } else {
4190                out.writeInt(0);
4191            }
4192            if (u.mWifiMulticastTimer != null) {
4193                out.writeInt(1);
4194                u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4195            } else {
4196                out.writeInt(0);
4197            }
4198            if (u.mAudioTurnedOnTimer != null) {
4199                out.writeInt(1);
4200                u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4201            } else {
4202                out.writeInt(0);
4203            }
4204            if (u.mVideoTurnedOnTimer != null) {
4205                out.writeInt(1);
4206                u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4207            } else {
4208                out.writeInt(0);
4209            }
4210
4211            if (u.mUserActivityCounters == null) {
4212                out.writeInt(0);
4213            } else {
4214                out.writeInt(1);
4215                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
4216                    u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
4217                }
4218            }
4219
4220            int NW = u.mWakelockStats.size();
4221            out.writeInt(NW);
4222            if (NW > 0) {
4223                for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
4224                        : u.mWakelockStats.entrySet()) {
4225                    out.writeString(ent.getKey());
4226                    Uid.Wakelock wl = ent.getValue();
4227                    if (wl.mTimerFull != null) {
4228                        out.writeInt(1);
4229                        wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
4230                    } else {
4231                        out.writeInt(0);
4232                    }
4233                    if (wl.mTimerPartial != null) {
4234                        out.writeInt(1);
4235                        wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
4236                    } else {
4237                        out.writeInt(0);
4238                    }
4239                    if (wl.mTimerWindow != null) {
4240                        out.writeInt(1);
4241                        wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
4242                    } else {
4243                        out.writeInt(0);
4244                    }
4245                }
4246            }
4247
4248            int NSE = u.mSensorStats.size();
4249            out.writeInt(NSE);
4250            if (NSE > 0) {
4251                for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
4252                        : u.mSensorStats.entrySet()) {
4253                    out.writeInt(ent.getKey());
4254                    Uid.Sensor se = ent.getValue();
4255                    if (se.mTimer != null) {
4256                        out.writeInt(1);
4257                        se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
4258                    } else {
4259                        out.writeInt(0);
4260                    }
4261                }
4262            }
4263
4264            int NP = u.mProcessStats.size();
4265            out.writeInt(NP);
4266            if (NP > 0) {
4267                for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
4268                    : u.mProcessStats.entrySet()) {
4269                    out.writeString(ent.getKey());
4270                    Uid.Proc ps = ent.getValue();
4271                    out.writeLong(ps.mUserTime);
4272                    out.writeLong(ps.mSystemTime);
4273                    out.writeInt(ps.mStarts);
4274                }
4275            }
4276
4277            NP = u.mPackageStats.size();
4278            out.writeInt(NP);
4279            if (NP > 0) {
4280                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
4281                    : u.mPackageStats.entrySet()) {
4282                    out.writeString(ent.getKey());
4283                    Uid.Pkg ps = ent.getValue();
4284                    out.writeInt(ps.mWakeups);
4285                    final int NS = ps.mServiceStats.size();
4286                    out.writeInt(NS);
4287                    if (NS > 0) {
4288                        for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
4289                                : ps.mServiceStats.entrySet()) {
4290                            out.writeString(sent.getKey());
4291                            BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
4292                            long time = ss.getStartTimeToNowLocked(NOW);
4293                            out.writeLong(time);
4294                            out.writeInt(ss.mStarts);
4295                            out.writeInt(ss.mLaunches);
4296                        }
4297                    }
4298                }
4299            }
4300
4301            out.writeLong(u.getTcpBytesReceived(STATS_SINCE_CHARGED));
4302            out.writeLong(u.getTcpBytesSent(STATS_SINCE_CHARGED));
4303        }
4304    }
4305
4306    public void readFromParcel(Parcel in) {
4307        readFromParcelLocked(in);
4308    }
4309
4310    void readFromParcelLocked(Parcel in) {
4311        int magic = in.readInt();
4312        if (magic != MAGIC) {
4313            throw new ParcelFormatException("Bad magic number");
4314        }
4315
4316        readHistory(in);
4317
4318        mStartCount = in.readInt();
4319        mBatteryUptime = in.readLong();
4320        mBatteryLastUptime = 0;
4321        mBatteryRealtime = in.readLong();
4322        mBatteryLastRealtime = 0;
4323        mScreenOn = false;
4324        mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables, in);
4325        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4326            mScreenBrightnessTimer[i] = new StopwatchTimer(-100-i, null, mUnpluggables, in);
4327        }
4328        mInputEventCounter = new Counter(mUnpluggables, in);
4329        mPhoneOn = false;
4330        mPhoneOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
4331        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
4332            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(-200-i, null, mUnpluggables, in);
4333        }
4334        mPhoneSignalScanningTimer = new StopwatchTimer(-200+1, null, mUnpluggables, in);
4335        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4336            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(-300-i, null, mUnpluggables, in);
4337        }
4338        mWifiOn = false;
4339        mWifiOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
4340        mWifiRunning = false;
4341        mWifiRunningTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
4342        mBluetoothOn = false;
4343        mBluetoothOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
4344        mUptime = in.readLong();
4345        mUptimeStart = in.readLong();
4346        mLastUptime = 0;
4347        mRealtime = in.readLong();
4348        mRealtimeStart = in.readLong();
4349        mLastRealtime = 0;
4350        mOnBattery = in.readInt() != 0;
4351        mOnBatteryInternal = false; // we are no longer really running.
4352        mTrackBatteryPastUptime = in.readLong();
4353        mTrackBatteryUptimeStart = in.readLong();
4354        mTrackBatteryPastRealtime = in.readLong();
4355        mTrackBatteryRealtimeStart = in.readLong();
4356        mUnpluggedBatteryUptime = in.readLong();
4357        mUnpluggedBatteryRealtime = in.readLong();
4358        mDischargeUnplugLevel = in.readInt();
4359        mDischargeCurrentLevel = in.readInt();
4360        mLowDischargeAmountSinceCharge = in.readInt();
4361        mHighDischargeAmountSinceCharge = in.readInt();
4362        mLastWriteTime = in.readLong();
4363
4364        mMobileDataRx[STATS_LAST] = in.readLong();
4365        mMobileDataRx[STATS_SINCE_UNPLUGGED] = -1;
4366        mMobileDataTx[STATS_LAST] = in.readLong();
4367        mMobileDataTx[STATS_SINCE_UNPLUGGED] = -1;
4368        mTotalDataRx[STATS_LAST] = in.readLong();
4369        mTotalDataRx[STATS_SINCE_UNPLUGGED] = -1;
4370        mTotalDataTx[STATS_LAST] = in.readLong();
4371        mTotalDataTx[STATS_SINCE_UNPLUGGED] = -1;
4372
4373        mRadioDataUptime = in.readLong();
4374        mRadioDataStart = -1;
4375
4376        mBluetoothPingCount = in.readInt();
4377        mBluetoothPingStart = -1;
4378
4379        mKernelWakelockStats.clear();
4380        int NKW = in.readInt();
4381        for (int ikw = 0; ikw < NKW; ikw++) {
4382            if (in.readInt() != 0) {
4383                String wakelockName = in.readString();
4384                in.readInt(); // Extra 0/1 written by Timer.writeTimerToParcel
4385                SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
4386                mKernelWakelockStats.put(wakelockName, kwlt);
4387            }
4388        }
4389
4390        mPartialTimers.clear();
4391        mFullTimers.clear();
4392        mWindowTimers.clear();
4393
4394        sNumSpeedSteps = in.readInt();
4395
4396        int numUids = in.readInt();
4397        mUidStats.clear();
4398        for (int i = 0; i < numUids; i++) {
4399            int uid = in.readInt();
4400            Uid u = new Uid(uid);
4401            u.readFromParcelLocked(mUnpluggables, in);
4402            mUidStats.append(uid, u);
4403        }
4404    }
4405
4406    public void writeToParcel(Parcel out, int flags) {
4407        writeToParcelLocked(out, true, flags);
4408    }
4409
4410    public void writeToParcelWithoutUids(Parcel out, int flags) {
4411        writeToParcelLocked(out, false, flags);
4412    }
4413
4414    @SuppressWarnings("unused")
4415    void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
4416        final long uSecUptime = SystemClock.uptimeMillis() * 1000;
4417        final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
4418        final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
4419        final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
4420
4421        out.writeInt(MAGIC);
4422
4423        writeHistory(out);
4424
4425        out.writeInt(mStartCount);
4426        out.writeLong(mBatteryUptime);
4427        out.writeLong(mBatteryRealtime);
4428        mScreenOnTimer.writeToParcel(out, batteryRealtime);
4429        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4430            mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
4431        }
4432        mInputEventCounter.writeToParcel(out);
4433        mPhoneOnTimer.writeToParcel(out, batteryRealtime);
4434        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
4435            mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
4436        }
4437        mPhoneSignalScanningTimer.writeToParcel(out, batteryRealtime);
4438        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4439            mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
4440        }
4441        mWifiOnTimer.writeToParcel(out, batteryRealtime);
4442        mWifiRunningTimer.writeToParcel(out, batteryRealtime);
4443        mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
4444        out.writeLong(mUptime);
4445        out.writeLong(mUptimeStart);
4446        out.writeLong(mRealtime);
4447        out.writeLong(mRealtimeStart);
4448        out.writeInt(mOnBattery ? 1 : 0);
4449        out.writeLong(batteryUptime);
4450        out.writeLong(mTrackBatteryUptimeStart);
4451        out.writeLong(batteryRealtime);
4452        out.writeLong(mTrackBatteryRealtimeStart);
4453        out.writeLong(mUnpluggedBatteryUptime);
4454        out.writeLong(mUnpluggedBatteryRealtime);
4455        out.writeInt(mDischargeUnplugLevel);
4456        out.writeInt(mDischargeCurrentLevel);
4457        out.writeInt(mLowDischargeAmountSinceCharge);
4458        out.writeInt(mHighDischargeAmountSinceCharge);
4459        out.writeLong(mLastWriteTime);
4460
4461        out.writeLong(getMobileTcpBytesReceived(STATS_SINCE_UNPLUGGED));
4462        out.writeLong(getMobileTcpBytesSent(STATS_SINCE_UNPLUGGED));
4463        out.writeLong(getTotalTcpBytesReceived(STATS_SINCE_UNPLUGGED));
4464        out.writeLong(getTotalTcpBytesSent(STATS_SINCE_UNPLUGGED));
4465
4466        // Write radio uptime for data
4467        out.writeLong(getRadioDataUptime());
4468
4469        out.writeInt(getBluetoothPingCount());
4470
4471        if (inclUids) {
4472            out.writeInt(mKernelWakelockStats.size());
4473            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
4474                SamplingTimer kwlt = ent.getValue();
4475                if (kwlt != null) {
4476                    out.writeInt(1);
4477                    out.writeString(ent.getKey());
4478                    Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
4479                } else {
4480                    out.writeInt(0);
4481                }
4482            }
4483        } else {
4484            out.writeInt(0);
4485        }
4486
4487        out.writeInt(sNumSpeedSteps);
4488
4489        if (inclUids) {
4490            int size = mUidStats.size();
4491            out.writeInt(size);
4492            for (int i = 0; i < size; i++) {
4493                out.writeInt(mUidStats.keyAt(i));
4494                Uid uid = mUidStats.valueAt(i);
4495
4496                uid.writeToParcelLocked(out, batteryRealtime);
4497            }
4498        } else {
4499            out.writeInt(0);
4500        }
4501    }
4502
4503    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
4504        new Parcelable.Creator<BatteryStatsImpl>() {
4505        public BatteryStatsImpl createFromParcel(Parcel in) {
4506            return new BatteryStatsImpl(in);
4507        }
4508
4509        public BatteryStatsImpl[] newArray(int size) {
4510            return new BatteryStatsImpl[size];
4511        }
4512    };
4513
4514    public void dumpLocked(PrintWriter pw) {
4515        if (DEBUG) {
4516            Printer pr = new PrintWriterPrinter(pw);
4517            pr.println("*** Screen timer:");
4518            mScreenOnTimer.logState(pr, "  ");
4519            for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
4520                pr.println("*** Screen brightness #" + i + ":");
4521                mScreenBrightnessTimer[i].logState(pr, "  ");
4522            }
4523            pr.println("*** Input event counter:");
4524            mInputEventCounter.logState(pr, "  ");
4525            pr.println("*** Phone timer:");
4526            mPhoneOnTimer.logState(pr, "  ");
4527            for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
4528                pr.println("*** Signal strength #" + i + ":");
4529                mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
4530            }
4531            pr.println("*** Signal scanning :");
4532            mPhoneSignalScanningTimer.logState(pr, "  ");
4533            for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
4534                pr.println("*** Data connection type #" + i + ":");
4535                mPhoneDataConnectionsTimer[i].logState(pr, "  ");
4536            }
4537            pr.println("*** Wifi timer:");
4538            mWifiOnTimer.logState(pr, "  ");
4539            pr.println("*** WifiRunning timer:");
4540            mWifiRunningTimer.logState(pr, "  ");
4541            pr.println("*** Bluetooth timer:");
4542            mBluetoothOnTimer.logState(pr, "  ");
4543        }
4544        super.dumpLocked(pw);
4545    }
4546}
4547