blob: a9e5052d13190ab1a4e67507da570a2079812078 [file] [log] [blame]
/*
* Copyright (C) 2006-2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.os;
import com.android.internal.util.JournaledFile;
import android.bluetooth.BluetoothHeadset;
import android.net.TrafficStats;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Handler;
import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFormatException;
import android.os.Parcelable;
import android.os.Process;
import android.os.SystemClock;
import android.os.WorkSource;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
import android.util.SparseArray;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
/**
* All information we are collecting about things that can happen that impact
* battery life. All times are represented in microseconds except where indicated
* otherwise.
*/
public final class BatteryStatsImpl extends BatteryStats {
private static final String TAG = "BatteryStatsImpl";
private static final boolean DEBUG = false;
private static final boolean DEBUG_HISTORY = false;
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
private static final int VERSION = 52;
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
// No, really, THIS is the maximum number of items we will record in the history.
private static final int MAX_MAX_HISTORY_ITEMS = 3000;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
// in to one common name.
private static final int MAX_WAKELOCKS_PER_UID = 30;
private static final String BATCHED_WAKELOCK_NAME = "*overflow*";
private static int sNumSpeedSteps;
private final JournaledFile mFile;
static final int MSG_UPDATE_WAKELOCKS = 1;
static final int MSG_REPORT_POWER_CHANGE = 2;
static final long DELAY_UPDATE_WAKELOCKS = 5*1000;
public interface BatteryCallback {
public void batteryNeedsCpuUpdate();
public void batteryPowerChanged(boolean onBattery);
}
final class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
BatteryCallback cb = mCallback;
switch (msg.what) {
case MSG_UPDATE_WAKELOCKS:
if (cb != null) {
cb.batteryNeedsCpuUpdate();
}
break;
case MSG_REPORT_POWER_CHANGE:
if (cb != null) {
cb.batteryPowerChanged(msg.arg1 != 0);
}
break;
}
}
}
private final MyHandler mHandler;
private BatteryCallback mCallback;
/**
* The statistics we have collected organized by uids.
*/
final SparseArray<BatteryStatsImpl.Uid> mUidStats =
new SparseArray<BatteryStatsImpl.Uid>();
// A set of pools of currently active timers. When a timer is queried, we will divide the
// elapsed time by the number of active timers to arrive at that timer's share of the time.
// In order to do this, we must refresh each timer whenever the number of active timers
// changes.
final ArrayList<StopwatchTimer> mPartialTimers = new ArrayList<StopwatchTimer>();
final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<StopwatchTimer>();
final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<StopwatchTimer>();
final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers
= new SparseArray<ArrayList<StopwatchTimer>>();
final ArrayList<StopwatchTimer> mWifiRunningTimers = new ArrayList<StopwatchTimer>();
final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<StopwatchTimer>();
final ArrayList<StopwatchTimer> mScanWifiLockTimers = new ArrayList<StopwatchTimer>();
final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<StopwatchTimer>();
// Last partial timers we use for distributing CPU usage.
final ArrayList<StopwatchTimer> mLastPartialTimers = new ArrayList<StopwatchTimer>();
// These are the objects that will want to do something when the device
// is unplugged from power.
final ArrayList<Unpluggable> mUnpluggables = new ArrayList<Unpluggable>();
boolean mShuttingDown;
long mHistoryBaseTime;
boolean mHaveBatteryLevel = false;
boolean mRecordingHistory = true;
int mNumHistoryItems;
HistoryItem mHistory;
HistoryItem mHistoryEnd;
HistoryItem mHistoryLastEnd;
HistoryItem mHistoryCache;
final HistoryItem mHistoryCur = new HistoryItem();
int mStartCount;
long mBatteryUptime;
long mBatteryLastUptime;
long mBatteryRealtime;
long mBatteryLastRealtime;
long mUptime;
long mUptimeStart;
long mLastUptime;
long mRealtime;
long mRealtimeStart;
long mLastRealtime;
boolean mScreenOn;
StopwatchTimer mScreenOnTimer;
int mScreenBrightnessBin = -1;
final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
Counter mInputEventCounter;
boolean mPhoneOn;
StopwatchTimer mPhoneOnTimer;
boolean mAudioOn;
StopwatchTimer mAudioOnTimer;
boolean mVideoOn;
StopwatchTimer mVideoOnTimer;
int mPhoneSignalStrengthBin = -1;
final StopwatchTimer[] mPhoneSignalStrengthsTimer =
new StopwatchTimer[NUM_SIGNAL_STRENGTH_BINS];
StopwatchTimer mPhoneSignalScanningTimer;
int mPhoneDataConnectionType = -1;
final StopwatchTimer[] mPhoneDataConnectionsTimer =
new StopwatchTimer[NUM_DATA_CONNECTION_TYPES];
boolean mWifiOn;
StopwatchTimer mWifiOnTimer;
int mWifiOnUid = -1;
boolean mGlobalWifiRunning;
StopwatchTimer mGlobalWifiRunningTimer;
boolean mBluetoothOn;
StopwatchTimer mBluetoothOnTimer;
/** Bluetooth headset object */
BluetoothHeadset mBtHeadset;
/**
* These provide time bases that discount the time the device is plugged
* in to power.
*/
boolean mOnBattery;
boolean mOnBatteryInternal;
long mTrackBatteryPastUptime;
long mTrackBatteryUptimeStart;
long mTrackBatteryPastRealtime;
long mTrackBatteryRealtimeStart;
long mUnpluggedBatteryUptime;
long mUnpluggedBatteryRealtime;
/*
* These keep track of battery levels (1-100) at the last plug event and the last unplug event.
*/
int mDischargeStartLevel;
int mDischargeUnplugLevel;
int mDischargeCurrentLevel;
int mLowDischargeAmountSinceCharge;
int mHighDischargeAmountSinceCharge;
long mLastWriteTime = 0; // Milliseconds
// Mobile data transferred while on battery
private long[] mMobileDataTx = new long[4];
private long[] mMobileDataRx = new long[4];
private long[] mTotalDataTx = new long[4];
private long[] mTotalDataRx = new long[4];
private long mRadioDataUptime;
private long mRadioDataStart;
private int mBluetoothPingCount;
private int mBluetoothPingStart = -1;
private int mPhoneServiceState = -1;
/*
* Holds a SamplingTimer associated with each kernel wakelock name being tracked.
*/
private final HashMap<String, SamplingTimer> mKernelWakelockStats =
new HashMap<String, SamplingTimer>();
public Map<String, ? extends SamplingTimer> getKernelWakelockStats() {
return mKernelWakelockStats;
}
private static int sKernelWakelockUpdateVersion = 0;
private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
Process.PROC_TAB_TERM|Process.PROC_OUT_STRING, // 0: name
Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 1: count
Process.PROC_TAB_TERM,
Process.PROC_TAB_TERM,
Process.PROC_TAB_TERM,
Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 5: totalTime
};
private final String[] mProcWakelocksName = new String[3];
private final long[] mProcWakelocksData = new long[3];
/*
* Used as a buffer for reading in data from /proc/wakelocks before it is processed and added
* to mKernelWakelockStats.
*/
private final Map<String, KernelWakelockStats> mProcWakelockFileStats =
new HashMap<String, KernelWakelockStats>();
private HashMap<String, Integer> mUidCache = new HashMap<String, Integer>();
// For debugging
public BatteryStatsImpl() {
mFile = null;
mHandler = null;
}
public static interface Unpluggable {
void unplug(long batteryUptime, long batteryRealtime);
void plug(long batteryUptime, long batteryRealtime);
}
/**
* State for keeping track of counting information.
*/
public static class Counter extends BatteryStats.Counter implements Unpluggable {
final AtomicInteger mCount = new AtomicInteger();
final ArrayList<Unpluggable> mUnpluggables;
int mLoadedCount;
int mLastCount;
int mUnpluggedCount;
int mPluggedCount;
Counter(ArrayList<Unpluggable> unpluggables, Parcel in) {
mUnpluggables = unpluggables;
mPluggedCount = in.readInt();
mCount.set(mPluggedCount);
mLoadedCount = in.readInt();
mLastCount = 0;
mUnpluggedCount = in.readInt();
unpluggables.add(this);
}
Counter(ArrayList<Unpluggable> unpluggables) {
mUnpluggables = unpluggables;
unpluggables.add(this);
}
public void writeToParcel(Parcel out) {
out.writeInt(mCount.get());
out.writeInt(mLoadedCount);
out.writeInt(mUnpluggedCount);
}
public void unplug(long batteryUptime, long batteryRealtime) {
mUnpluggedCount = mPluggedCount;
mCount.set(mPluggedCount);
}
public void plug(long batteryUptime, long batteryRealtime) {
mPluggedCount = mCount.get();
}
/**
* Writes a possibly null Counter to a Parcel.
*
* @param out the Parcel to be written to.
* @param counter a Counter, or null.
*/
public static void writeCounterToParcel(Parcel out, Counter counter) {
if (counter == null) {
out.writeInt(0); // indicates null
return;
}
out.writeInt(1); // indicates non-null
counter.writeToParcel(out);
}
@Override
public int getCountLocked(int which) {
int val;
if (which == STATS_LAST) {
val = mLastCount;
} else {
val = mCount.get();
if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedCount;
} else if (which != STATS_SINCE_CHARGED) {
val -= mLoadedCount;
}
}
return val;
}
public void logState(Printer pw, String prefix) {
pw.println(prefix + "mCount=" + mCount.get()
+ " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
+ " mUnpluggedCount=" + mUnpluggedCount
+ " mPluggedCount=" + mPluggedCount);
}
void stepAtomic() {
mCount.incrementAndGet();
}
/**
* Clear state of this counter.
*/
void reset(boolean detachIfReset) {
mCount.set(0);
mLoadedCount = mLastCount = mPluggedCount = mUnpluggedCount = 0;
if (detachIfReset) {
detach();
}
}
void detach() {
mUnpluggables.remove(this);
}
void writeSummaryFromParcelLocked(Parcel out) {
int count = mCount.get();
out.writeInt(count);
}
void readSummaryFromParcelLocked(Parcel in) {
mLoadedCount = in.readInt();
mCount.set(mLoadedCount);
mLastCount = 0;
mUnpluggedCount = mPluggedCount = mLoadedCount;
}
}
public static class SamplingCounter extends Counter {
SamplingCounter(ArrayList<Unpluggable> unpluggables, Parcel in) {
super(unpluggables, in);
}
SamplingCounter(ArrayList<Unpluggable> unpluggables) {
super(unpluggables);
}
public void addCountAtomic(long count) {
mCount.addAndGet((int)count);
}
}
/**
* State for keeping track of timing information.
*/
public static abstract class Timer extends BatteryStats.Timer implements Unpluggable {
final int mType;
final ArrayList<Unpluggable> mUnpluggables;
int mCount;
int mLoadedCount;
int mLastCount;
int mUnpluggedCount;
// Times are in microseconds for better accuracy when dividing by the
// lock count, and are in "battery realtime" units.
/**
* The total time we have accumulated since the start of the original
* boot, to the last time something interesting happened in the
* current run.
*/
long mTotalTime;
/**
* The total time we loaded for the previous runs. Subtract this from
* mTotalTime to find the time for the current run of the system.
*/
long mLoadedTime;
/**
* The run time of the last run of the system, as loaded from the
* saved data.
*/
long mLastTime;
/**
* The value of mTotalTime when unplug() was last called. Subtract
* this from mTotalTime to find the time since the last unplug from
* power.
*/
long mUnpluggedTime;
/**
* Constructs from a parcel.
* @param type
* @param unpluggables
* @param powerType
* @param in
*/
Timer(int type, ArrayList<Unpluggable> unpluggables, Parcel in) {
mType = type;
mUnpluggables = unpluggables;
mCount = in.readInt();
mLoadedCount = in.readInt();
mLastCount = 0;
mUnpluggedCount = in.readInt();
mTotalTime = in.readLong();
mLoadedTime = in.readLong();
mLastTime = 0;
mUnpluggedTime = in.readLong();
unpluggables.add(this);
}
Timer(int type, ArrayList<Unpluggable> unpluggables) {
mType = type;
mUnpluggables = unpluggables;
unpluggables.add(this);
}
protected abstract long computeRunTimeLocked(long curBatteryRealtime);
protected abstract int computeCurrentCountLocked();
/**
* Clear state of this timer. Returns true if the timer is inactive
* so can be completely dropped.
*/
boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
mTotalTime = mLoadedTime = mLastTime = 0;
mCount = mLoadedCount = mLastCount = 0;
if (detachIfReset) {
detach();
}
return true;
}
void detach() {
mUnpluggables.remove(this);
}
public void writeToParcel(Parcel out, long batteryRealtime) {
out.writeInt(mCount);
out.writeInt(mLoadedCount);
out.writeInt(mUnpluggedCount);
out.writeLong(computeRunTimeLocked(batteryRealtime));
out.writeLong(mLoadedTime);
out.writeLong(mUnpluggedTime);
}
public void unplug(long batteryUptime, long batteryRealtime) {
if (DEBUG && mType < 0) {
Log.v(TAG, "unplug #" + mType + ": realtime=" + batteryRealtime
+ " old mUnpluggedTime=" + mUnpluggedTime
+ " old mUnpluggedCount=" + mUnpluggedCount);
}
mUnpluggedTime = computeRunTimeLocked(batteryRealtime);
mUnpluggedCount = mCount;
if (DEBUG && mType < 0) {
Log.v(TAG, "unplug #" + mType
+ ": new mUnpluggedTime=" + mUnpluggedTime
+ " new mUnpluggedCount=" + mUnpluggedCount);
}
}
public void plug(long batteryUptime, long batteryRealtime) {
if (DEBUG && mType < 0) {
Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime
+ " old mTotalTime=" + mTotalTime);
}
mTotalTime = computeRunTimeLocked(batteryRealtime);
mCount = computeCurrentCountLocked();
if (DEBUG && mType < 0) {
Log.v(TAG, "plug #" + mType
+ ": new mTotalTime=" + mTotalTime);
}
}
/**
* Writes a possibly null Timer to a Parcel.
*
* @param out the Parcel to be written to.
* @param timer a Timer, or null.
*/
public static void writeTimerToParcel(Parcel out, Timer timer,
long batteryRealtime) {
if (timer == null) {
out.writeInt(0); // indicates null
return;
}
out.writeInt(1); // indicates non-null
timer.writeToParcel(out, batteryRealtime);
}
@Override
public long getTotalTimeLocked(long batteryRealtime, int which) {
long val;
if (which == STATS_LAST) {
val = mLastTime;
} else {
val = computeRunTimeLocked(batteryRealtime);
if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedTime;
} else if (which != STATS_SINCE_CHARGED) {
val -= mLoadedTime;
}
}
return val;
}
@Override
public int getCountLocked(int which) {
int val;
if (which == STATS_LAST) {
val = mLastCount;
} else {
val = computeCurrentCountLocked();
if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedCount;
} else if (which != STATS_SINCE_CHARGED) {
val -= mLoadedCount;
}
}
return val;
}
public void logState(Printer pw, String prefix) {
pw.println(prefix + " mCount=" + mCount
+ " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
+ " mUnpluggedCount=" + mUnpluggedCount);
pw.println(prefix + "mTotalTime=" + mTotalTime
+ " mLoadedTime=" + mLoadedTime);
pw.println(prefix + "mLastTime=" + mLastTime
+ " mUnpluggedTime=" + mUnpluggedTime);
}
void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
long runTime = computeRunTimeLocked(batteryRealtime);
// Divide by 1000 for backwards compatibility
out.writeLong((runTime + 500) / 1000);
out.writeInt(mCount);
}
void readSummaryFromParcelLocked(Parcel in) {
// Multiply by 1000 for backwards compatibility
mTotalTime = mLoadedTime = in.readLong() * 1000;
mLastTime = 0;
mUnpluggedTime = mTotalTime;
mCount = mLoadedCount = in.readInt();
mLastCount = 0;
mUnpluggedCount = mCount;
}
}
public static final class SamplingTimer extends Timer {
/**
* The most recent reported count from /proc/wakelocks.
*/
int mCurrentReportedCount;
/**
* The reported count from /proc/wakelocks when unplug() was last
* called.
*/
int mUnpluggedReportedCount;
/**
* The most recent reported total_time from /proc/wakelocks.
*/
long mCurrentReportedTotalTime;
/**
* The reported total_time from /proc/wakelocks when unplug() was last
* called.
*/
long mUnpluggedReportedTotalTime;
/**
* Whether we are currently in a discharge cycle.
*/
boolean mInDischarge;
/**
* Whether we are currently recording reported values.
*/
boolean mTrackingReportedValues;
/*
* A sequnce counter, incremented once for each update of the stats.
*/
int mUpdateVersion;
SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge, Parcel in) {
super(0, unpluggables, in);
mCurrentReportedCount = in.readInt();
mUnpluggedReportedCount = in.readInt();
mCurrentReportedTotalTime = in.readLong();
mUnpluggedReportedTotalTime = in.readLong();
mTrackingReportedValues = in.readInt() == 1;
mInDischarge = inDischarge;
}
SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge,
boolean trackReportedValues) {
super(0, unpluggables);
mTrackingReportedValues = trackReportedValues;
mInDischarge = inDischarge;
}
public void setStale() {
mTrackingReportedValues = false;
mUnpluggedReportedTotalTime = 0;
mUnpluggedReportedCount = 0;
}
public void setUpdateVersion(int version) {
mUpdateVersion = version;
}
public int getUpdateVersion() {
return mUpdateVersion;
}
public void updateCurrentReportedCount(int count) {
if (mInDischarge && mUnpluggedReportedCount == 0) {
// Updating the reported value for the first time.
mUnpluggedReportedCount = count;
// If we are receiving an update update mTrackingReportedValues;
mTrackingReportedValues = true;
}
mCurrentReportedCount = count;
}
public void updateCurrentReportedTotalTime(long totalTime) {
if (mInDischarge && mUnpluggedReportedTotalTime == 0) {
// Updating the reported value for the first time.
mUnpluggedReportedTotalTime = totalTime;
// If we are receiving an update update mTrackingReportedValues;
mTrackingReportedValues = true;
}
mCurrentReportedTotalTime = totalTime;
}
public void unplug(long batteryUptime, long batteryRealtime) {
super.unplug(batteryUptime, batteryRealtime);
if (mTrackingReportedValues) {
mUnpluggedReportedTotalTime = mCurrentReportedTotalTime;
mUnpluggedReportedCount = mCurrentReportedCount;
}
mInDischarge = true;
}
public void plug(long batteryUptime, long batteryRealtime) {
super.plug(batteryUptime, batteryRealtime);
mInDischarge = false;
}
public void logState(Printer pw, String prefix) {
super.logState(pw, prefix);
pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount
+ " mUnpluggedReportedCount=" + mUnpluggedReportedCount
+ " mCurrentReportedTotalTime=" + mCurrentReportedTotalTime
+ " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTime);
}
protected long computeRunTimeLocked(long curBatteryRealtime) {
return mTotalTime + (mInDischarge && mTrackingReportedValues
? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0);
}
protected int computeCurrentCountLocked() {
return mCount + (mInDischarge && mTrackingReportedValues
? mCurrentReportedCount - mUnpluggedReportedCount : 0);
}
public void writeToParcel(Parcel out, long batteryRealtime) {
super.writeToParcel(out, batteryRealtime);
out.writeInt(mCurrentReportedCount);
out.writeInt(mUnpluggedReportedCount);
out.writeLong(mCurrentReportedTotalTime);
out.writeLong(mUnpluggedReportedTotalTime);
out.writeInt(mTrackingReportedValues ? 1 : 0);
}
boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
super.reset(stats, detachIfReset);
setStale();
return true;
}
void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
super.writeSummaryFromParcelLocked(out, batteryRealtime);
out.writeLong(mCurrentReportedTotalTime);
out.writeInt(mCurrentReportedCount);
out.writeInt(mTrackingReportedValues ? 1 : 0);
}
void readSummaryFromParcelLocked(Parcel in) {
super.readSummaryFromParcelLocked(in);
mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong();
mUnpluggedReportedCount = mCurrentReportedCount = in.readInt();
mTrackingReportedValues = in.readInt() == 1;
}
}
/**
* State for keeping track of timing information.
*/
public static final class StopwatchTimer extends Timer {
final Uid mUid;
final ArrayList<StopwatchTimer> mTimerPool;
int mNesting;
/**
* The last time at which we updated the timer. If mNesting is > 0,
* subtract this from the current battery time to find the amount of
* time we have been running since we last computed an update.
*/
long mUpdateTime;
/**
* The total time at which the timer was acquired, to determine if it
* was actually held for an interesting duration.
*/
long mAcquireTime;
long mTimeout;
/**
* For partial wake locks, keep track of whether we are in the list
* to consume CPU cycles.
*/
boolean mInList;
StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
ArrayList<Unpluggable> unpluggables, Parcel in) {
super(type, unpluggables, in);
mUid = uid;
mTimerPool = timerPool;
mUpdateTime = in.readLong();
}
StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
ArrayList<Unpluggable> unpluggables) {
super(type, unpluggables);
mUid = uid;
mTimerPool = timerPool;
}
void setTimeout(long timeout) {
mTimeout = timeout;
}
public void writeToParcel(Parcel out, long batteryRealtime) {
super.writeToParcel(out, batteryRealtime);
out.writeLong(mUpdateTime);
}
public void plug(long batteryUptime, long batteryRealtime) {
if (mNesting > 0) {
if (DEBUG && mType < 0) {
Log.v(TAG, "old mUpdateTime=" + mUpdateTime);
}
super.plug(batteryUptime, batteryRealtime);
mUpdateTime = batteryRealtime;
if (DEBUG && mType < 0) {
Log.v(TAG, "new mUpdateTime=" + mUpdateTime);
}
}
}
public void logState(Printer pw, String prefix) {
super.logState(pw, prefix);
pw.println(prefix + "mNesting=" + mNesting + "mUpdateTime=" + mUpdateTime
+ " mAcquireTime=" + mAcquireTime);
}
void startRunningLocked(BatteryStatsImpl stats) {
if (mNesting++ == 0) {
mUpdateTime = stats.getBatteryRealtimeLocked(
SystemClock.elapsedRealtime() * 1000);
if (mTimerPool != null) {
// Accumulate time to all currently active timers before adding
// this new one to the pool.
refreshTimersLocked(stats, mTimerPool);
// Add this timer to the active pool
mTimerPool.add(this);
}
// Increment the count
mCount++;
mAcquireTime = mTotalTime;
if (DEBUG && mType < 0) {
Log.v(TAG, "start #" + mType + ": mUpdateTime=" + mUpdateTime
+ " mTotalTime=" + mTotalTime + " mCount=" + mCount
+ " mAcquireTime=" + mAcquireTime);
}
}
}
boolean isRunningLocked() {
return mNesting > 0;
}
void stopRunningLocked(BatteryStatsImpl stats) {
// Ignore attempt to stop a timer that isn't running
if (mNesting == 0) {
return;
}
if (--mNesting == 0) {
if (mTimerPool != null) {
// Accumulate time to all active counters, scaled by the total
// active in the pool, before taking this one out of the pool.
refreshTimersLocked(stats, mTimerPool);
// Remove this timer from the active pool
mTimerPool.remove(this);
} else {
final long realtime = SystemClock.elapsedRealtime() * 1000;
final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
mNesting = 1;
mTotalTime = computeRunTimeLocked(batteryRealtime);
mNesting = 0;
}
if (DEBUG && mType < 0) {
Log.v(TAG, "stop #" + mType + ": mUpdateTime=" + mUpdateTime
+ " mTotalTime=" + mTotalTime + " mCount=" + mCount
+ " mAcquireTime=" + mAcquireTime);
}
if (mTotalTime == mAcquireTime) {
// If there was no change in the time, then discard this
// count. A somewhat cheezy strategy, but hey.
mCount--;
}
}
}
// Update the total time for all other running Timers with the same type as this Timer
// due to a change in timer count
private static void refreshTimersLocked(final BatteryStatsImpl stats,
final ArrayList<StopwatchTimer> pool) {
final long realtime = SystemClock.elapsedRealtime() * 1000;
final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
final int N = pool.size();
for (int i=N-1; i>= 0; i--) {
final StopwatchTimer t = pool.get(i);
long heldTime = batteryRealtime - t.mUpdateTime;
if (heldTime > 0) {
t.mTotalTime += heldTime / N;
}
t.mUpdateTime = batteryRealtime;
}
}
@Override
protected long computeRunTimeLocked(long curBatteryRealtime) {
if (mTimeout > 0 && curBatteryRealtime > mUpdateTime + mTimeout) {
curBatteryRealtime = mUpdateTime + mTimeout;
}
return mTotalTime + (mNesting > 0
? (curBatteryRealtime - mUpdateTime)
/ (mTimerPool != null ? mTimerPool.size() : 1)
: 0);
}
@Override
protected int computeCurrentCountLocked() {
return mCount;
}
boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
boolean canDetach = mNesting <= 0;
super.reset(stats, canDetach && detachIfReset);
if (mNesting > 0) {
mUpdateTime = stats.getBatteryRealtimeLocked(
SystemClock.elapsedRealtime() * 1000);
}
mAcquireTime = mTotalTime;
return canDetach;
}
void detach() {
super.detach();
if (mTimerPool != null) {
mTimerPool.remove(this);
}
}
void readSummaryFromParcelLocked(Parcel in) {
super.readSummaryFromParcelLocked(in);
mNesting = 0;
}
}
private final Map<String, KernelWakelockStats> readKernelWakelockStats() {
byte[] buffer = new byte[4096];
int len;
try {
FileInputStream is = new FileInputStream("/proc/wakelocks");
len = is.read(buffer);
is.close();
if (len > 0) {
int i;
for (i=0; i<len; i++) {
if (buffer[i] == '\0') {
len = i;
break;
}
}
}
} catch (java.io.FileNotFoundException e) {
return null;
} catch (java.io.IOException e) {
return null;
}
return parseProcWakelocks(buffer, len);
}
private final Map<String, KernelWakelockStats> parseProcWakelocks(
byte[] wlBuffer, int len) {
String name;
int count;
long totalTime;
int startIndex, endIndex;
int numUpdatedWlNames = 0;
// Advance past the first line.
int i;
for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++);
startIndex = endIndex = i + 1;
synchronized(this) {
Map<String, KernelWakelockStats> m = mProcWakelockFileStats;
sKernelWakelockUpdateVersion++;
while (endIndex < len) {
for (endIndex=startIndex;
endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
endIndex++);
// Don't go over the end of the buffer
if (endIndex < len) {
endIndex++; // endIndex is an exclusive upper bound.
}
String[] nameStringArray = mProcWakelocksName;
long[] wlData = mProcWakelocksData;
// Stomp out any bad characters since this is from a circular buffer
// A corruption is seen sometimes that results in the vm crashing
// This should prevent crashes and the line will probably fail to parse
for (int j = startIndex; j < endIndex; j++) {
if ((wlBuffer[j] & 0x80) != 0) wlBuffer[j] = (byte) '?';
}
boolean parsed = Process.parseProcLine(wlBuffer, startIndex, endIndex,
PROC_WAKELOCKS_FORMAT, nameStringArray, wlData, null);
name = nameStringArray[0];
count = (int) wlData[1];
// convert nanoseconds to microseconds with rounding.
totalTime = (wlData[2] + 500) / 1000;
if (parsed && name.length() > 0) {
if (!m.containsKey(name)) {
m.put(name, new KernelWakelockStats(count, totalTime,
sKernelWakelockUpdateVersion));
numUpdatedWlNames++;
} else {
KernelWakelockStats kwlStats = m.get(name);
if (kwlStats.mVersion == sKernelWakelockUpdateVersion) {
kwlStats.mCount += count;
kwlStats.mTotalTime += totalTime;
} else {
kwlStats.mCount = count;
kwlStats.mTotalTime = totalTime;
kwlStats.mVersion = sKernelWakelockUpdateVersion;
numUpdatedWlNames++;
}
}
}
startIndex = endIndex;
}
if (m.size() != numUpdatedWlNames) {
// Don't report old data.
Iterator<KernelWakelockStats> itr = m.values().iterator();
while (itr.hasNext()) {
if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
itr.remove();
}
}
}
return m;
}
}
private class KernelWakelockStats {
public int mCount;
public long mTotalTime;
public int mVersion;
KernelWakelockStats(int count, long totalTime, int version) {
mCount = count;
mTotalTime = totalTime;
mVersion = version;
}
}
/*
* Get the KernelWakelockTimer associated with name, and create a new one if one
* doesn't already exist.
*/
public SamplingTimer getKernelWakelockTimerLocked(String name) {
SamplingTimer kwlt = mKernelWakelockStats.get(name);
if (kwlt == null) {
kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
true /* track reported values */);
mKernelWakelockStats.put(name, kwlt);
}
return kwlt;
}
private void doDataPlug(long[] dataTransfer, long currentBytes) {
dataTransfer[STATS_LAST] = dataTransfer[STATS_SINCE_UNPLUGGED];
dataTransfer[STATS_SINCE_UNPLUGGED] = -1;
}
private void doDataUnplug(long[] dataTransfer, long currentBytes) {
dataTransfer[STATS_SINCE_UNPLUGGED] = currentBytes;
}
/**
* Radio uptime in microseconds when transferring data. This value is very approximate.
* @return
*/
private long getCurrentRadioDataUptime() {
try {
File awakeTimeFile = new File("/sys/devices/virtual/net/rmnet0/awake_time_ms");
if (!awakeTimeFile.exists()) return 0;
BufferedReader br = new BufferedReader(new FileReader(awakeTimeFile));
String line = br.readLine();
br.close();
return Long.parseLong(line) * 1000;
} catch (NumberFormatException nfe) {
// Nothing
} catch (IOException ioe) {
// Nothing
}
return 0;
}
/**
* @deprecated use getRadioDataUptime
*/
public long getRadioDataUptimeMs() {
return getRadioDataUptime() / 1000;
}
/**
* Returns the duration that the cell radio was up for data transfers.
*/
public long getRadioDataUptime() {
if (mRadioDataStart == -1) {
return mRadioDataUptime;
} else {
return getCurrentRadioDataUptime() - mRadioDataStart;
}
}
private int getCurrentBluetoothPingCount() {
if (mBtHeadset != null) {
return mBtHeadset.getBatteryUsageHint();
}
return -1;
}
public int getBluetoothPingCount() {
if (mBluetoothPingStart == -1) {
return mBluetoothPingCount;
} else if (mBtHeadset != null) {
return getCurrentBluetoothPingCount() - mBluetoothPingStart;
}
return 0;
}
public void setBtHeadset(BluetoothHeadset headset) {
if (headset != null && mBtHeadset == null && isOnBattery() && mBluetoothPingStart == -1) {
mBluetoothPingStart = getCurrentBluetoothPingCount();
}
mBtHeadset = headset;
}
int mChangedStates = 0;
void addHistoryRecordLocked(long curTime) {
if (!mHaveBatteryLevel || !mRecordingHistory) {
return;
}
// If the current time is basically the same as the last time,
// and no states have since the last recorded entry changed and
// are now resetting back to their original value, then just collapse
// into one record.
if (mHistoryEnd != null && mHistoryEnd.cmd == HistoryItem.CMD_UPDATE
&& (mHistoryBaseTime+curTime) < (mHistoryEnd.time+2000)
&& ((mHistoryEnd.states^mHistoryCur.states)&mChangedStates) == 0) {
// If the current is the same as the one before, then we no
// longer need the entry.
if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE
&& mHistoryLastEnd.same(mHistoryCur)) {
mHistoryLastEnd.next = null;
mHistoryEnd.next = mHistoryCache;
mHistoryCache = mHistoryEnd;
mHistoryEnd = mHistoryLastEnd;
mHistoryLastEnd = null;
} else {
mChangedStates |= mHistoryEnd.states^mHistoryCur.states;
mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, mHistoryCur);
}
return;
}
mChangedStates = 0;
if (mNumHistoryItems == MAX_HISTORY_ITEMS
|| mNumHistoryItems == MAX_MAX_HISTORY_ITEMS) {
addHistoryRecordLocked(curTime, HistoryItem.CMD_OVERFLOW);
}
if (mNumHistoryItems >= MAX_HISTORY_ITEMS) {
// Once we've reached the maximum number of items, we only
// record changes to the battery level and the most interesting states.
// Once we've reached the maximum maximum number of items, we only
// record changes to the battery level.
if (mHistoryEnd != null && mHistoryEnd.batteryLevel
== mHistoryCur.batteryLevel &&
(mNumHistoryItems >= MAX_MAX_HISTORY_ITEMS
|| ((mHistoryEnd.states^mHistoryCur.states)
& HistoryItem.MOST_INTERESTING_STATES) == 0)) {
return;
}
}
addHistoryRecordLocked(curTime, HistoryItem.CMD_UPDATE);
}
void addHistoryRecordLocked(long curTime, byte cmd) {
HistoryItem rec = mHistoryCache;
if (rec != null) {
mHistoryCache = rec.next;
} else {
rec = new HistoryItem();
}
rec.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
addHistoryRecordLocked(rec);
}
void addHistoryRecordLocked(HistoryItem rec) {
mNumHistoryItems++;
rec.next = null;
mHistoryLastEnd = mHistoryEnd;
if (mHistoryEnd != null) {
mHistoryEnd.next = rec;
mHistoryEnd = rec;
} else {
mHistory = mHistoryEnd = rec;
}
}
void clearHistoryLocked() {
if (mHistory != null) {
mHistoryEnd.next = mHistoryCache;
mHistoryCache = mHistory;
mHistory = mHistoryLastEnd = mHistoryEnd = null;
}
mNumHistoryItems = 0;
mHistoryBaseTime = 0;
}
public void doUnplugLocked(long batteryUptime, long batteryRealtime) {
for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
Uid u = mUidStats.valueAt(iu);
u.mStartedTcpBytesReceived = TrafficStats.getUidRxBytes(u.mUid);
u.mStartedTcpBytesSent = TrafficStats.getUidTxBytes(u.mUid);
u.mTcpBytesReceivedAtLastUnplug = u.mCurrentTcpBytesReceived;
u.mTcpBytesSentAtLastUnplug = u.mCurrentTcpBytesSent;
}
for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
mUnpluggables.get(i).unplug(batteryUptime, batteryRealtime);
}
// Track total mobile data
doDataUnplug(mMobileDataRx, TrafficStats.getMobileRxBytes());
doDataUnplug(mMobileDataTx, TrafficStats.getMobileTxBytes());
doDataUnplug(mTotalDataRx, TrafficStats.getTotalRxBytes());
doDataUnplug(mTotalDataTx, TrafficStats.getTotalTxBytes());
// Track radio awake time
mRadioDataStart = getCurrentRadioDataUptime();
mRadioDataUptime = 0;
// Track bt headset ping count
mBluetoothPingStart = getCurrentBluetoothPingCount();
mBluetoothPingCount = 0;
}
public void doPlugLocked(long batteryUptime, long batteryRealtime) {
for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
Uid u = mUidStats.valueAt(iu);
if (u.mStartedTcpBytesReceived >= 0) {
u.mCurrentTcpBytesReceived = u.computeCurrentTcpBytesReceived();
u.mStartedTcpBytesReceived = -1;
}
if (u.mStartedTcpBytesSent >= 0) {
u.mCurrentTcpBytesSent = u.computeCurrentTcpBytesSent();
u.mStartedTcpBytesSent = -1;
}
}
for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
mUnpluggables.get(i).plug(batteryUptime, batteryRealtime);
}
doDataPlug(mMobileDataRx, TrafficStats.getMobileRxBytes());
doDataPlug(mMobileDataTx, TrafficStats.getMobileTxBytes());
doDataPlug(mTotalDataRx, TrafficStats.getTotalRxBytes());
doDataPlug(mTotalDataTx, TrafficStats.getTotalTxBytes());
// Track radio awake time
mRadioDataUptime = getRadioDataUptime();
mRadioDataStart = -1;
// Track bt headset ping count
mBluetoothPingCount = getBluetoothPingCount();
mBluetoothPingStart = -1;
}
int mWakeLockNesting;
public void noteStartWakeLocked(int uid, int pid, String name, int type) {
if (type == WAKE_TYPE_PARTIAL) {
// Only care about partial wake locks, since full wake locks
// will be canceled when the user puts the screen to sleep.
if (mWakeLockNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
mWakeLockNesting++;
}
if (uid >= 0) {
if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
}
getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type);
}
}
public void noteStopWakeLocked(int uid, int pid, String name, int type) {
if (type == WAKE_TYPE_PARTIAL) {
mWakeLockNesting--;
if (mWakeLockNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
}
if (uid >= 0) {
if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
}
getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type);
}
}
public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteStartWakeLocked(ws.get(i), pid, name, type);
}
}
public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteStopWakeLocked(ws.get(i), pid, name, type);
}
}
public int startAddingCpuLocked() {
mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
if (mScreenOn) {
return 0;
}
final int N = mPartialTimers.size();
if (N == 0) {
mLastPartialTimers.clear();
return 0;
}
// How many timers should consume CPU? Only want to include ones
// that have already been in the list.
for (int i=0; i<N; i++) {
StopwatchTimer st = mPartialTimers.get(i);
if (st.mInList) {
Uid uid = st.mUid;
// We don't include the system UID, because it so often
// holds wake locks at one request or another of an app.
if (uid != null && uid.mUid != Process.SYSTEM_UID) {
return 50;
}
}
}
return 0;
}
public void finishAddingCpuLocked(int perc, int utime, int stime, long[] cpuSpeedTimes) {
final int N = mPartialTimers.size();
if (perc != 0) {
int num = 0;
for (int i=0; i<N; i++) {
StopwatchTimer st = mPartialTimers.get(i);
if (st.mInList) {
Uid uid = st.mUid;
// We don't include the system UID, because it so often
// holds wake locks at one request or another of an app.
if (uid != null && uid.mUid != Process.SYSTEM_UID) {
num++;
}
}
}
if (num != 0) {
for (int i=0; i<N; i++) {
StopwatchTimer st = mPartialTimers.get(i);
if (st.mInList) {
Uid uid = st.mUid;
if (uid != null && uid.mUid != Process.SYSTEM_UID) {
int myUTime = utime/num;
int mySTime = stime/num;
utime -= myUTime;
stime -= mySTime;
num--;
Uid.Proc proc = uid.getProcessStatsLocked("*wakelock*");
proc.addCpuTimeLocked(myUTime, mySTime);
proc.addSpeedStepTimes(cpuSpeedTimes);
}
}
}
}
// Just in case, collect any lost CPU time.
if (utime != 0 || stime != 0) {
Uid uid = getUidStatsLocked(Process.SYSTEM_UID);
if (uid != null) {
Uid.Proc proc = uid.getProcessStatsLocked("*lost*");
proc.addCpuTimeLocked(utime, stime);
proc.addSpeedStepTimes(cpuSpeedTimes);
}
}
}
final int NL = mLastPartialTimers.size();
boolean diff = N != NL;
for (int i=0; i<NL && !diff; i++) {
diff |= mPartialTimers.get(i) != mLastPartialTimers.get(i);
}
if (!diff) {
for (int i=0; i<NL; i++) {
mPartialTimers.get(i).mInList = true;
}
return;
}
for (int i=0; i<NL; i++) {
mLastPartialTimers.get(i).mInList = false;
}
mLastPartialTimers.clear();
for (int i=0; i<N; i++) {
StopwatchTimer st = mPartialTimers.get(i);
st.mInList = true;
mLastPartialTimers.add(st);
}
}
public void noteProcessDiedLocked(int uid, int pid) {
Uid u = mUidStats.get(uid);
if (u != null) {
u.mPids.remove(pid);
}
}
public long getProcessWakeTime(int uid, int pid, long realtime) {
Uid u = mUidStats.get(uid);
if (u != null) {
Uid.Pid p = u.mPids.get(pid);
if (p != null) {
return p.mWakeSum + (p.mWakeStart != 0 ? (realtime - p.mWakeStart) : 0);
}
}
return 0;
}
public void reportExcessiveWakeLocked(int uid, String proc, long overTime, long usedTime) {
Uid u = mUidStats.get(uid);
if (u != null) {
u.reportExcessiveWakeLocked(proc, overTime, usedTime);
}
}
public void reportExcessiveCpuLocked(int uid, String proc, long overTime, long usedTime) {
Uid u = mUidStats.get(uid);
if (u != null) {
u.reportExcessiveCpuLocked(proc, overTime, usedTime);
}
}
int mSensorNesting;
public void noteStartSensorLocked(int uid, int sensor) {
if (mSensorNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
mSensorNesting++;
getUidStatsLocked(uid).noteStartSensor(sensor);
}
public void noteStopSensorLocked(int uid, int sensor) {
mSensorNesting--;
if (mSensorNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Stop sensor to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
getUidStatsLocked(uid).noteStopSensor(sensor);
}
int mGpsNesting;
public void noteStartGpsLocked(int uid) {
if (mGpsNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
mGpsNesting++;
getUidStatsLocked(uid).noteStartGps();
}
public void noteStopGpsLocked(int uid) {
mGpsNesting--;
if (mGpsNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Stop GPS to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
getUidStatsLocked(uid).noteStopGps();
}
public void noteScreenOnLocked() {
if (!mScreenOn) {
mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mScreenOn = true;
mScreenOnTimer.startRunningLocked(this);
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
}
// Fake a wake lock, so we consider the device waked as long
// as the screen is on.
noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
}
}
public void noteScreenOffLocked() {
if (mScreenOn) {
mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mScreenOn = false;
mScreenOnTimer.stopRunningLocked(this);
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
}
noteStopWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
}
}
public void noteScreenBrightnessLocked(int brightness) {
// Bin the brightness.
int bin = brightness / (256/NUM_SCREEN_BRIGHTNESS_BINS);
if (bin < 0) bin = 0;
else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
if (mScreenBrightnessBin != bin) {
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_BRIGHTNESS_MASK)
| (bin << HistoryItem.STATE_BRIGHTNESS_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
if (mScreenOn) {
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
}
mScreenBrightnessTimer[bin].startRunningLocked(this);
}
mScreenBrightnessBin = bin;
}
}
public void noteInputEventAtomic() {
mInputEventCounter.stepAtomic();
}
public void noteUserActivityLocked(int uid, int event) {
getUidStatsLocked(uid).noteUserActivityLocked(event);
}
public void notePhoneOnLocked() {
if (!mPhoneOn) {
mHistoryCur.states |= HistoryItem.STATE_PHONE_IN_CALL_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mPhoneOn = true;
mPhoneOnTimer.startRunningLocked(this);
}
}
public void notePhoneOffLocked() {
if (mPhoneOn) {
mHistoryCur.states &= ~HistoryItem.STATE_PHONE_IN_CALL_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mPhoneOn = false;
mPhoneOnTimer.stopRunningLocked(this);
}
}
void stopAllSignalStrengthTimersLocked(int except) {
for (int i = 0; i < NUM_SIGNAL_STRENGTH_BINS; i++) {
if (i == except) {
continue;
}
while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
mPhoneSignalStrengthsTimer[i].stopRunningLocked(this);
}
}
}
/**
* Telephony stack updates the phone state.
* @param state phone state from ServiceState.getState()
*/
public void notePhoneStateLocked(int state) {
boolean scanning = false;
int bin = mPhoneSignalStrengthBin;
// If the phone is powered off, stop all timers.
if (state == ServiceState.STATE_POWER_OFF) {
stopAllSignalStrengthTimersLocked(-1);
// If we're back in service or continuing in service, restart the old timer.
} if (state == ServiceState.STATE_IN_SERVICE) {
if (bin == -1) bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
if (!mPhoneSignalStrengthsTimer[bin].isRunningLocked()) {
mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
}
// If we're out of service, we are in the lowest signal strength
// bin and have the scanning bit set.
} else if (state == ServiceState.STATE_OUT_OF_SERVICE) {
scanning = true;
mPhoneSignalStrengthBin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
stopAllSignalStrengthTimersLocked(mPhoneSignalStrengthBin);
if (!mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].isRunningLocked()) {
mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].startRunningLocked(this);
}
if (!mPhoneSignalScanningTimer.isRunningLocked()) {
mHistoryCur.states |= HistoryItem.STATE_PHONE_SCANNING_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mPhoneSignalScanningTimer.startRunningLocked(this);
}
}
if (!scanning) {
// If we are no longer scanning, then stop the scanning timer.
if (mPhoneSignalScanningTimer.isRunningLocked()) {
mHistoryCur.states &= ~HistoryItem.STATE_PHONE_SCANNING_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone stopped scanning to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mPhoneSignalScanningTimer.stopRunningLocked(this);
}
}
if (mPhoneServiceState != state) {
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_PHONE_STATE_MASK)
| (state << HistoryItem.STATE_PHONE_STATE_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Phone state " + bin + " to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mPhoneServiceState = state;
}
}
public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
// Bin the strength.
int bin;
if (mPhoneServiceState == ServiceState.STATE_POWER_OFF
|| mPhoneServiceState == ServiceState.STATE_OUT_OF_SERVICE) {
// Ignore any signal strength changes when radio was turned off or out of service.
return;
}
if (!signalStrength.isGsm()) {
int dBm = signalStrength.getCdmaDbm();
if (dBm >= -75) bin = SIGNAL_STRENGTH_GREAT;
else if (dBm >= -85) bin = SIGNAL_STRENGTH_GOOD;
else if (dBm >= -95) bin = SIGNAL_STRENGTH_MODERATE;
else if (dBm >= -100) bin = SIGNAL_STRENGTH_POOR;
else bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
} else {
int asu = signalStrength.getGsmSignalStrength();
if (asu < 0 || asu >= 99) bin = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
else if (asu >= 16) bin = SIGNAL_STRENGTH_GREAT;
else if (asu >= 8) bin = SIGNAL_STRENGTH_GOOD;
else if (asu >= 4) bin = SIGNAL_STRENGTH_MODERATE;
else bin = SIGNAL_STRENGTH_POOR;
}
if (mPhoneSignalStrengthBin != bin) {
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_SIGNAL_STRENGTH_MASK)
| (bin << HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + bin + " to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
if (mPhoneSignalStrengthBin >= 0) {
mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this);
}
mPhoneSignalStrengthBin = bin;
mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
}
}
public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData) {
int bin = DATA_CONNECTION_NONE;
if (hasData) {
switch (dataType) {
case TelephonyManager.NETWORK_TYPE_EDGE:
bin = DATA_CONNECTION_EDGE;
break;
case TelephonyManager.NETWORK_TYPE_GPRS:
bin = DATA_CONNECTION_GPRS;
break;
case TelephonyManager.NETWORK_TYPE_UMTS:
bin = DATA_CONNECTION_UMTS;
break;
case TelephonyManager.NETWORK_TYPE_CDMA:
bin = DATA_CONNECTION_CDMA;
break;
case TelephonyManager.NETWORK_TYPE_EVDO_0:
bin = DATA_CONNECTION_EVDO_0;
break;
case TelephonyManager.NETWORK_TYPE_EVDO_A:
bin = DATA_CONNECTION_EVDO_A;
break;
case TelephonyManager.NETWORK_TYPE_1xRTT:
bin = DATA_CONNECTION_1xRTT;
break;
case TelephonyManager.NETWORK_TYPE_HSDPA:
bin = DATA_CONNECTION_HSDPA;
break;
case TelephonyManager.NETWORK_TYPE_HSUPA:
bin = DATA_CONNECTION_HSUPA;
break;
case TelephonyManager.NETWORK_TYPE_HSPA:
bin = DATA_CONNECTION_HSPA;
break;
case TelephonyManager.NETWORK_TYPE_IDEN:
bin = DATA_CONNECTION_IDEN;
break;
case TelephonyManager.NETWORK_TYPE_EVDO_B:
bin = DATA_CONNECTION_EVDO_B;
break;
default:
bin = DATA_CONNECTION_OTHER;
break;
}
}
if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
if (mPhoneDataConnectionType != bin) {
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
| (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
if (mPhoneDataConnectionType >= 0) {
mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this);
}
mPhoneDataConnectionType = bin;
mPhoneDataConnectionsTimer[bin].startRunningLocked(this);
}
}
public void noteWifiOnLocked() {
if (!mWifiOn) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mWifiOn = true;
mWifiOnTimer.startRunningLocked(this);
}
}
public void noteWifiOffLocked() {
if (mWifiOn) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mWifiOn = false;
mWifiOnTimer.stopRunningLocked(this);
}
if (mWifiOnUid >= 0) {
getUidStatsLocked(mWifiOnUid).noteWifiStoppedLocked();
mWifiOnUid = -1;
}
}
public void noteAudioOnLocked(int uid) {
if (!mAudioOn) {
mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mAudioOn = true;
mAudioOnTimer.startRunningLocked(this);
}
getUidStatsLocked(uid).noteAudioTurnedOnLocked();
}
public void noteAudioOffLocked(int uid) {
if (mAudioOn) {
mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mAudioOn = false;
mAudioOnTimer.stopRunningLocked(this);
}
getUidStatsLocked(uid).noteAudioTurnedOffLocked();
}
public void noteVideoOnLocked(int uid) {
if (!mVideoOn) {
mHistoryCur.states |= HistoryItem.STATE_VIDEO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mVideoOn = true;
mVideoOnTimer.startRunningLocked(this);
}
getUidStatsLocked(uid).noteVideoTurnedOnLocked();
}
public void noteVideoOffLocked(int uid) {
if (mVideoOn) {
mHistoryCur.states &= ~HistoryItem.STATE_VIDEO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mVideoOn = false;
mVideoOnTimer.stopRunningLocked(this);
}
getUidStatsLocked(uid).noteVideoTurnedOffLocked();
}
public void noteWifiRunningLocked(WorkSource ws) {
if (!mGlobalWifiRunning) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_RUNNING_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mGlobalWifiRunning = true;
mGlobalWifiRunningTimer.startRunningLocked(this);
int N = ws.size();
for (int i=0; i<N; i++) {
getUidStatsLocked(ws.get(i)).noteWifiRunningLocked();
}
} else {
Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
}
}
public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
if (mGlobalWifiRunning) {
int N = oldWs.size();
for (int i=0; i<N; i++) {
getUidStatsLocked(oldWs.get(i)).noteWifiStoppedLocked();
}
N = newWs.size();
for (int i=0; i<N; i++) {
getUidStatsLocked(newWs.get(i)).noteWifiRunningLocked();
}
} else {
Log.w(TAG, "noteWifiRunningChangedLocked -- called while WIFI not running");
}
}
public void noteWifiStoppedLocked(WorkSource ws) {
if (mGlobalWifiRunning) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RUNNING_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mGlobalWifiRunning = false;
mGlobalWifiRunningTimer.stopRunningLocked(this);
int N = ws.size();
for (int i=0; i<N; i++) {
getUidStatsLocked(ws.get(i)).noteWifiStoppedLocked();
}
} else {
Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
}
}
public void noteBluetoothOnLocked() {
if (!mBluetoothOn) {
mHistoryCur.states |= HistoryItem.STATE_BLUETOOTH_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mBluetoothOn = true;
mBluetoothOnTimer.startRunningLocked(this);
}
}
public void noteBluetoothOffLocked() {
if (mBluetoothOn) {
mHistoryCur.states &= ~HistoryItem.STATE_BLUETOOTH_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mBluetoothOn = false;
mBluetoothOnTimer.stopRunningLocked(this);
}
}
int mWifiFullLockNesting = 0;
public void noteFullWifiLockAcquiredLocked(int uid) {
if (mWifiFullLockNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
mWifiFullLockNesting++;
getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
}
public void noteFullWifiLockReleasedLocked(int uid) {
mWifiFullLockNesting--;
if (mWifiFullLockNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
}
int mWifiScanLockNesting = 0;
public void noteScanWifiLockAcquiredLocked(int uid) {
if (mWifiScanLockNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
mWifiScanLockNesting++;
getUidStatsLocked(uid).noteScanWifiLockAcquiredLocked();
}
public void noteScanWifiLockReleasedLocked(int uid) {
mWifiScanLockNesting--;
if (mWifiScanLockNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
getUidStatsLocked(uid).noteScanWifiLockReleasedLocked();
}
int mWifiMulticastNesting = 0;
public void noteWifiMulticastEnabledLocked(int uid) {
if (mWifiMulticastNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
mWifiMulticastNesting++;
getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
}
public void noteWifiMulticastDisabledLocked(int uid) {
mWifiMulticastNesting--;
if (mWifiMulticastNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
}
public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteFullWifiLockAcquiredLocked(ws.get(i));
}
}
public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteFullWifiLockReleasedLocked(ws.get(i));
}
}
public void noteScanWifiLockAcquiredFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteScanWifiLockAcquiredLocked(ws.get(i));
}
}
public void noteScanWifiLockReleasedFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteScanWifiLockReleasedLocked(ws.get(i));
}
}
public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteWifiMulticastEnabledLocked(ws.get(i));
}
}
public void noteWifiMulticastDisabledFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteWifiMulticastDisabledLocked(ws.get(i));
}
}
@Override public long getScreenOnTime(long batteryRealtime, int which) {
return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override public long getScreenBrightnessTime(int brightnessBin,
long batteryRealtime, int which) {
return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
batteryRealtime, which);
}
@Override public int getInputEventCount(int which) {
return mInputEventCounter.getCountLocked(which);
}
@Override public long getPhoneOnTime(long batteryRealtime, int which) {
return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override public long getPhoneSignalStrengthTime(int strengthBin,
long batteryRealtime, int which) {
return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
batteryRealtime, which);
}
@Override public long getPhoneSignalScanningTime(
long batteryRealtime, int which) {
return mPhoneSignalScanningTimer.getTotalTimeLocked(
batteryRealtime, which);
}
@Override public int getPhoneSignalStrengthCount(int dataType, int which) {
return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
}
@Override public long getPhoneDataConnectionTime(int dataType,
long batteryRealtime, int which) {
return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
batteryRealtime, which);
}
@Override public int getPhoneDataConnectionCount(int dataType, int which) {
return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
}
@Override public long getWifiOnTime(long batteryRealtime, int which) {
return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override public long getGlobalWifiRunningTime(long batteryRealtime, int which) {
return mGlobalWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override public long getBluetoothOnTime(long batteryRealtime, int which) {
return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override public boolean getIsOnBattery() {
return mOnBattery;
}
@Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
return mUidStats;
}
/**
* The statistics associated with a particular uid.
*/
public final class Uid extends BatteryStats.Uid {
final int mUid;
long mLoadedTcpBytesReceived;
long mLoadedTcpBytesSent;
long mCurrentTcpBytesReceived;
long mCurrentTcpBytesSent;
long mTcpBytesReceivedAtLastUnplug;
long mTcpBytesSentAtLastUnplug;
// These are not saved/restored when parcelling, since we want
// to return from the parcel with a snapshot of the state.
long mStartedTcpBytesReceived = -1;
long mStartedTcpBytesSent = -1;
boolean mWifiRunning;
StopwatchTimer mWifiRunningTimer;
boolean mFullWifiLockOut;
StopwatchTimer mFullWifiLockTimer;
boolean mScanWifiLockOut;
StopwatchTimer mScanWifiLockTimer;
boolean mWifiMulticastEnabled;
StopwatchTimer mWifiMulticastTimer;
boolean mAudioTurnedOn;
StopwatchTimer mAudioTurnedOnTimer;
boolean mVideoTurnedOn;
StopwatchTimer mVideoTurnedOnTimer;
Counter[] mUserActivityCounters;
/**
* The statistics we have collected for this uid's wake locks.
*/
final HashMap<String, Wakelock> mWakelockStats = new HashMap<String, Wakelock>();
/**
* The statistics we have collected for this uid's sensor activations.
*/
final HashMap<Integer, Sensor> mSensorStats = new HashMap<Integer, Sensor>();
/**
* The statistics we have collected for this uid's processes.
*/
final HashMap<String, Proc> mProcessStats = new HashMap<String, Proc>();
/**
* The statistics we have collected for this uid's processes.
*/
final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
/**
* The transient wake stats we have collected for this uid's pids.
*/
final SparseArray<Pid> mPids = new SparseArray<Pid>();
public Uid(int uid) {
mUid = uid;
mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
mWifiRunningTimers, mUnpluggables);
mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
mFullWifiLockTimers, mUnpluggables);
mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
mScanWifiLockTimers, mUnpluggables);
mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
mWifiMulticastTimers, mUnpluggables);
mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
null, mUnpluggables);
mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
null, mUnpluggables);
}
@Override
public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
return mWakelockStats;
}
@Override
public Map<Integer, ? extends BatteryStats.Uid.Sensor> getSensorStats() {
return mSensorStats;
}
@Override
public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
return mProcessStats;
}
@Override
public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
return mPackageStats;
}
@Override
public int getUid() {
return mUid;
}
@Override
public long getTcpBytesReceived(int which) {
if (which == STATS_LAST) {
return mLoadedTcpBytesReceived;
} else {
long current = computeCurrentTcpBytesReceived();
if (which == STATS_SINCE_UNPLUGGED) {
current -= mTcpBytesReceivedAtLastUnplug;
} else if (which == STATS_SINCE_CHARGED) {
current += mLoadedTcpBytesReceived;
}
return current;
}
}
public long computeCurrentTcpBytesReceived() {
return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
? (TrafficStats.getUidRxBytes(mUid) - mStartedTcpBytesReceived) : 0);
}
@Override
public long getTcpBytesSent(int which) {
if (which == STATS_LAST) {
return mLoadedTcpBytesSent;
} else {
long current = computeCurrentTcpBytesSent();
if (which == STATS_SINCE_UNPLUGGED) {
current -= mTcpBytesSentAtLastUnplug;
} else if (which == STATS_SINCE_CHARGED) {
current += mLoadedTcpBytesSent;
}
return current;
}
}
@Override
public void noteWifiRunningLocked() {
if (!mWifiRunning) {
mWifiRunning = true;
if (mWifiRunningTimer == null) {
mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
mWifiRunningTimers, mUnpluggables);
}
mWifiRunningTimer.startRunningLocked(BatteryStatsImpl.this);
}
}
@Override
public void noteWifiStoppedLocked() {
if (mWifiRunning) {
mWifiRunning = false;
mWifiRunningTimer.stopRunningLocked(BatteryStatsImpl.this);
}
}
@Override
public void noteFullWifiLockAcquiredLocked() {
if (!mFullWifiLockOut) {
mFullWifiLockOut = true;
if (mFullWifiLockTimer == null) {
mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
mFullWifiLockTimers, mUnpluggables);
}
mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
}
}
@Override
public void noteFullWifiLockReleasedLocked() {
if (mFullWifiLockOut) {
mFullWifiLockOut = false;
mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
}
}
@Override
public void noteScanWifiLockAcquiredLocked() {
if (!mScanWifiLockOut) {
mScanWifiLockOut = true;
if (mScanWifiLockTimer == null) {
mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
mScanWifiLockTimers, mUnpluggables);
}
mScanWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
}
}
@Override
public void noteScanWifiLockReleasedLocked() {
if (mScanWifiLockOut) {
mScanWifiLockOut = false;
mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
}
}
@Override
public void noteWifiMulticastEnabledLocked() {
if (!mWifiMulticastEnabled) {
mWifiMulticastEnabled = true;
if (mWifiMulticastTimer == null) {
mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
mWifiMulticastTimers, mUnpluggables);
}
mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
}
}
@Override
public void noteWifiMulticastDisabledLocked() {
if (mWifiMulticastEnabled) {
mWifiMulticastEnabled = false;
mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
}
}
@Override
public void noteAudioTurnedOnLocked() {
if (!mAudioTurnedOn) {
mAudioTurnedOn = true;
if (mAudioTurnedOnTimer == null) {
mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
null, mUnpluggables);
}
mAudioTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
}
}
@Override
public void noteAudioTurnedOffLocked() {
if (mAudioTurnedOn) {
mAudioTurnedOn = false;
mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
}
}
@Override
public void noteVideoTurnedOnLocked() {
if (!mVideoTurnedOn) {
mVideoTurnedOn = true;
if (mVideoTurnedOnTimer == null) {
mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
null, mUnpluggables);
}
mVideoTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
}
}
@Override
public void noteVideoTurnedOffLocked() {
if (mVideoTurnedOn) {
mVideoTurnedOn = false;
mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
}
}
@Override
public long getWifiRunningTime(long batteryRealtime, int which) {
if (mWifiRunningTimer == null) {
return 0;
}
return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override
public long getFullWifiLockTime(long batteryRealtime, int which) {
if (mFullWifiLockTimer == null) {
return 0;
}
return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override
public long getScanWifiLockTime(long batteryRealtime, int which) {
if (mScanWifiLockTimer == null) {
return 0;
}
return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override
public long getWifiMulticastTime(long batteryRealtime, int which) {
if (mWifiMulticastTimer == null) {
return 0;
}
return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime,
which);
}
@Override
public long getAudioTurnedOnTime(long batteryRealtime, int which) {
if (mAudioTurnedOnTimer == null) {
return 0;
}
return mAudioTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override
public long getVideoTurnedOnTime(long batteryRealtime, int which) {
if (mVideoTurnedOnTimer == null) {
return 0;
}
return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override
public void noteUserActivityLocked(int type) {
if (mUserActivityCounters == null) {
initUserActivityLocked();
}
if (type < 0) type = 0;
else if (type >= NUM_USER_ACTIVITY_TYPES) type = NUM_USER_ACTIVITY_TYPES-1;
mUserActivityCounters[type].stepAtomic();
}
@Override
public boolean hasUserActivity() {
return mUserActivityCounters != null;
}
@Override
public int getUserActivityCount(int type, int which) {
if (mUserActivityCounters == null) {
return 0;
}
return mUserActivityCounters[type].getCountLocked(which);
}
void initUserActivityLocked() {
mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
mUserActivityCounters[i] = new Counter(mUnpluggables);
}
}
public long computeCurrentTcpBytesSent() {
return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
? (TrafficStats.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
}
/**
* Clear all stats for this uid. Returns true if the uid is completely
* inactive so can be dropped.
*/
boolean reset() {
boolean active = false;
if (mWifiRunningTimer != null) {
active |= !mWifiRunningTimer.reset(BatteryStatsImpl.this, false);
active |= mWifiRunning;
}
if (mFullWifiLockTimer != null) {
active |= !mFullWifiLockTimer.reset(BatteryStatsImpl.this, false);
active |= mFullWifiLockOut;
}
if (mScanWifiLockTimer != null) {
active |= !mScanWifiLockTimer.reset(BatteryStatsImpl.this, false);
active |= mScanWifiLockOut;
}
if (mWifiMulticastTimer != null) {
active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
active |= mWifiMulticastEnabled;
}
if (mAudioTurnedOnTimer != null) {
active |= !mAudioTurnedOnTimer.reset(BatteryStatsImpl.this, false);
active |= mAudioTurnedOn;
}
if (mVideoTurnedOnTimer != null) {
active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
active |= mVideoTurnedOn;
}
mLoadedTcpBytesReceived = mLoadedTcpBytesSent = 0;
mCurrentTcpBytesReceived = mCurrentTcpBytesSent = 0;
if (mUserActivityCounters != null) {
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
mUserActivityCounters[i].reset(false);
}
}
if (mWakelockStats.size() > 0) {
Iterator<Map.Entry<String, Wakelock>> it = mWakelockStats.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Wakelock> wakelockEntry = it.next();
Wakelock wl = wakelockEntry.getValue();
if (wl.reset()) {
it.remove();
} else {
active = true;
}
}
}
if (mSensorStats.size() > 0) {
Iterator<Map.Entry<Integer, Sensor>> it = mSensorStats.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, Sensor> sensorEntry = it.next();
Sensor s = sensorEntry.getValue();
if (s.reset()) {
it.remove();
} else {
active = true;
}
}
}
if (mProcessStats.size() > 0) {
Iterator<Map.Entry<String, Proc>> it = mProcessStats.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Proc> procEntry = it.next();
procEntry.getValue().detach();
}
mProcessStats.clear();
}
if (mPids.size() > 0) {
for (int i=0; !active && i<mPids.size(); i++) {
Pid pid = mPids.valueAt(i);
if (pid.mWakeStart != 0) {
active = true;
}
}
}
if (mPackageStats.size() > 0) {
Iterator<Map.Entry<String, Pkg>> it = mPackageStats.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Pkg> pkgEntry = it.next();
Pkg p = pkgEntry.getValue();
p.detach();
if (p.mServiceStats.size() > 0) {
Iterator<Map.Entry<String, Pkg.Serv>> it2
= p.mServiceStats.entrySet().iterator();
while (it2.hasNext()) {
Map.Entry<String, Pkg.Serv> servEntry = it2.next();
servEntry.getValue().detach();
}
}
}
mPackageStats.clear();
}
mPids.clear();
if (!active) {
if (mWifiRunningTimer != null) {
mWifiRunningTimer.detach();
}
if (mFullWifiLockTimer != null) {
mFullWifiLockTimer.detach();
}
if (mScanWifiLockTimer != null) {
mScanWifiLockTimer.detach();
}
if (mWifiMulticastTimer != null) {
mWifiMulticastTimer.detach();
}
if (mAudioTurnedOnTimer != null) {
mAudioTurnedOnTimer.detach();
}
if (mVideoTurnedOnTimer != null) {
mVideoTurnedOnTimer.detach();
}
if (mUserActivityCounters != null) {
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
mUserActivityCounters[i].detach();
}
}
}
return !active;
}
void writeToParcelLocked(Parcel out, long batteryRealtime) {
out.writeInt(mWakelockStats.size());
for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
out.writeString(wakelockEntry.getKey());
Uid.Wakelock wakelock = wakelockEntry.getValue();
wakelock.writeToParcelLocked(out, batteryRealtime);
}
out.writeInt(mSensorStats.size());
for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
out.writeInt(sensorEntry.getKey());
Uid.Sensor sensor = sensorEntry.getValue();
sensor.writeToParcelLocked(out, batteryRealtime);
}
out.writeInt(mProcessStats.size());
for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
out.writeString(procEntry.getKey());
Uid.Proc proc = procEntry.getValue();
proc.writeToParcelLocked(out);
}
out.writeInt(mPackageStats.size());
for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
out.writeString(pkgEntry.getKey());
Uid.Pkg pkg = pkgEntry.getValue();
pkg.writeToParcelLocked(out);
}
out.writeLong(mLoadedTcpBytesReceived);
out.writeLong(mLoadedTcpBytesSent);
out.writeLong(computeCurrentTcpBytesReceived());
out.writeLong(computeCurrentTcpBytesSent());
out.writeLong(mTcpBytesReceivedAtLastUnplug);
out.writeLong(mTcpBytesSentAtLastUnplug);
if (mWifiRunningTimer != null) {
out.writeInt(1);
mWifiRunningTimer.writeToParcel(out, batteryRealtime);
} else {
out.writeInt(0);
}
if (mFullWifiLockTimer != null) {
out.writeInt(1);
mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
} else {
out.writeInt(0);
}
if (mScanWifiLockTimer != null) {
out.writeInt(1);
mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
} else {
out.writeInt(0);
}
if (mWifiMulticastTimer != null) {
out.writeInt(1);
mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
} else {
out.writeInt(0);
}
if (mAudioTurnedOnTimer != null) {
out.writeInt(1);
mAudioTurnedOnTimer.writeToParcel(out, batteryRealtime);
} else {
out.writeInt(0);
}
if (mVideoTurnedOnTimer != null) {
out.writeInt(1);
mVideoTurnedOnTimer.writeToParcel(out, batteryRealtime);
} else {
out.writeInt(0);
}
if (mUserActivityCounters != null) {
out.writeInt(1);
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
mUserActivityCounters[i].writeToParcel(out);
}
} else {
out.writeInt(0);
}
}
void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
int numWakelocks = in.readInt();
mWakelockStats.clear();
for (int j = 0; j < numWakelocks; j++) {
String wakelockName = in.readString();
Uid.Wakelock wakelock = new Wakelock();
wakelock.readFromParcelLocked(unpluggables, in);
if (mWakelockStats.size() < MAX_WAKELOCKS_PER_UID) {
// We will just drop some random set of wakelocks if
// the previous run of the system was an older version
// that didn't impose a limit.
mWakelockStats.put(wakelockName, wakelock);
}
}
int numSensors = in.readInt();
mSensorStats.clear();
for (int k = 0; k < numSensors; k++) {
int sensorNumber = in.readInt();
Uid.Sensor sensor = new Sensor(sensorNumber);
sensor.readFromParcelLocked(mUnpluggables, in);
mSensorStats.put(sensorNumber, sensor);
}
int numProcs = in.readInt();
mProcessStats.clear();
for (int k = 0; k < numProcs; k++) {
String processName = in.readString();
Uid.Proc proc = new Proc();
proc.readFromParcelLocked(in);
mProcessStats.put(processName, proc);
}
int numPkgs = in.readInt();
mPackageStats.clear();
for (int l = 0; l < numPkgs; l++) {
String packageName = in.readString();
Uid.Pkg pkg = new Pkg();
pkg.readFromParcelLocked(in);
mPackageStats.put(packageName, pkg);
}
mLoadedTcpBytesReceived = in.readLong();
mLoadedTcpBytesSent = in.readLong();
mCurrentTcpBytesReceived = in.readLong();
mCurrentTcpBytesSent = in.readLong();
mTcpBytesReceivedAtLastUnplug = in.readLong();
mTcpBytesSentAtLastUnplug = in.readLong();
mWifiRunning = false;
if (in.readInt() != 0) {
mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
mWifiRunningTimers, mUnpluggables, in);
} else {
mWifiRunningTimer = null;
}
mFullWifiLockOut = false;
if (in.readInt() != 0) {
mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
mFullWifiLockTimers, mUnpluggables, in);
} else {
mFullWifiLockTimer = null;
}
mScanWifiLockOut = false;
if (in.readInt() != 0) {
mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
mScanWifiLockTimers, mUnpluggables, in);
} else {
mScanWifiLockTimer = null;
}
mWifiMulticastEnabled = false;
if (in.readInt() != 0) {
mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
mWifiMulticastTimers, mUnpluggables, in);
} else {
mWifiMulticastTimer = null;
}
mAudioTurnedOn = false;
if (in.readInt() != 0) {
mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
null, mUnpluggables, in);
} else {
mAudioTurnedOnTimer = null;
}
mVideoTurnedOn = false;
if (in.readInt() != 0) {
mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
null, mUnpluggables, in);
} else {
mVideoTurnedOnTimer = null;
}
if (in.readInt() != 0) {
mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
mUserActivityCounters[i] = new Counter(mUnpluggables, in);
}
} else {
mUserActivityCounters = null;
}
}
/**
* The statistics associated with a particular wake lock.
*/
public final class Wakelock extends BatteryStats.Uid.Wakelock {
/**
* How long (in ms) this uid has been keeping the device partially awake.
*/
StopwatchTimer mTimerPartial;
/**
* How long (in ms) this uid has been keeping the device fully awake.
*/
StopwatchTimer mTimerFull;
/**
* How long (in ms) this uid has had a window keeping the device awake.
*/
StopwatchTimer mTimerWindow;
/**
* Reads a possibly null Timer from a Parcel. The timer is associated with the
* proper timer pool from the given BatteryStatsImpl object.
*
* @param in the Parcel to be read from.
* return a new Timer, or null.
*/
private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
ArrayList<Unpluggable> unpluggables, Parcel in) {
if (in.readInt() == 0) {
return null;
}
return new StopwatchTimer(Uid.this, type, pool, unpluggables, in);
}
boolean reset() {
boolean wlactive = false;
if (mTimerFull != null) {
wlactive |= !mTimerFull.reset(BatteryStatsImpl.this, false);
}
if (mTimerPartial != null) {
wlactive |= !mTimerPartial.reset(BatteryStatsImpl.this, false);
}
if (mTimerWindow != null) {
wlactive |= !mTimerWindow.reset(BatteryStatsImpl.this, false);
}
if (!wlactive) {
if (mTimerFull != null) {
mTimerFull.detach();
mTimerFull = null;
}
if (mTimerPartial != null) {
mTimerPartial.detach();
mTimerPartial = null;
}
if (mTimerWindow != null) {
mTimerWindow.detach();
mTimerWindow = null;
}
}
return !wlactive;
}
void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
mPartialTimers, unpluggables, in);
mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
mFullTimers, unpluggables, in);
mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
mWindowTimers, unpluggables, in);
}
void writeToParcelLocked(Parcel out, long batteryRealtime) {
Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
}
@Override
public Timer getWakeTime(int type) {
switch (type) {
case WAKE_TYPE_FULL: return mTimerFull;
case WAKE_TYPE_PARTIAL: return mTimerPartial;
case WAKE_TYPE_WINDOW: return mTimerWindow;
default: throw new IllegalArgumentException("type = " + type);
}
}
}
public final class Sensor extends BatteryStats.Uid.Sensor {
final int mHandle;
StopwatchTimer mTimer;
public Sensor(int handle) {
mHandle = handle;
}
private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
Parcel in) {
if (in.readInt() == 0) {
return null;
}
ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
if (pool == null) {
pool = new ArrayList<StopwatchTimer>();
mSensorTimers.put(mHandle, pool);
}
return new StopwatchTimer(Uid.this, 0, pool, unpluggables, in);
}
boolean reset() {
if (mTimer.reset(BatteryStatsImpl.this, true)) {
mTimer = null;
return true;
}
return false;
}
void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
mTimer = readTimerFromParcel(unpluggables, in);
}
void writeToParcelLocked(Parcel out, long batteryRealtime) {
Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
}
@Override
public Timer getSensorTime() {
return mTimer;
}
@Override
public int getHandle() {
return mHandle;
}
}
/**
* The statistics associated with a particular process.
*/
public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
/**
* Total time (in 1/100 sec) spent executing in user code.
*/
long mUserTime;
/**
* Total time (in 1/100 sec) spent executing in kernel code.
*/
long mSystemTime;
/**
* Number of times the process has been started.
*/
int mStarts;
/**
* Amount of time the process was running in the foreground.
*/
long mForegroundTime;
/**
* The amount of user time loaded from a previous save.
*/
long mLoadedUserTime;
/**
* The amount of system time loaded from a previous save.
*/
long mLoadedSystemTime;
/**
* The number of times the process has started from a previous save.
*/
int mLoadedStarts;
/**
* The amount of foreground time loaded from a previous save.
*/
long mLoadedForegroundTime;
/**
* The amount of user time loaded from the previous run.
*/
long mLastUserTime;
/**
* The amount of system time loaded from the previous run.
*/
long mLastSystemTime;
/**
* The number of times the process has started from the previous run.
*/
int mLastStarts;
/**
* The amount of foreground time loaded from the previous run
*/
long mLastForegroundTime;
/**
* The amount of user time when last unplugged.
*/
long mUnpluggedUserTime;
/**
* The amount of system time when last unplugged.
*/
long mUnpluggedSystemTime;
/**
* The number of times the process has started before unplugged.
*/
int mUnpluggedStarts;
/**
* The amount of foreground time since unplugged.
*/
long mUnpluggedForegroundTime;
SamplingCounter[] mSpeedBins;
ArrayList<ExcessivePower> mExcessivePower;
Proc() {
mUnpluggables.add(this);
mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
}
public void unplug(long batteryUptime, long batteryRealtime) {
mUnpluggedUserTime = mUserTime;
mUnpluggedSystemTime = mSystemTime;
mUnpluggedStarts = mStarts;
mUnpluggedForegroundTime = mForegroundTime;
}
public void plug(long batteryUptime, long batteryRealtime) {
}
void detach() {
mUnpluggables.remove(this);
for (int i = 0; i < mSpeedBins.length; i++) {
SamplingCounter c = mSpeedBins[i];
if (c != null) {
mUnpluggables.remove(c);
mSpeedBins[i] = null;
}
}
}
public int countExcessivePowers() {
return mExcessivePower != null ? mExcessivePower.size() : 0;
}
public ExcessivePower getExcessivePower(int i) {
if (mExcessivePower != null) {
return mExcessivePower.get(i);
}
return null;
}
public void addExcessiveWake(long overTime, long usedTime) {
if (mExcessivePower == null) {
mExcessivePower = new ArrayList<ExcessivePower>();
}
ExcessivePower ew = new ExcessivePower();
ew.type = ExcessivePower.TYPE_WAKE;
ew.overTime = overTime;
ew.usedTime = usedTime;
mExcessivePower.add(ew);
}
public void addExcessiveCpu(long overTime, long usedTime) {
if (mExcessivePower == null) {
mExcessivePower = new ArrayList<ExcessivePower>();
}
ExcessivePower ew = new ExcessivePower();
ew.type = ExcessivePower.TYPE_CPU;
ew.overTime = overTime;
ew.usedTime = usedTime;
mExcessivePower.add(ew);
}
void writeExcessivePowerToParcelLocked(Parcel out) {
if (mExcessivePower == null) {
out.writeInt(0);
return;
}
final int N = mExcessivePower.size();
out.writeInt(N);
for (int i=0; i<N; i++) {
ExcessivePower ew = mExcessivePower.get(i);
out.writeInt(ew.type);
out.writeLong(ew.overTime);
out.writeLong(ew.usedTime);
}
}
void readExcessivePowerFromParcelLocked(Parcel in) {
final int N = in.readInt();
if (N == 0) {
mExcessivePower = null;
return;
}
mExcessivePower = new ArrayList<ExcessivePower>();
for (int i=0; i<N; i++) {
ExcessivePower ew = new ExcessivePower();
ew.type = in.readInt();
ew.overTime = in.readLong();
ew.usedTime = in.readLong();
mExcessivePower.add(ew);
}
}
void writeToParcelLocked(Parcel out) {
out.writeLong(mUserTime);
out.writeLong(mSystemTime);
out.writeLong(mForegroundTime);
out.writeInt(mStarts);
out.writeLong(mLoadedUserTime);
out.writeLong(mLoadedSystemTime);
out.writeLong(mLoadedForegroundTime);
out.writeInt(mLoadedStarts);
out.writeLong(mUnpluggedUserTime);
out.writeLong(mUnpluggedSystemTime);
out.writeLong(mUnpluggedForegroundTime);
out.writeInt(mUnpluggedStarts);
out.writeInt(mSpeedBins.length);
for (int i = 0; i < mSpeedBins.length; i++) {
SamplingCounter c = mSpeedBins[i];
if (c != null) {
out.writeInt(1);
c.writeToParcel(out);
} else {
out.writeInt(0);
}
}
writeExcessivePowerToParcelLocked(out);
}
void readFromParcelLocked(Parcel in) {
mUserTime = in.readLong();
mSystemTime = in.readLong();
mForegroundTime = in.readLong();
mStarts = in.readInt();
mLoadedUserTime = in.readLong();
mLoadedSystemTime = in.readLong();
mLoadedForegroundTime = in.readLong();
mLoadedStarts = in.readInt();
mLastUserTime = 0;
mLastSystemTime = 0;
mLastForegroundTime = 0;
mLastStarts = 0;
mUnpluggedUserTime = in.readLong();
mUnpluggedSystemTime = in.readLong();
mUnpluggedForegroundTime = in.readLong();
mUnpluggedStarts = in.readInt();
int bins = in.readInt();
int steps = getCpuSpeedSteps();
mSpeedBins = new SamplingCounter[bins >= steps ? bins : steps];
for (int i = 0; i < bins; i++) {
if (in.readInt() != 0) {
mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
}
}
readExcessivePowerFromParcelLocked(in);
}
public BatteryStatsImpl getBatteryStats() {
return BatteryStatsImpl.this;
}
public void addCpuTimeLocked(int utime, int stime) {
mUserTime += utime;
mSystemTime += stime;
}
public void addForegroundTimeLocked(long ttime) {
mForegroundTime += ttime;
}
public void incStartsLocked() {
mStarts++;
}
@Override
public long getUserTime(int which) {
long val;
if (which == STATS_LAST) {
val = mLastUserTime;
} else {
val = mUserTime;
if (which == STATS_CURRENT) {
val -= mLoadedUserTime;
} else if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedUserTime;
}
}
return val;
}
@Override
public long getSystemTime(int which) {
long val;
if (which == STATS_LAST) {
val = mLastSystemTime;
} else {
val = mSystemTime;
if (which == STATS_CURRENT) {
val -= mLoadedSystemTime;
} else if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedSystemTime;
}
}
return val;
}
@Override
public long getForegroundTime(int which) {
long val;
if (which == STATS_LAST) {
val = mLastForegroundTime;
} else {
val = mForegroundTime;
if (which == STATS_CURRENT) {
val -= mLoadedForegroundTime;
} else if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedForegroundTime;
}
}
return val;
}
@Override
public int getStarts(int which) {
int val;
if (which == STATS_LAST) {
val = mLastStarts;
} else {
val = mStarts;
if (which == STATS_CURRENT) {
val -= mLoadedStarts;
} else if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedStarts;
}
}
return val;
}
/* Called by ActivityManagerService when CPU times are updated. */
public void addSpeedStepTimes(long[] values) {
for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
long amt = values[i];
if (amt != 0) {
SamplingCounter c = mSpeedBins[i];
if (c == null) {
mSpeedBins[i] = c = new SamplingCounter(mUnpluggables);
}
c.addCountAtomic(values[i]);
}
}
}
@Override
public long getTimeAtCpuSpeedStep(int speedStep, int which) {
if (speedStep < mSpeedBins.length) {
SamplingCounter c = mSpeedBins[speedStep];
return c != null ? c.getCountLocked(which) : 0;
} else {
return 0;
}
}
}
/**
* The statistics associated with a particular package.
*/
public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
/**
* Number of times this package has done something that could wake up the
* device from sleep.
*/
int mWakeups;
/**
* Number of things that could wake up the device loaded from a
* previous save.
*/
int mLoadedWakeups;
/**
* Number of things that could wake up the device as of the
* last run.
*/
int mLastWakeups;
/**
* Number of things that could wake up the device as of the
* last run.
*/
int mUnpluggedWakeups;
/**
* The statics we have collected for this package's services.
*/
final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
Pkg() {
mUnpluggables.add(this);
}
public void unplug(long batteryUptime, long batteryRealtime) {
mUnpluggedWakeups = mWakeups;
}
public void plug(long batteryUptime, long batteryRealtime) {
}
void detach() {
mUnpluggables.remove(this);
}
void readFromParcelLocked(Parcel in) {
mWakeups = in.readInt();
mLoadedWakeups = in.readInt();
mLastWakeups = 0;
mUnpluggedWakeups = in.readInt();
int numServs = in.readInt();
mServiceStats.clear();
for (int m = 0; m < numServs; m++) {
String serviceName = in.readString();
Uid.Pkg.Serv serv = new Serv();
mServiceStats.put(serviceName, serv);
serv.readFromParcelLocked(in);
}
}
void writeToParcelLocked(Parcel out) {
out.writeInt(mWakeups);
out.writeInt(mLoadedWakeups);
out.writeInt(mUnpluggedWakeups);
out.writeInt(mServiceStats.size());
for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
out.writeString(servEntry.getKey());
Uid.Pkg.Serv serv = servEntry.getValue();
serv.writeToParcelLocked(out);
}
}
@Override
public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
return mServiceStats;
}
@Override
public int getWakeups(int which) {
int val;
if (which == STATS_LAST) {
val = mLastWakeups;
} else {
val = mWakeups;
if (which == STATS_CURRENT) {
val -= mLoadedWakeups;
} else if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedWakeups;
}
}
return val;
}
/**
* The statistics associated with a particular service.
*/
public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
/**
* Total time (ms in battery uptime) the service has been left started.
*/
long mStartTime;
/**
* If service has been started and not yet stopped, this is
* when it was started.
*/
long mRunningSince;
/**
* True if we are currently running.
*/
boolean mRunning;
/**
* Total number of times startService() has been called.
*/
int mStarts;
/**
* Total time (ms in battery uptime) the service has been left launched.
*/
long mLaunchedTime;
/**
* If service has been launched and not yet exited, this is
* when it was launched (ms in battery uptime).
*/
long mLaunchedSince;
/**
* True if we are currently launched.
*/
boolean mLaunched;
/**
* Total number times the service has been launched.
*/
int mLaunches;
/**
* The amount of time spent started loaded from a previous save
* (ms in battery uptime).
*/
long mLoadedStartTime;
/**
* The number of starts loaded from a previous save.
*/
int mLoadedStarts;
/**
* The number of launches loaded from a previous save.
*/
int mLoadedLaunches;
/**
* The amount of time spent started as of the last run (ms
* in battery uptime).
*/
long mLastStartTime;
/**
* The number of starts as of the last run.
*/
int mLastStarts;
/**
* The number of launches as of the last run.
*/
int mLastLaunches;
/**
* The amount of time spent started when last unplugged (ms
* in battery uptime).
*/
long mUnpluggedStartTime;
/**
* The number of starts when last unplugged.
*/
int mUnpluggedStarts;
/**
* The number of launches when last unplugged.
*/
int mUnpluggedLaunches;
Serv() {
mUnpluggables.add(this);
}
public void unplug(long batteryUptime, long batteryRealtime) {
mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
mUnpluggedStarts = mStarts;
mUnpluggedLaunches = mLaunches;
}
public void plug(long batteryUptime, long batteryRealtime) {
}
void detach() {
mUnpluggables.remove(this);
}
void readFromParcelLocked(Parcel in) {
mStartTime = in.readLong();
mRunningSince = in.readLong();
mRunning = in.readInt() != 0;
mStarts = in.readInt();
mLaunchedTime = in.readLong();
mLaunchedSince = in.readLong();
mLaunched = in.readInt() != 0;
mLaunches = in.readInt();
mLoadedStartTime = in.readLong();
mLoadedStarts = in.readInt();
mLoadedLaunches = in.readInt();
mLastStartTime = 0;
mLastStarts = 0;
mLastLaunches = 0;
mUnpluggedStartTime = in.readLong();
mUnpluggedStarts = in.readInt();
mUnpluggedLaunches = in.readInt();
}
void writeToParcelLocked(Parcel out) {
out.writeLong(mStartTime);
out.writeLong(mRunningSince);
out.writeInt(mRunning ? 1 : 0);
out.writeInt(mStarts);
out.writeLong(mLaunchedTime);
out.writeLong(mLaunchedSince);
out.writeInt(mLaunched ? 1 : 0);
out.writeInt(mLaunches);
out.writeLong(mLoadedStartTime);
out.writeInt(mLoadedStarts);
out.writeInt(mLoadedLaunches);
out.writeLong(mUnpluggedStartTime);
out.writeInt(mUnpluggedStarts);
out.writeInt(mUnpluggedLaunches);
}
long getLaunchTimeToNowLocked(long batteryUptime) {
if (!mLaunched) return mLaunchedTime;
return mLaunchedTime + batteryUptime - mLaunchedSince;
}
long getStartTimeToNowLocked(long batteryUptime) {
if (!mRunning) return mStartTime;
return mStartTime + batteryUptime - mRunningSince;
}
public void startLaunchedLocked() {
if (!mLaunched) {
mLaunches++;
mLaunchedSince = getBatteryUptimeLocked();
mLaunched = true;
}
}
public void stopLaunchedLocked() {
if (mLaunched) {
long time = getBatteryUptimeLocked() - mLaunchedSince;
if (time > 0) {
mLaunchedTime += time;
} else {
mLaunches--;
}
mLaunched = false;
}
}
public void startRunningLocked() {
if (!mRunning) {
mStarts++;
mRunningSince = getBatteryUptimeLocked();
mRunning = true;
}
}
public void stopRunningLocked() {
if (mRunning) {
long time = getBatteryUptimeLocked() - mRunningSince;
if (time > 0) {
mStartTime += time;
} else {
mStarts--;
}
mRunning = false;
}
}
public BatteryStatsImpl getBatteryStats() {
return BatteryStatsImpl.this;
}
@Override
public int getLaunches(int which) {
int val;
if (which == STATS_LAST) {
val = mLastLaunches;
} else {
val = mLaunches;
if (which == STATS_CURRENT) {
val -= mLoadedLaunches;
} else if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedLaunches;
}
}
return val;
}
@Override
public long getStartTime(long now, int which) {
long val;
if (which == STATS_LAST) {
val = mLastStartTime;
} else {
val = getStartTimeToNowLocked(now);
if (which == STATS_CURRENT) {
val -= mLoadedStartTime;
} else if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedStartTime;
}
}
return val;
}
@Override
public int getStarts(int which) {
int val;
if (which == STATS_LAST) {
val = mLastStarts;
} else {
val = mStarts;
if (which == STATS_CURRENT) {
val -= mLoadedStarts;
} else if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedStarts;
}
}
return val;
}
}
public BatteryStatsImpl getBatteryStats() {
return BatteryStatsImpl.this;
}
public void incWakeupsLocked() {
mWakeups++;
}
final Serv newServiceStatsLocked() {
return new Serv();
}
}
/**
* Retrieve the statistics object for a particular process, creating
* if needed.
*/
public Proc getProcessStatsLocked(String name) {
Proc ps = mProcessStats.get(name);
if (ps == null) {
ps = new Proc();
mProcessStats.put(name, ps);
}
return ps;
}
public SparseArray<? extends Pid> getPidStats() {
return mPids;
}
public Pid getPidStatsLocked(int pid) {
Pid p = mPids.get(pid);
if (p == null) {
p = new Pid();
mPids.put(pid, p);
}
return p;
}
/**
* Retrieve the statistics object for a particular service, creating
* if needed.
*/
public Pkg getPackageStatsLocked(String name) {
Pkg ps = mPackageStats.get(name);
if (ps == null) {
ps = new Pkg();
mPackageStats.put(name, ps);
}
return ps;
}
/**
* Retrieve the statistics object for a particular service, creating
* if needed.
*/
public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
Pkg ps = getPackageStatsLocked(pkg);
Pkg.Serv ss = ps.mServiceStats.get(serv);
if (ss == null) {
ss = ps.newServiceStatsLocked();
ps.mServiceStats.put(serv, ss);
}
return ss;
}
public StopwatchTimer getWakeTimerLocked(String name, int type) {
Wakelock wl = mWakelockStats.get(name);
if (wl == null) {
if (mWakelockStats.size() > MAX_WAKELOCKS_PER_UID) {
name = BATCHED_WAKELOCK_NAME;
wl = mWakelockStats.get(name);
}
if (wl == null) {
wl = new Wakelock();
mWakelockStats.put(name, wl);
}
}
StopwatchTimer t = null;
switch (type) {
case WAKE_TYPE_PARTIAL:
t = wl.mTimerPartial;
if (t == null) {
t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
mPartialTimers, mUnpluggables);
wl.mTimerPartial = t;
}
return t;
case WAKE_TYPE_FULL:
t = wl.mTimerFull;
if (t == null) {
t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
mFullTimers, mUnpluggables);
wl.mTimerFull = t;
}
return t;
case WAKE_TYPE_WINDOW:
t = wl.mTimerWindow;
if (t == null) {
t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
mWindowTimers, mUnpluggables);
wl.mTimerWindow = t;
}
return t;
default:
throw new IllegalArgumentException("type=" + type);
}
}
public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
Sensor se = mSensorStats.get(sensor);
if (se == null) {
if (!create) {
return null;
}
se = new Sensor(sensor);
mSensorStats.put(sensor, se);
}
StopwatchTimer t = se.mTimer;
if (t != null) {
return t;
}
ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
if (timers == null) {
timers = new ArrayList<StopwatchTimer>();
mSensorTimers.put(sensor, timers);
}
t = new StopwatchTimer(Uid.this, BatteryStats.SENSOR, timers, mUnpluggables);
se.mTimer = t;
return t;
}
public void noteStartWakeLocked(int pid, String name, int type) {
StopwatchTimer t = getWakeTimerLocked(name, type);
if (t != null) {
t.startRunningLocked(BatteryStatsImpl.this);
}
if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
Pid p = getPidStatsLocked(pid);
if (p.mWakeStart == 0) {
p.mWakeStart = SystemClock.elapsedRealtime();
}
}
}
public void noteStopWakeLocked(int pid, String name, int type) {
StopwatchTimer t = getWakeTimerLocked(name, type);
if (t != null) {
t.stopRunningLocked(BatteryStatsImpl.this);
}
if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
Pid p = mPids.get(pid);
if (p != null && p.mWakeStart != 0) {
p.mWakeSum += SystemClock.elapsedRealtime() - p.mWakeStart;
p.mWakeStart = 0;
}
}
}
public void reportExcessiveWakeLocked(String proc, long overTime, long usedTime) {
Proc p = getProcessStatsLocked(proc);
if (p != null) {
p.addExcessiveWake(overTime, usedTime);
}
}
public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) {
Proc p = getProcessStatsLocked(proc);
if (p != null) {
p.addExcessiveCpu(overTime, usedTime);
}
}
public void noteStartSensor(int sensor) {
StopwatchTimer t = getSensorTimerLocked(sensor, true);
if (t != null) {
t.startRunningLocked(BatteryStatsImpl.this);
}
}
public void noteStopSensor(int sensor) {
// Don't create a timer if one doesn't already exist
StopwatchTimer t = getSensorTimerLocked(sensor, false);
if (t != null) {
t.stopRunningLocked(BatteryStatsImpl.this);
}
}
public void noteStartGps() {
StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
if (t != null) {
t.startRunningLocked(BatteryStatsImpl.this);
}
}
public void noteStopGps() {
StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
if (t != null) {
t.stopRunningLocked(BatteryStatsImpl.this);
}
}
public BatteryStatsImpl getBatteryStats() {
return BatteryStatsImpl.this;
}
}
public BatteryStatsImpl(String filename) {
mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
mHandler = new MyHandler();
mStartCount++;
mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mUnpluggables);
}
mInputEventCounter = new Counter(mUnpluggables);
mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables);
for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null, mUnpluggables);
}
mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null, mUnpluggables);
}
mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables);
mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables);
mAudioOnTimer = new StopwatchTimer(null, -6, null, mUnpluggables);
mVideoOnTimer = new StopwatchTimer(null, -7, null, mUnpluggables);
mOnBattery = mOnBatteryInternal = false;
initTimes();
mTrackBatteryPastUptime = 0;
mTrackBatteryPastRealtime = 0;
mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
mDischargeStartLevel = 0;
mDischargeUnplugLevel = 0;
mDischargeCurrentLevel = 0;
mLowDischargeAmountSinceCharge = 0;
mHighDischargeAmountSinceCharge = 0;
}
public BatteryStatsImpl(Parcel p) {
mFile = null;
mHandler = null;
readFromParcel(p);
}
public void setCallback(BatteryCallback cb) {
mCallback = cb;
}
public void setNumSpeedSteps(int steps) {
if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
}
public void setRadioScanningTimeout(long timeout) {
if (mPhoneSignalScanningTimer != null) {
mPhoneSignalScanningTimer.setTimeout(timeout);
}
}
private HistoryItem mHistoryIterator;
public boolean startIteratingHistoryLocked() {
return (mHistoryIterator = mHistory) != null;
}
public boolean getNextHistoryLocked(HistoryItem out) {
HistoryItem cur = mHistoryIterator;
if (cur == null) {
return false;
}
out.setTo(cur);
mHistoryIterator = cur.next;
return true;
}
@Override
public HistoryItem getHistory() {
return mHistory;
}
@Override
public long getHistoryBaseTime() {
return mHistoryBaseTime;
}
@Override
public int getStartCount() {
return mStartCount;
}
public boolean isOnBattery() {
return mOnBattery;
}
public boolean isScreenOn() {
return mScreenOn;
}
void initTimes() {
mBatteryRealtime = mTrackBatteryPastUptime = 0;
mBatteryUptime = mTrackBatteryPastRealtime = 0;
mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
}
public void resetAllStatsLocked() {
mStartCount = 0;
initTimes();
mScreenOnTimer.reset(this, false);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].reset(this, false);
}
mInputEventCounter.reset(false);
mPhoneOnTimer.reset(this, false);
mAudioOnTimer.reset(this, false);
mVideoOnTimer.reset(this, false);
for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].reset(this, false);
}
mPhoneSignalScanningTimer.reset(this, false);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i].reset(this, false);
}
mWifiOnTimer.reset(this, false);
mGlobalWifiRunningTimer.reset(this, false);
mBluetoothOnTimer.reset(this, false);
for (int i=0; i<mUidStats.size(); i++) {
if (mUidStats.valueAt(i).reset()) {
mUidStats.remove(mUidStats.keyAt(i));
i--;
}
}
if (mKernelWakelockStats.size() > 0) {
for (SamplingTimer timer : mKernelWakelockStats.values()) {
mUnpluggables.remove(timer);
}
mKernelWakelockStats.clear();
}
clearHistoryLocked();
}
void setOnBattery(boolean onBattery, int oldStatus, int level) {
synchronized(this) {
boolean doWrite = false;
Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
m.arg1 = onBattery ? 1 : 0;
mHandler.sendMessage(m);
mOnBattery = mOnBatteryInternal = onBattery;
long uptime = SystemClock.uptimeMillis() * 1000;
long mSecRealtime = SystemClock.elapsedRealtime();
long realtime = mSecRealtime * 1000;
if (onBattery) {
// We will reset our status if we are unplugging after the
// battery was last full, or the level is at 100, or
// we have gone through a significant charge (from a very low
// level to a now very high level).
if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
|| level >= 100
|| (mDischargeCurrentLevel < 20 && level > 90)) {
doWrite = true;
resetAllStatsLocked();
mDischargeStartLevel = level;
mLowDischargeAmountSinceCharge = 0;
mHighDischargeAmountSinceCharge = 0;
}
updateKernelWakelocksLocked();
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(mSecRealtime);
mTrackBatteryUptimeStart = uptime;
mTrackBatteryRealtimeStart = realtime;
mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
mDischargeCurrentLevel = mDischargeUnplugLevel = level;
doUnplugLocked(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
} else {
updateKernelWakelocksLocked();
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(mSecRealtime);
mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
mDischargeCurrentLevel = level;
if (level < mDischargeUnplugLevel) {
mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
}
doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
}
if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
if (mFile != null) {
writeAsyncLocked();
}
}
}
}
// This should probably be exposed in the API, though it's not critical
private static final int BATTERY_PLUGGED_NONE = 0;
public void setBatteryState(int status, int health, int plugType, int level,
int temp, int volt) {
boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
int oldStatus = mHistoryCur.batteryStatus;
if (!mHaveBatteryLevel) {
mHaveBatteryLevel = true;
// We start out assuming that the device is plugged in (not
// on battery). If our first report is now that we are indeed
// plugged in, then twiddle our state to correctly reflect that
// since we won't be going through the full setOnBattery().
if (onBattery == mOnBattery) {
if (onBattery) {
mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
} else {
mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
}
}
oldStatus = status;
}
if (onBattery) {
mDischargeCurrentLevel = level;
mRecordingHistory = true;
}
if (onBattery != mOnBattery) {
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.batteryStatus = (byte)status;
mHistoryCur.batteryHealth = (byte)health;
mHistoryCur.batteryPlugType = (byte)plugType;
mHistoryCur.batteryTemperature = (char)temp;
mHistoryCur.batteryVoltage = (char)volt;
setOnBattery(onBattery, oldStatus, level);
} else {
boolean changed = false;
if (mHistoryCur.batteryLevel != level) {
mHistoryCur.batteryLevel = (byte)level;
changed = true;
}
if (mHistoryCur.batteryStatus != status) {
mHistoryCur.batteryStatus = (byte)status;
changed = true;
}
if (mHistoryCur.batteryHealth != health) {
mHistoryCur.batteryHealth = (byte)health;
changed = true;
}
if (mHistoryCur.batteryPlugType != plugType) {
mHistoryCur.batteryPlugType = (byte)plugType;
changed = true;
}
if (mHistoryCur.batteryTemperature != temp) {
mHistoryCur.batteryTemperature = (char)temp;
changed = true;
}
if (mHistoryCur.batteryVoltage != volt) {
mHistoryCur.batteryVoltage = (char)volt;
changed = true;
}
if (changed) {
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
}
if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
// We don't record history while we are plugged in and fully charged.
// The next time we are unplugged, history will be cleared.
mRecordingHistory = false;
}
}
public void updateKernelWakelocksLocked() {
Map<String, KernelWakelockStats> m = readKernelWakelockStats();
if (m == null) {
// Not crashing might make board bringup easier.
Slog.w(TAG, "Couldn't get kernel wake lock stats");
return;
}
for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
String name = ent.getKey();
KernelWakelockStats kws = ent.getValue();
SamplingTimer kwlt = mKernelWakelockStats.get(name);
if (kwlt == null) {
kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
true /* track reported values */);
mKernelWakelockStats.put(name, kwlt);
}
kwlt.updateCurrentReportedCount(kws.mCount);
kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
}
if (m.size() != mKernelWakelockStats.size()) {
// Set timers to stale if they didn't appear in /proc/wakelocks this time.
for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
SamplingTimer st = ent.getValue();
if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
st.setStale();
}
}
}
}
public long getAwakeTimeBattery() {
return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
}
public long getAwakeTimePlugged() {
return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
}
@Override
public long computeUptime(long curTime, int which) {
switch (which) {
case STATS_SINCE_CHARGED: return mUptime + (curTime-mUptimeStart);
case STATS_LAST: return mLastUptime;
case STATS_CURRENT: return (curTime-mUptimeStart);
case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
}
return 0;
}
@Override
public long computeRealtime(long curTime, int which) {
switch (which) {
case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
case STATS_LAST: return mLastRealtime;
case STATS_CURRENT: return (curTime-mRealtimeStart);
case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
}
return 0;
}
@Override
public long computeBatteryUptime(long curTime, int which) {
switch (which) {
case STATS_SINCE_CHARGED:
return mBatteryUptime + getBatteryUptime(curTime);
case STATS_LAST:
return mBatteryLastUptime;
case STATS_CURRENT:
return getBatteryUptime(curTime);
case STATS_SINCE_UNPLUGGED:
return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
}
return 0;
}
@Override
public long computeBatteryRealtime(long curTime, int which) {
switch (which) {
case STATS_SINCE_CHARGED:
return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
case STATS_LAST:
return mBatteryLastRealtime;
case STATS_CURRENT:
return getBatteryRealtimeLocked(curTime);
case STATS_SINCE_UNPLUGGED:
return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
}
return 0;
}
long getBatteryUptimeLocked(long curTime) {
long time = mTrackBatteryPastUptime;
if (mOnBatteryInternal) {
time += curTime - mTrackBatteryUptimeStart;
}
return time;
}
long getBatteryUptimeLocked() {
return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
}
@Override
public long getBatteryUptime(long curTime) {
return getBatteryUptimeLocked(curTime);
}
long getBatteryRealtimeLocked(long curTime) {
long time = mTrackBatteryPastRealtime;
if (mOnBatteryInternal) {
time += curTime - mTrackBatteryRealtimeStart;
}
return time;
}
@Override
public long getBatteryRealtime(long curTime) {
return getBatteryRealtimeLocked(curTime);
}
private long getTcpBytes(long current, long[] dataBytes, int which) {
if (which == STATS_LAST) {
return dataBytes[STATS_LAST];
} else {
if (which == STATS_SINCE_UNPLUGGED) {
if (dataBytes[STATS_SINCE_UNPLUGGED] < 0) {
return dataBytes[STATS_LAST];
} else {
return current - dataBytes[STATS_SINCE_UNPLUGGED];
}
} else if (which == STATS_SINCE_CHARGED) {
return (current - dataBytes[STATS_CURRENT]) + dataBytes[STATS_SINCE_CHARGED];
}
return current - dataBytes[STATS_CURRENT];
}
}
/** Only STATS_UNPLUGGED works properly */
public long getMobileTcpBytesSent(int which) {
return getTcpBytes(TrafficStats.getMobileTxBytes(), mMobileDataTx, which);
}
/** Only STATS_UNPLUGGED works properly */
public long getMobileTcpBytesReceived(int which) {
return getTcpBytes(TrafficStats.getMobileRxBytes(), mMobileDataRx, which);
}
/** Only STATS_UNPLUGGED works properly */
public long getTotalTcpBytesSent(int which) {
return getTcpBytes(TrafficStats.getTotalTxBytes(), mTotalDataTx, which);
}
/** Only STATS_UNPLUGGED works properly */
public long getTotalTcpBytesReceived(int which) {
return getTcpBytes(TrafficStats.getTotalRxBytes(), mTotalDataRx, which);
}
@Override
public int getDischargeStartLevel() {
synchronized(this) {
return getDischargeStartLevelLocked();
}
}
public int getDischargeStartLevelLocked() {
return mDischargeUnplugLevel;
}
@Override
public int getDischargeCurrentLevel() {
synchronized(this) {
return getDischargeCurrentLevelLocked();
}
}
public int getDischargeCurrentLevelLocked() {
return mDischargeCurrentLevel;
}
@Override
public int getLowDischargeAmountSinceCharge() {
synchronized(this) {
return mLowDischargeAmountSinceCharge;
}
}
@Override
public int getHighDischargeAmountSinceCharge() {
synchronized(this) {
return mHighDischargeAmountSinceCharge;
}
}
@Override
public int getCpuSpeedSteps() {
return sNumSpeedSteps;
}
/**
* Retrieve the statistics object for a particular uid, creating if needed.
*/
public Uid getUidStatsLocked(int uid) {
Uid u = mUidStats.get(uid);
if (u == null) {
u = new Uid(uid);
mUidStats.put(uid, u);
}
return u;
}
/**
* Remove the statistics object for a particular uid.
*/
public void removeUidStatsLocked(int uid) {
mUidStats.remove(uid);
}
/**
* Retrieve the statistics object for a particular process, creating
* if needed.
*/
public Uid.Proc getProcessStatsLocked(int uid, String name) {
Uid u = getUidStatsLocked(uid);
return u.getProcessStatsLocked(name);
}
/**
* Retrieve the statistics object for a particular process, given
* the name of the process.
* @param name process name
* @return the statistics object for the process
*/
public Uid.Proc getProcessStatsLocked(String name, int pid) {
int uid;
if (mUidCache.containsKey(name)) {
uid = mUidCache.get(name);
} else {
uid = Process.getUidForPid(pid);
mUidCache.put(name, uid);
}
Uid u = getUidStatsLocked(uid);
return u.getProcessStatsLocked(name);
}
/**
* Retrieve the statistics object for a particular process, creating
* if needed.
*/
public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
Uid u = getUidStatsLocked(uid);
return u.getPackageStatsLocked(pkg);
}
/**
* Retrieve the statistics object for a particular service, creating
* if needed.
*/
public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
Uid u = getUidStatsLocked(uid);
return u.getServiceStatsLocked(pkg, name);
}
/**
* Massage data to distribute any reasonable work down to more specific
* owners. Must only be called on a dead BatteryStats object!
*/
public void distributeWorkLocked(int which) {
// Aggregate all CPU time associated with WIFI.
Uid wifiUid = mUidStats.get(Process.WIFI_UID);
if (wifiUid != null) {
long uSecTime = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
for (Uid.Proc proc : wifiUid.mProcessStats.values()) {
long totalRunningTime = getGlobalWifiRunningTime(uSecTime, which);
for (int i=0; i<mUidStats.size(); i++) {
Uid uid = mUidStats.valueAt(i);
if (uid.mUid != Process.WIFI_UID) {
long uidRunningTime = uid.getWifiRunningTime(uSecTime, which);
if (uidRunningTime > 0) {
Uid.Proc uidProc = uid.getProcessStatsLocked("*wifi*");
long time = proc.getUserTime(which);
time = (time*uidRunningTime)/totalRunningTime;
uidProc.mUserTime += time;
proc.mUserTime -= time;
time = proc.getSystemTime(which);
time = (time*uidRunningTime)/totalRunningTime;
uidProc.mSystemTime += time;
proc.mSystemTime -= time;
time = proc.getForegroundTime(which);
time = (time*uidRunningTime)/totalRunningTime;
uidProc.mForegroundTime += time;
proc.mForegroundTime -= time;
for (int sb=0; sb<proc.mSpeedBins.length; sb++) {
SamplingCounter sc = proc.mSpeedBins[sb];
if (sc != null) {
time = sc.getCountLocked(which);
time = (time*uidRunningTime)/totalRunningTime;
SamplingCounter uidSc = uidProc.mSpeedBins[sb];
if (uidSc == null) {
uidSc = new SamplingCounter(mUnpluggables);
uidProc.mSpeedBins[sb] = uidSc;
}
uidSc.mCount.addAndGet((int)time);
sc.mCount.addAndGet((int)-time);
}
}
totalRunningTime -= uidRunningTime;
}
}
}
}
}
}
public void shutdownLocked() {
writeSyncLocked();
mShuttingDown = true;
}
Parcel mPendingWrite = null;
final ReentrantLock mWriteLock = new ReentrantLock();
public void writeAsyncLocked() {
writeLocked(false);
}
public void writeSyncLocked() {
writeLocked(true);
}
void writeLocked(boolean sync) {
if (mFile == null) {
Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
return;
}
if (mShuttingDown) {
return;
}
Parcel out = Parcel.obtain();
writeSummaryToParcel(out);
mLastWriteTime = SystemClock.elapsedRealtime();
if (mPendingWrite != null) {
mPendingWrite.recycle();
}
mPendingWrite = out;
if (sync) {
commitPendingDataToDisk();
} else {
Thread thr = new Thread("BatteryStats-Write") {
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
commitPendingDataToDisk();
}
};
thr.start();
}
}
public void commitPendingDataToDisk() {
final Parcel next;
synchronized (this) {
next = mPendingWrite;
mPendingWrite = null;
if (next == null) {
return;
}
mWriteLock.lock();
}
try {
FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
stream.write(next.marshall());
stream.flush();
stream.close();
mFile.commit();
} catch (IOException e) {
Slog.w("BatteryStats", "Error writing battery statistics", e);
mFile.rollback();
} finally {
next.recycle();
mWriteLock.unlock();
}
}
static byte[] readFully(FileInputStream stream) throws java.io.IOException {
int pos = 0;
int avail = stream.available();
byte[] data = new byte[avail];
while (true) {
int amt = stream.read(data, pos, data.length-pos);
//Log.i("foo", "Read " + amt + " bytes at " + pos
// + " of avail " + data.length);
if (amt <= 0) {
//Log.i("foo", "**** FINISHED READING: pos=" + pos
// + " len=" + data.length);
return data;
}
pos += amt;
avail = stream.available();
if (avail > data.length-pos) {
byte[] newData = new byte[pos+avail];
System.arraycopy(data, 0, newData, 0, pos);
data = newData;
}
}
}
public void readLocked() {
if (mFile == null) {
Slog.w("BatteryStats", "readLocked: no file associated with this instance");
return;
}
mUidStats.clear();
try {
File file = mFile.chooseForRead();
if (!file.exists()) {
return;
}
FileInputStream stream = new FileInputStream(file);
byte[] raw = readFully(stream);
Parcel in = Parcel.obtain();
in.unmarshall(raw, 0, raw.length);
in.setDataPosition(0);
stream.close();
readSummaryFromParcel(in);
} catch(java.io.IOException e) {
Slog.e("BatteryStats", "Error reading battery statistics", e);
}
addHistoryRecordLocked(SystemClock.elapsedRealtime(), HistoryItem.CMD_START);
}
public int describeContents() {
return 0;
}
void readHistory(Parcel in) {
mHistory = mHistoryEnd = mHistoryCache = null;
mHistoryBaseTime = 0;
long time;
while ((time=in.readLong()) >= 0) {
HistoryItem rec = new HistoryItem(time, in);
addHistoryRecordLocked(rec);
if (rec.time > mHistoryBaseTime) {
mHistoryBaseTime = rec.time;
}
}
long oldnow = SystemClock.elapsedRealtime() - (5*60*100);
if (oldnow > 0) {
// If the system process has restarted, but not the entire
// system, then the mHistoryBaseTime already accounts for
// much of the elapsed time. We thus want to adjust it back,
// to avoid large gaps in the data. We determine we are
// in this case by arbitrarily saying it is so if at this
// point in boot the elapsed time is already more than 5 seconds.
mHistoryBaseTime -= oldnow;
}
}
void writeHistory(Parcel out) {
HistoryItem rec = mHistory;
while (rec != null) {
if (rec.time >= 0) rec.writeToParcel(out, 0);
rec = rec.next;
}
out.writeLong(-1);
}
private void readSummaryFromParcel(Parcel in) {
final int version = in.readInt();
if (version != VERSION) {
Slog.w("BatteryStats", "readFromParcel: version got " + version
+ ", expected " + VERSION + "; erasing old stats");
return;
}
readHistory(in);
mStartCount = in.readInt();
mBatteryUptime = in.readLong();
mBatteryRealtime = in.readLong();
mUptime = in.readLong();
mRealtime = in.readLong();
mDischargeUnplugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
mLowDischargeAmountSinceCharge = in.readInt();
mHighDischargeAmountSinceCharge = in.readInt();
mStartCount++;
mScreenOn = false;
mScreenOnTimer.readSummaryFromParcelLocked(in);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
}
mInputEventCounter.readSummaryFromParcelLocked(in);
mPhoneOn = false;
mPhoneOnTimer.readSummaryFromParcelLocked(in);
for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
}
mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
}
mWifiOn = false;
mWifiOnTimer.readSummaryFromParcelLocked(in);
mGlobalWifiRunning = false;
mGlobalWifiRunningTimer.readSummaryFromParcelLocked(in);
mBluetoothOn = false;
mBluetoothOnTimer.readSummaryFromParcelLocked(in);
int NKW = in.readInt();
if (NKW > 10000) {
Slog.w(TAG, "File corrupt: too many kernel wake locks " + NKW);
return;
}
for (int ikw = 0; ikw < NKW; ikw++) {
if (in.readInt() != 0) {
String kwltName = in.readString();
getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
}
}
sNumSpeedSteps = in.readInt();
final int NU = in.readInt();
if (NU > 10000) {
Slog.w(TAG, "File corrupt: too many uids " + NU);
return;
}
for (int iu = 0; iu < NU; iu++) {
int uid = in.readInt();
Uid u = new Uid(uid);
mUidStats.put(uid, u);
u.mWifiRunning = false;
if (in.readInt() != 0) {
u.mWifiRunningTimer.readSummaryFromParcelLocked(in);
}
u.mFullWifiLockOut = false;
if (in.readInt() != 0) {
u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
}
u.mScanWifiLockOut = false;
if (in.readInt() != 0) {
u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
}
u.mWifiMulticastEnabled = false;
if (in.readInt() != 0) {
u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
}
u.mAudioTurnedOn = false;
if (in.readInt() != 0) {
u.mAudioTurnedOnTimer.readSummaryFromParcelLocked(in);
}
u.mVideoTurnedOn = false;
if (in.readInt() != 0) {
u.mVideoTurnedOnTimer.readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
if (u.mUserActivityCounters == null) {
u.initUserActivityLocked();
}
for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
}
}
int NW = in.readInt();
if (NW > 10000) {
Slog.w(TAG, "File corrupt: too many wake locks " + NW);
return;
}
for (int iw = 0; iw < NW; iw++) {
String wlName = in.readString();
if (in.readInt() != 0) {
u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
}
}
int NP = in.readInt();
if (NP > 10000) {
Slog.w(TAG, "File corrupt: too many sensors " + NP);
return;
}
for (int is = 0; is < NP; is++) {
int seNumber = in.readInt();
if (in.readInt() != 0) {
u.getSensorTimerLocked(seNumber, true)
.readSummaryFromParcelLocked(in);
}
}
NP = in.readInt();
if (NP > 10000) {
Slog.w(TAG, "File corrupt: too many processes " + NP);
return;
}
for (int ip = 0; ip < NP; ip++) {
String procName = in.readString();
Uid.Proc p = u.getProcessStatsLocked(procName);
p.mUserTime = p.mLoadedUserTime = in.readLong();
p.mSystemTime = p.mLoadedSystemTime = in.readLong();
p.mStarts = p.mLoadedStarts = in.readInt();
int NSB = in.readInt();
p.mSpeedBins = new SamplingCounter[NSB];
for (int i=0; i<NSB; i++) {
if (in.readInt() != 0) {
p.mSpeedBins[i] = new SamplingCounter(mUnpluggables);
p.mSpeedBins[i].readSummaryFromParcelLocked(in);
}
}
p.readExcessivePowerFromParcelLocked(in);
}
NP = in.readInt();
if (NP > 10000) {
Slog.w(TAG, "File corrupt: too many packages " + NP);
return;
}
for (int ip = 0; ip < NP; ip++) {
String pkgName = in.readString();
Uid.Pkg p = u.getPackageStatsLocked(pkgName);
p.mWakeups = p.mLoadedWakeups = in.readInt();
final int NS = in.readInt();
for (int is = 0; is < NS; is++) {
String servName = in.readString();
Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
s.mStartTime = s.mLoadedStartTime = in.readLong();
s.mStarts = s.mLoadedStarts = in.readInt();
s.mLaunches = s.mLoadedLaunches = in.readInt();
}
}
u.mLoadedTcpBytesReceived = in.readLong();
u.mLoadedTcpBytesSent = in.readLong();
}
}
/**
* Writes a summary of the statistics to a Parcel, in a format suitable to be written to
* disk. This format does not allow a lossless round-trip.
*
* @param out the Parcel to be written to.
*/
public void writeSummaryToParcel(Parcel out) {
final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
final long NOW = getBatteryUptimeLocked(NOW_SYS);
final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
out.writeInt(VERSION);
writeHistory(out);
out.writeInt(mStartCount);
out.writeLong(computeBatteryUptime(NOW_SYS, STATS_SINCE_CHARGED));
out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
out.writeInt(mDischargeUnplugLevel);
out.writeInt(mDischargeCurrentLevel);
out.writeInt(mLowDischargeAmountSinceCharge);
out.writeInt(mHighDischargeAmountSinceCharge);
mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
}
mInputEventCounter.writeSummaryFromParcelLocked(out);
mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
}
mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
}
mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
out.writeInt(mKernelWakelockStats.size());
for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
Timer kwlt = ent.getValue();
if (kwlt != null) {
out.writeInt(1);
out.writeString(ent.getKey());
ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
}
out.writeInt(sNumSpeedSteps);
final int NU = mUidStats.size();
out.writeInt(NU);
for (int iu = 0; iu < NU; iu++) {
out.writeInt(mUidStats.keyAt(iu));
Uid u = mUidStats.valueAt(iu);
if (u.mWifiRunningTimer != null) {
out.writeInt(1);
u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
if (u.mFullWifiLockTimer != null) {
out.writeInt(1);
u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
if (u.mScanWifiLockTimer != null) {
out.writeInt(1);
u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
if (u.mWifiMulticastTimer != null) {
out.writeInt(1);
u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
if (u.mAudioTurnedOnTimer != null) {
out.writeInt(1);
u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
if (u.mVideoTurnedOnTimer != null) {
out.writeInt(1);
u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
if (u.mUserActivityCounters == null) {
out.writeInt(0);
} else {
out.writeInt(1);
for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
}
}
int NW = u.mWakelockStats.size();
out.writeInt(NW);
if (NW > 0) {
for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
: u.mWakelockStats.entrySet()) {
out.writeString(ent.getKey());
Uid.Wakelock wl = ent.getValue();
if (wl.mTimerFull != null) {
out.writeInt(1);
wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
if (wl.mTimerPartial != null) {
out.writeInt(1);
wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
if (wl.mTimerWindow != null) {
out.writeInt(1);
wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
}
}
int NSE = u.mSensorStats.size();
out.writeInt(NSE);
if (NSE > 0) {
for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
: u.mSensorStats.entrySet()) {
out.writeInt(ent.getKey());
Uid.Sensor se = ent.getValue();
if (se.mTimer != null) {
out.writeInt(1);
se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
}
}
int NP = u.mProcessStats.size();
out.writeInt(NP);
if (NP > 0) {
for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
: u.mProcessStats.entrySet()) {
out.writeString(ent.getKey());
Uid.Proc ps = ent.getValue();
out.writeLong(ps.mUserTime);
out.writeLong(ps.mSystemTime);
out.writeInt(ps.mStarts);
final int N = ps.mSpeedBins.length;
out.writeInt(N);
for (int i=0; i<N; i++) {
if (ps.mSpeedBins[i] != null) {
out.writeInt(1);
ps.mSpeedBins[i].writeSummaryFromParcelLocked(out);
} else {
out.writeInt(0);
}
}
ps.writeExcessivePowerToParcelLocked(out);
}
}
NP = u.mPackageStats.size();
out.writeInt(NP);
if (NP > 0) {
for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
: u.mPackageStats.entrySet()) {
out.writeString(ent.getKey());
Uid.Pkg ps = ent.getValue();
out.writeInt(ps.mWakeups);
final int NS = ps.mServiceStats.size();
out.writeInt(NS);
if (NS > 0) {
for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
: ps.mServiceStats.entrySet()) {
out.writeString(sent.getKey());
BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
long time = ss.getStartTimeToNowLocked(NOW);
out.writeLong(time);
out.writeInt(ss.mStarts);
out.writeInt(ss.mLaunches);
}
}
}
}
out.writeLong(u.getTcpBytesReceived(STATS_SINCE_CHARGED));
out.writeLong(u.getTcpBytesSent(STATS_SINCE_CHARGED));
}
}
public void readFromParcel(Parcel in) {
readFromParcelLocked(in);
}
void readFromParcelLocked(Parcel in) {
int magic = in.readInt();
if (magic != MAGIC) {
throw new ParcelFormatException("Bad magic number");
}
readHistory(in);
mStartCount = in.readInt();
mBatteryUptime = in.readLong();
mBatteryLastUptime = 0;
mBatteryRealtime = in.readLong();
mBatteryLastRealtime = 0;
mScreenOn = false;
mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables, in);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i,
null, mUnpluggables, in);
}
mInputEventCounter = new Counter(mUnpluggables, in);
mPhoneOn = false;
mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
null, mUnpluggables, in);
}
mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables, in);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
null, mUnpluggables, in);
}
mWifiOn = false;
mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
mGlobalWifiRunning = false;
mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
mBluetoothOn = false;
mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
mUptime = in.readLong();
mUptimeStart = in.readLong();
mLastUptime = 0;
mRealtime = in.readLong();
mRealtimeStart = in.readLong();
mLastRealtime = 0;
mOnBattery = in.readInt() != 0;
mOnBatteryInternal = false; // we are no longer really running.
mTrackBatteryPastUptime = in.readLong();
mTrackBatteryUptimeStart = in.readLong();
mTrackBatteryPastRealtime = in.readLong();
mTrackBatteryRealtimeStart = in.readLong();
mUnpluggedBatteryUptime = in.readLong();
mUnpluggedBatteryRealtime = in.readLong();
mDischargeUnplugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
mLowDischargeAmountSinceCharge = in.readInt();
mHighDischargeAmountSinceCharge = in.readInt();
mLastWriteTime = in.readLong();
mMobileDataRx[STATS_LAST] = in.readLong();
mMobileDataRx[STATS_SINCE_UNPLUGGED] = -1;
mMobileDataTx[STATS_LAST] = in.readLong();
mMobileDataTx[STATS_SINCE_UNPLUGGED] = -1;
mTotalDataRx[STATS_LAST] = in.readLong();
mTotalDataRx[STATS_SINCE_UNPLUGGED] = -1;
mTotalDataTx[STATS_LAST] = in.readLong();
mTotalDataTx[STATS_SINCE_UNPLUGGED] = -1;
mRadioDataUptime = in.readLong();
mRadioDataStart = -1;
mBluetoothPingCount = in.readInt();
mBluetoothPingStart = -1;
mKernelWakelockStats.clear();
int NKW = in.readInt();
for (int ikw = 0; ikw < NKW; ikw++) {
if (in.readInt() != 0) {
String wakelockName = in.readString();
in.readInt(); // Extra 0/1 written by Timer.writeTimerToParcel
SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
mKernelWakelockStats.put(wakelockName, kwlt);
}
}
mPartialTimers.clear();
mFullTimers.clear();
mWindowTimers.clear();
mWifiRunningTimers.clear();
mFullWifiLockTimers.clear();
mScanWifiLockTimers.clear();
mWifiMulticastTimers.clear();
sNumSpeedSteps = in.readInt();
int numUids = in.readInt();
mUidStats.clear();
for (int i = 0; i < numUids; i++) {
int uid = in.readInt();
Uid u = new Uid(uid);
u.readFromParcelLocked(mUnpluggables, in);
mUidStats.append(uid, u);
}
}
public void writeToParcel(Parcel out, int flags) {
writeToParcelLocked(out, true, flags);
}
public void writeToParcelWithoutUids(Parcel out, int flags) {
writeToParcelLocked(out, false, flags);
}
@SuppressWarnings("unused")
void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
final long uSecUptime = SystemClock.uptimeMillis() * 1000;
final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
out.writeInt(MAGIC);
writeHistory(out);
out.writeInt(mStartCount);
out.writeLong(mBatteryUptime);
out.writeLong(mBatteryRealtime);
mScreenOnTimer.writeToParcel(out, batteryRealtime);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
}
mInputEventCounter.writeToParcel(out);
mPhoneOnTimer.writeToParcel(out, batteryRealtime);
for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
}
mPhoneSignalScanningTimer.writeToParcel(out, batteryRealtime);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
}
mWifiOnTimer.writeToParcel(out, batteryRealtime);
mGlobalWifiRunningTimer.writeToParcel(out, batteryRealtime);
mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
out.writeLong(mUptime);
out.writeLong(mUptimeStart);
out.writeLong(mRealtime);
out.writeLong(mRealtimeStart);
out.writeInt(mOnBattery ? 1 : 0);
out.writeLong(batteryUptime);
out.writeLong(mTrackBatteryUptimeStart);
out.writeLong(batteryRealtime);
out.writeLong(mTrackBatteryRealtimeStart);
out.writeLong(mUnpluggedBatteryUptime);
out.writeLong(mUnpluggedBatteryRealtime);
out.writeInt(mDischargeUnplugLevel);
out.writeInt(mDischargeCurrentLevel);
out.writeInt(mLowDischargeAmountSinceCharge);
out.writeInt(mHighDischargeAmountSinceCharge);
out.writeLong(mLastWriteTime);
out.writeLong(getMobileTcpBytesReceived(STATS_SINCE_UNPLUGGED));
out.writeLong(getMobileTcpBytesSent(STATS_SINCE_UNPLUGGED));
out.writeLong(getTotalTcpBytesReceived(STATS_SINCE_UNPLUGGED));
out.writeLong(getTotalTcpBytesSent(STATS_SINCE_UNPLUGGED));
// Write radio uptime for data
out.writeLong(getRadioDataUptime());
out.writeInt(getBluetoothPingCount());
if (inclUids) {
out.writeInt(mKernelWakelockStats.size());
for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
SamplingTimer kwlt = ent.getValue();
if (kwlt != null) {
out.writeInt(1);
out.writeString(ent.getKey());
Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
} else {
out.writeInt(0);
}
}
} else {
out.writeInt(0);
}
out.writeInt(sNumSpeedSteps);
if (inclUids) {
int size = mUidStats.size();
out.writeInt(size);
for (int i = 0; i < size; i++) {
out.writeInt(mUidStats.keyAt(i));
Uid uid = mUidStats.valueAt(i);
uid.writeToParcelLocked(out, batteryRealtime);
}
} else {
out.writeInt(0);
}
}
public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
new Parcelable.Creator<BatteryStatsImpl>() {
public BatteryStatsImpl createFromParcel(Parcel in) {
return new BatteryStatsImpl(in);
}
public BatteryStatsImpl[] newArray(int size) {
return new BatteryStatsImpl[size];
}
};
public void dumpLocked(PrintWriter pw) {
if (DEBUG) {
Printer pr = new PrintWriterPrinter(pw);
pr.println("*** Screen timer:");
mScreenOnTimer.logState(pr, " ");
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
pr.println("*** Screen brightness #" + i + ":");
mScreenBrightnessTimer[i].logState(pr, " ");
}
pr.println("*** Input event counter:");
mInputEventCounter.logState(pr, " ");
pr.println("*** Phone timer:");
mPhoneOnTimer.logState(pr, " ");
for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
pr.println("*** Signal strength #" + i + ":");
mPhoneSignalStrengthsTimer[i].logState(pr, " ");
}
pr.println("*** Signal scanning :");
mPhoneSignalScanningTimer.logState(pr, " ");
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
pr.println("*** Data connection type #" + i + ":");
mPhoneDataConnectionsTimer[i].logState(pr, " ");
}
pr.println("*** Wifi timer:");
mWifiOnTimer.logState(pr, " ");
pr.println("*** WifiRunning timer:");
mGlobalWifiRunningTimer.logState(pr, " ");
pr.println("*** Bluetooth timer:");
mBluetoothOnTimer.logState(pr, " ");
}
super.dumpLocked(pw);
}
}