com.android.internal.os.BatteryStatsImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of android-all Show documentation
Show all versions of android-all Show documentation
A library jar that provides APIs for Applications written for the Google Android Platform.
/*
* 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 static android.net.NetworkStats.UID_ALL;
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
import android.app.ActivityManager;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkStats;
import android.net.wifi.WifiManager;
import android.os.BadParcelableException;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Build;
import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
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.SystemProperties;
import android.os.WorkSource;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.LogWriter;
import android.util.MutableInt;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.JournaledFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
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;
private static final boolean USE_OLD_HISTORY = false; // for debugging.
// TODO: remove "tcp" from network methods, since we measure total stats.
// 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 = 114 + (USE_OLD_HISTORY ? 1000 : 0);
// 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 = 100;
private static int sNumSpeedSteps;
private final JournaledFile mFile;
public final AtomicFile mCheckinFile;
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 {
public MyHandler(Looper looper) {
super(looper, null, true);
}
@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;
}
}
}
public final MyHandler mHandler;
private BatteryCallback mCallback;
/**
* Mapping isolated uids to the actual owning app uid.
*/
final SparseIntArray mIsolatedUids = new SparseIntArray();
/**
* The statistics we have collected organized by uids.
*/
final SparseArray mUidStats =
new SparseArray();
// 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 mPartialTimers = new ArrayList();
final ArrayList mFullTimers = new ArrayList();
final ArrayList mWindowTimers = new ArrayList();
final SparseArray> mSensorTimers
= new SparseArray>();
final ArrayList mWifiRunningTimers = new ArrayList();
final ArrayList mFullWifiLockTimers = new ArrayList();
final ArrayList mWifiMulticastTimers = new ArrayList();
final ArrayList mWifiScanTimers = new ArrayList();
final SparseArray> mWifiBatchedScanTimers =
new SparseArray>();
final ArrayList mAudioTurnedOnTimers = new ArrayList();
final ArrayList mVideoTurnedOnTimers = new ArrayList();
// Last partial timers we use for distributing CPU usage.
final ArrayList mLastPartialTimers = new ArrayList();
// These are the objects that will want to do something when the device
// is unplugged from power.
final TimeBase mOnBatteryTimeBase = new TimeBase();
// These are the objects that will want to do something when the device
// is unplugged from power *and* the screen is off.
final TimeBase mOnBatteryScreenOffTimeBase = new TimeBase();
// Set to true when we want to distribute CPU across wakelocks for the next
// CPU update, even if we aren't currently running wake locks.
boolean mDistributeWakelockCpu;
boolean mShuttingDown;
final HistoryEventTracker mActiveEvents = new HistoryEventTracker();
long mHistoryBaseTime;
boolean mHaveBatteryLevel = false;
boolean mRecordingHistory = false;
int mNumHistoryItems;
static final int MAX_HISTORY_BUFFER = 256*1024; // 256KB
static final int MAX_MAX_HISTORY_BUFFER = 320*1024; // 320KB
final Parcel mHistoryBuffer = Parcel.obtain();
final HistoryItem mHistoryLastWritten = new HistoryItem();
final HistoryItem mHistoryLastLastWritten = new HistoryItem();
final HistoryItem mHistoryReadTmp = new HistoryItem();
final HistoryItem mHistoryAddTmp = new HistoryItem();
final HashMap mHistoryTagPool = new HashMap();
String[] mReadHistoryStrings;
int[] mReadHistoryUids;
int mReadHistoryChars;
int mNextHistoryTagIdx = 0;
int mNumHistoryTagChars = 0;
int mHistoryBufferLastPos = -1;
boolean mHistoryOverflow = false;
long mLastHistoryElapsedRealtime = 0;
long mTrackRunningHistoryElapsedRealtime = 0;
long mTrackRunningHistoryUptime = 0;
final HistoryItem mHistoryCur = new HistoryItem();
HistoryItem mHistory;
HistoryItem mHistoryEnd;
HistoryItem mHistoryLastEnd;
HistoryItem mHistoryCache;
private HistoryItem mHistoryIterator;
private boolean mReadOverflow;
private boolean mIteratingHistory;
int mStartCount;
long mStartClockTime;
String mStartPlatformVersion;
String mEndPlatformVersion;
long mLastRecordedClockTime;
long mLastRecordedClockRealtime;
long mUptime;
long mUptimeStart;
long mRealtime;
long mRealtimeStart;
int mWakeLockNesting;
boolean mWakeLockImportant;
boolean mRecordAllHistory;
boolean mNoAutoReset;
int mScreenState = Display.STATE_UNKNOWN;
StopwatchTimer mScreenOnTimer;
int mScreenBrightnessBin = -1;
final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
boolean mInteractive;
StopwatchTimer mInteractiveTimer;
boolean mLowPowerModeEnabled;
StopwatchTimer mLowPowerModeEnabledTimer;
boolean mPhoneOn;
StopwatchTimer mPhoneOnTimer;
int mAudioOnNesting;
StopwatchTimer mAudioOnTimer;
int mVideoOnNesting;
StopwatchTimer mVideoOnTimer;
boolean mFlashlightOn;
StopwatchTimer mFlashlightOnTimer;
int mPhoneSignalStrengthBin = -1;
int mPhoneSignalStrengthBinRaw = -1;
final StopwatchTimer[] mPhoneSignalStrengthsTimer =
new StopwatchTimer[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
StopwatchTimer mPhoneSignalScanningTimer;
int mPhoneDataConnectionType = -1;
final StopwatchTimer[] mPhoneDataConnectionsTimer =
new StopwatchTimer[NUM_DATA_CONNECTION_TYPES];
final LongSamplingCounter[] mNetworkByteActivityCounters =
new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
final LongSamplingCounter[] mNetworkPacketActivityCounters =
new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
boolean mWifiOn;
StopwatchTimer mWifiOnTimer;
boolean mGlobalWifiRunning;
StopwatchTimer mGlobalWifiRunningTimer;
int mWifiState = -1;
final StopwatchTimer[] mWifiStateTimer = new StopwatchTimer[NUM_WIFI_STATES];
int mWifiSupplState = -1;
final StopwatchTimer[] mWifiSupplStateTimer = new StopwatchTimer[NUM_WIFI_SUPPL_STATES];
int mWifiSignalStrengthBin = -1;
final StopwatchTimer[] mWifiSignalStrengthsTimer =
new StopwatchTimer[NUM_WIFI_SIGNAL_STRENGTH_BINS];
boolean mBluetoothOn;
StopwatchTimer mBluetoothOnTimer;
int mBluetoothState = -1;
final StopwatchTimer[] mBluetoothStateTimer = new StopwatchTimer[NUM_BLUETOOTH_STATES];
int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
long mMobileRadioActiveStartTime;
StopwatchTimer mMobileRadioActiveTimer;
StopwatchTimer mMobileRadioActivePerAppTimer;
LongSamplingCounter mMobileRadioActiveAdjustedTime;
LongSamplingCounter mMobileRadioActiveUnknownTime;
LongSamplingCounter mMobileRadioActiveUnknownCount;
/** Bluetooth headset object */
BluetoothHeadset mBtHeadset;
/**
* These provide time bases that discount the time the device is plugged
* in to power.
*/
boolean mOnBattery;
boolean mOnBatteryInternal;
/*
* These keep track of battery levels (1-100) at the last plug event and the last unplug event.
*/
int mDischargeStartLevel;
int mDischargeUnplugLevel;
int mDischargePlugLevel;
int mDischargeCurrentLevel;
int mCurrentBatteryLevel;
int mLowDischargeAmountSinceCharge;
int mHighDischargeAmountSinceCharge;
int mDischargeScreenOnUnplugLevel;
int mDischargeScreenOffUnplugLevel;
int mDischargeAmountScreenOn;
int mDischargeAmountScreenOnSinceCharge;
int mDischargeAmountScreenOff;
int mDischargeAmountScreenOffSinceCharge;
static final int MAX_LEVEL_STEPS = 200;
int mInitStepMode = 0;
int mCurStepMode = 0;
int mModStepMode = 0;
int mLastDischargeStepLevel;
long mLastDischargeStepTime;
int mMinDischargeStepLevel;
int mNumDischargeStepDurations;
final long[] mDischargeStepDurations = new long[MAX_LEVEL_STEPS];
int mLastChargeStepLevel;
long mLastChargeStepTime;
int mMaxChargeStepLevel;
int mNumChargeStepDurations;
final long[] mChargeStepDurations = new long[MAX_LEVEL_STEPS];
long mLastWriteTime = 0; // Milliseconds
private int mBluetoothPingCount;
private int mBluetoothPingStart = -1;
private int mPhoneServiceState = -1;
private int mPhoneServiceStateRaw = -1;
private int mPhoneSimStateRaw = -1;
/*
* Holds a SamplingTimer associated with each kernel wakelock name being tracked.
*/
private final HashMap mKernelWakelockStats =
new HashMap();
public Map getKernelWakelockStats() {
return mKernelWakelockStats;
}
private static int sKernelWakelockUpdateVersion = 0;
String mLastWakeupReason = null;
long mLastWakeupUptimeMs = 0;
private final HashMap mWakeupReasonStats = new HashMap<>();
public Map getWakeupReasonStats() {
return mWakeupReasonStats;
}
private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
Process.PROC_TAB_TERM|Process.PROC_OUT_STRING| // 0: name
Process.PROC_QUOTES,
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 static final int[] WAKEUP_SOURCES_FORMAT = new int[] {
Process.PROC_TAB_TERM|Process.PROC_OUT_STRING, // 0: name
Process.PROC_TAB_TERM|Process.PROC_COMBINE|
Process.PROC_OUT_LONG, // 1: count
Process.PROC_TAB_TERM|Process.PROC_COMBINE,
Process.PROC_TAB_TERM|Process.PROC_COMBINE,
Process.PROC_TAB_TERM|Process.PROC_COMBINE,
Process.PROC_TAB_TERM|Process.PROC_COMBINE,
Process.PROC_TAB_TERM|Process.PROC_COMBINE
|Process.PROC_OUT_LONG, // 6: 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 mProcWakelockFileStats =
new HashMap();
private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
private NetworkStats mCurMobileSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
private NetworkStats mLastMobileSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
private NetworkStats mCurWifiSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
private NetworkStats mLastWifiSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
private NetworkStats mTmpNetworkStats;
private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
@GuardedBy("this")
private String[] mMobileIfaces = new String[0];
@GuardedBy("this")
private String[] mWifiIfaces = new String[0];
public BatteryStatsImpl() {
mFile = null;
mCheckinFile = null;
mHandler = null;
clearHistoryLocked();
}
public static interface TimeBaseObs {
void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime);
void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime);
}
static class TimeBase {
private final ArrayList mObservers = new ArrayList();
private long mUptime;
private long mRealtime;
private boolean mRunning;
private long mPastUptime;
private long mUptimeStart;
private long mPastRealtime;
private long mRealtimeStart;
private long mUnpluggedUptime;
private long mUnpluggedRealtime;
public void dump(PrintWriter pw, String prefix) {
StringBuilder sb = new StringBuilder(128);
pw.print(prefix); pw.print("mRunning="); pw.println(mRunning);
sb.setLength(0);
sb.append(prefix);
sb.append("mUptime=");
formatTimeMs(sb, mUptime / 1000);
pw.println(sb.toString());
sb.setLength(0);
sb.append(prefix);
sb.append("mRealtime=");
formatTimeMs(sb, mRealtime / 1000);
pw.println(sb.toString());
sb.setLength(0);
sb.append(prefix);
sb.append("mPastUptime=");
formatTimeMs(sb, mPastUptime / 1000); sb.append("mUptimeStart=");
formatTimeMs(sb, mUptimeStart / 1000);
sb.append("mUnpluggedUptime="); formatTimeMs(sb, mUnpluggedUptime / 1000);
pw.println(sb.toString());
sb.setLength(0);
sb.append(prefix);
sb.append("mPastRealtime=");
formatTimeMs(sb, mPastRealtime / 1000); sb.append("mRealtimeStart=");
formatTimeMs(sb, mRealtimeStart / 1000);
sb.append("mUnpluggedRealtime="); formatTimeMs(sb, mUnpluggedRealtime / 1000);
pw.println(sb.toString());
}
public void add(TimeBaseObs observer) {
mObservers.add(observer);
}
public void remove(TimeBaseObs observer) {
if (!mObservers.remove(observer)) {
Slog.wtf(TAG, "Removed unknown observer: " + observer);
}
}
public void init(long uptime, long realtime) {
mRealtime = 0;
mUptime = 0;
mPastUptime = 0;
mPastRealtime = 0;
mUptimeStart = uptime;
mRealtimeStart = realtime;
mUnpluggedUptime = getUptime(mUptimeStart);
mUnpluggedRealtime = getRealtime(mRealtimeStart);
}
public void reset(long uptime, long realtime) {
if (!mRunning) {
mPastUptime = 0;
mPastRealtime = 0;
} else {
mUptimeStart = uptime;
mRealtimeStart = realtime;
mUnpluggedUptime = getUptime(uptime);
mUnpluggedRealtime = getRealtime(realtime);
}
}
public long computeUptime(long curTime, int which) {
switch (which) {
case STATS_SINCE_CHARGED:
return mUptime + getUptime(curTime);
case STATS_CURRENT:
return getUptime(curTime);
case STATS_SINCE_UNPLUGGED:
return getUptime(curTime) - mUnpluggedUptime;
}
return 0;
}
public long computeRealtime(long curTime, int which) {
switch (which) {
case STATS_SINCE_CHARGED:
return mRealtime + getRealtime(curTime);
case STATS_CURRENT:
return getRealtime(curTime);
case STATS_SINCE_UNPLUGGED:
return getRealtime(curTime) - mUnpluggedRealtime;
}
return 0;
}
public long getUptime(long curTime) {
long time = mPastUptime;
if (mRunning) {
time += curTime - mUptimeStart;
}
return time;
}
public long getRealtime(long curTime) {
long time = mPastRealtime;
if (mRunning) {
time += curTime - mRealtimeStart;
}
return time;
}
public long getUptimeStart() {
return mUptimeStart;
}
public long getRealtimeStart() {
return mRealtimeStart;
}
public boolean isRunning() {
return mRunning;
}
public boolean setRunning(boolean running, long uptime, long realtime) {
if (mRunning != running) {
mRunning = running;
if (running) {
mUptimeStart = uptime;
mRealtimeStart = realtime;
long batteryUptime = mUnpluggedUptime = getUptime(uptime);
long batteryRealtime = mUnpluggedRealtime = getRealtime(realtime);
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onTimeStarted(realtime, batteryUptime, batteryRealtime);
}
} else {
mPastUptime += uptime - mUptimeStart;
mPastRealtime += realtime - mRealtimeStart;
long batteryUptime = getUptime(uptime);
long batteryRealtime = getRealtime(realtime);
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onTimeStopped(realtime, batteryUptime, batteryRealtime);
}
}
return true;
}
return false;
}
public void readSummaryFromParcel(Parcel in) {
mUptime = in.readLong();
mRealtime = in.readLong();
}
public void writeSummaryToParcel(Parcel out, long uptime, long realtime) {
out.writeLong(computeUptime(uptime, STATS_SINCE_CHARGED));
out.writeLong(computeRealtime(realtime, STATS_SINCE_CHARGED));
}
public void readFromParcel(Parcel in) {
mRunning = false;
mUptime = in.readLong();
mPastUptime = in.readLong();
mUptimeStart = in.readLong();
mRealtime = in.readLong();
mPastRealtime = in.readLong();
mRealtimeStart = in.readLong();
mUnpluggedUptime = in.readLong();
mUnpluggedRealtime = in.readLong();
}
public void writeToParcel(Parcel out, long uptime, long realtime) {
final long runningUptime = getUptime(uptime);
final long runningRealtime = getRealtime(realtime);
out.writeLong(mUptime);
out.writeLong(runningUptime);
out.writeLong(mUptimeStart);
out.writeLong(mRealtime);
out.writeLong(runningRealtime);
out.writeLong(mRealtimeStart);
out.writeLong(mUnpluggedUptime);
out.writeLong(mUnpluggedRealtime);
}
}
/**
* State for keeping track of counting information.
*/
public static class Counter extends BatteryStats.Counter implements TimeBaseObs {
final AtomicInteger mCount = new AtomicInteger();
final TimeBase mTimeBase;
int mLoadedCount;
int mLastCount;
int mUnpluggedCount;
int mPluggedCount;
Counter(TimeBase timeBase, Parcel in) {
mTimeBase = timeBase;
mPluggedCount = in.readInt();
mCount.set(mPluggedCount);
mLoadedCount = in.readInt();
mLastCount = 0;
mUnpluggedCount = in.readInt();
timeBase.add(this);
}
Counter(TimeBase timeBase) {
mTimeBase = timeBase;
timeBase.add(this);
}
public void writeToParcel(Parcel out) {
out.writeInt(mCount.get());
out.writeInt(mLoadedCount);
out.writeInt(mUnpluggedCount);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
mUnpluggedCount = mPluggedCount;
mCount.set(mPluggedCount);
}
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
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 = 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() {
mTimeBase.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(TimeBase timeBase, Parcel in) {
super(timeBase, in);
}
SamplingCounter(TimeBase timeBase) {
super(timeBase);
}
public void addCountAtomic(long count) {
mCount.addAndGet((int)count);
}
}
public static class LongSamplingCounter extends LongCounter implements TimeBaseObs {
final TimeBase mTimeBase;
long mCount;
long mLoadedCount;
long mLastCount;
long mUnpluggedCount;
long mPluggedCount;
LongSamplingCounter(TimeBase timeBase, Parcel in) {
mTimeBase = timeBase;
mPluggedCount = in.readLong();
mCount = mPluggedCount;
mLoadedCount = in.readLong();
mLastCount = 0;
mUnpluggedCount = in.readLong();
timeBase.add(this);
}
LongSamplingCounter(TimeBase timeBase) {
mTimeBase = timeBase;
timeBase.add(this);
}
public void writeToParcel(Parcel out) {
out.writeLong(mCount);
out.writeLong(mLoadedCount);
out.writeLong(mUnpluggedCount);
}
@Override
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
mUnpluggedCount = mPluggedCount;
mCount = mPluggedCount;
}
@Override
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
mPluggedCount = mCount;
}
public long getCountLocked(int which) {
long val = mCount;
if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedCount;
} else if (which != STATS_SINCE_CHARGED) {
val -= mLoadedCount;
}
return val;
}
@Override
public void logState(Printer pw, String prefix) {
pw.println(prefix + "mCount=" + mCount
+ " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
+ " mUnpluggedCount=" + mUnpluggedCount
+ " mPluggedCount=" + mPluggedCount);
}
void addCountLocked(long count) {
mCount += count;
}
/**
* Clear state of this counter.
*/
void reset(boolean detachIfReset) {
mCount = 0;
mLoadedCount = mLastCount = mPluggedCount = mUnpluggedCount = 0;
if (detachIfReset) {
detach();
}
}
void detach() {
mTimeBase.remove(this);
}
void writeSummaryFromParcelLocked(Parcel out) {
out.writeLong(mCount);
}
void readSummaryFromParcelLocked(Parcel in) {
mLoadedCount = in.readLong();
mCount = mLoadedCount;
mLastCount = 0;
mUnpluggedCount = mPluggedCount = mLoadedCount;
}
}
/**
* State for keeping track of timing information.
*/
public static abstract class Timer extends BatteryStats.Timer implements TimeBaseObs {
final int mType;
final TimeBase mTimeBase;
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 timeBase
* @param in
*/
Timer(int type, TimeBase timeBase, Parcel in) {
mType = type;
mTimeBase = timeBase;
mCount = in.readInt();
mLoadedCount = in.readInt();
mLastCount = 0;
mUnpluggedCount = in.readInt();
mTotalTime = in.readLong();
mLoadedTime = in.readLong();
mLastTime = 0;
mUnpluggedTime = in.readLong();
timeBase.add(this);
if (DEBUG) Log.i(TAG, "**** READ TIMER #" + mType + ": mTotalTime=" + mTotalTime);
}
Timer(int type, TimeBase timeBase) {
mType = type;
mTimeBase = timeBase;
timeBase.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(boolean detachIfReset) {
mTotalTime = mLoadedTime = mLastTime = 0;
mCount = mLoadedCount = mLastCount = 0;
if (detachIfReset) {
detach();
}
return true;
}
void detach() {
mTimeBase.remove(this);
}
public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
if (DEBUG) Log.i(TAG, "**** WRITING TIMER #" + mType + ": mTotalTime="
+ computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
out.writeInt(mCount);
out.writeInt(mLoadedCount);
out.writeInt(mUnpluggedCount);
out.writeLong(computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
out.writeLong(mLoadedTime);
out.writeLong(mUnpluggedTime);
}
public void onTimeStarted(long elapsedRealtime, long timeBaseUptime, long baseRealtime) {
if (DEBUG && mType < 0) {
Log.v(TAG, "unplug #" + mType + ": realtime=" + baseRealtime
+ " old mUnpluggedTime=" + mUnpluggedTime
+ " old mUnpluggedCount=" + mUnpluggedCount);
}
mUnpluggedTime = computeRunTimeLocked(baseRealtime);
mUnpluggedCount = mCount;
if (DEBUG && mType < 0) {
Log.v(TAG, "unplug #" + mType
+ ": new mUnpluggedTime=" + mUnpluggedTime
+ " new mUnpluggedCount=" + mUnpluggedCount);
}
}
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
if (DEBUG && mType < 0) {
Log.v(TAG, "plug #" + mType + ": realtime=" + baseRealtime
+ " old mTotalTime=" + mTotalTime);
}
mTotalTime = computeRunTimeLocked(baseRealtime);
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 elapsedRealtimeUs) {
if (timer == null) {
out.writeInt(0); // indicates null
return;
}
out.writeInt(1); // indicates non-null
timer.writeToParcel(out, elapsedRealtimeUs);
}
@Override
public long getTotalTimeLocked(long elapsedRealtimeUs, int which) {
long val = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
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 = 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 elapsedRealtimeUs) {
long runTime = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
out.writeLong(runTime);
out.writeInt(mCount);
}
void readSummaryFromParcelLocked(Parcel in) {
// Multiply by 1000 for backwards compatibility
mTotalTime = mLoadedTime = in.readLong();
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 mTimeBaseRunning;
/**
* Whether we are currently recording reported values.
*/
boolean mTrackingReportedValues;
/*
* A sequence counter, incremented once for each update of the stats.
*/
int mUpdateVersion;
SamplingTimer(TimeBase timeBase, Parcel in) {
super(0, timeBase, in);
mCurrentReportedCount = in.readInt();
mUnpluggedReportedCount = in.readInt();
mCurrentReportedTotalTime = in.readLong();
mUnpluggedReportedTotalTime = in.readLong();
mTrackingReportedValues = in.readInt() == 1;
mTimeBaseRunning = timeBase.isRunning();
}
SamplingTimer(TimeBase timeBase, boolean trackReportedValues) {
super(0, timeBase);
mTrackingReportedValues = trackReportedValues;
mTimeBaseRunning = timeBase.isRunning();
}
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 (mTimeBaseRunning && 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 addCurrentReportedCount(int delta) {
updateCurrentReportedCount(mCurrentReportedCount + delta);
}
public void updateCurrentReportedTotalTime(long totalTime) {
if (mTimeBaseRunning && 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 addCurrentReportedTotalTime(long delta) {
updateCurrentReportedTotalTime(mCurrentReportedTotalTime + delta);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
super.onTimeStarted(elapsedRealtime, baseUptime, baseRealtime);
if (mTrackingReportedValues) {
mUnpluggedReportedTotalTime = mCurrentReportedTotalTime;
mUnpluggedReportedCount = mCurrentReportedCount;
}
mTimeBaseRunning = true;
}
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
mTimeBaseRunning = 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 + (mTimeBaseRunning && mTrackingReportedValues
? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0);
}
protected int computeCurrentCountLocked() {
return mCount + (mTimeBaseRunning && mTrackingReportedValues
? mCurrentReportedCount - mUnpluggedReportedCount : 0);
}
public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
super.writeToParcel(out, elapsedRealtimeUs);
out.writeInt(mCurrentReportedCount);
out.writeInt(mUnpluggedReportedCount);
out.writeLong(mCurrentReportedTotalTime);
out.writeLong(mUnpluggedReportedTotalTime);
out.writeInt(mTrackingReportedValues ? 1 : 0);
}
boolean reset(boolean detachIfReset) {
super.reset(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;
}
}
/**
* A timer that increments in batches. It does not run for durations, but just jumps
* for a pre-determined amount.
*/
public static final class BatchTimer extends Timer {
final Uid mUid;
/**
* The last time at which we updated the timer. This is in elapsed realtime microseconds.
*/
long mLastAddedTime;
/**
* The last duration that we added to the timer. This is in microseconds.
*/
long mLastAddedDuration;
/**
* Whether we are currently in a discharge cycle.
*/
boolean mInDischarge;
BatchTimer(Uid uid, int type, TimeBase timeBase, Parcel in) {
super(type, timeBase, in);
mUid = uid;
mLastAddedTime = in.readLong();
mLastAddedDuration = in.readLong();
mInDischarge = timeBase.isRunning();
}
BatchTimer(Uid uid, int type, TimeBase timeBase) {
super(type, timeBase);
mUid = uid;
mInDischarge = timeBase.isRunning();
}
@Override
public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
super.writeToParcel(out, elapsedRealtimeUs);
out.writeLong(mLastAddedTime);
out.writeLong(mLastAddedDuration);
}
@Override
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
recomputeLastDuration(SystemClock.elapsedRealtime() * 1000, false);
mInDischarge = false;
super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
}
@Override
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
recomputeLastDuration(elapsedRealtime, false);
mInDischarge = true;
// If we are still within the last added duration, then re-added whatever remains.
if (mLastAddedTime == elapsedRealtime) {
mTotalTime += mLastAddedDuration;
}
super.onTimeStarted(elapsedRealtime, baseUptime, baseRealtime);
}
@Override
public void logState(Printer pw, String prefix) {
super.logState(pw, prefix);
pw.println(prefix + "mLastAddedTime=" + mLastAddedTime
+ " mLastAddedDuration=" + mLastAddedDuration);
}
private long computeOverage(long curTime) {
if (mLastAddedTime > 0) {
return mLastTime + mLastAddedDuration - curTime;
}
return 0;
}
private void recomputeLastDuration(long curTime, boolean abort) {
final long overage = computeOverage(curTime);
if (overage > 0) {
// Aborting before the duration ran out -- roll back the remaining
// duration. Only do this if currently discharging; otherwise we didn't
// actually add the time.
if (mInDischarge) {
mTotalTime -= overage;
}
if (abort) {
mLastAddedTime = 0;
} else {
mLastAddedTime = curTime;
mLastAddedDuration -= overage;
}
}
}
public void addDuration(BatteryStatsImpl stats, long durationMillis) {
final long now = SystemClock.elapsedRealtime() * 1000;
recomputeLastDuration(now, true);
mLastAddedTime = now;
mLastAddedDuration = durationMillis * 1000;
if (mInDischarge) {
mTotalTime += mLastAddedDuration;
mCount++;
}
}
public void abortLastDuration(BatteryStatsImpl stats) {
final long now = SystemClock.elapsedRealtime() * 1000;
recomputeLastDuration(now, true);
}
@Override
protected int computeCurrentCountLocked() {
return mCount;
}
@Override
protected long computeRunTimeLocked(long curBatteryRealtime) {
final long overage = computeOverage(SystemClock.elapsedRealtime() * 1000);
if (overage > 0) {
return mTotalTime = overage;
}
return mTotalTime;
}
@Override
boolean reset(boolean detachIfReset) {
final long now = SystemClock.elapsedRealtime() * 1000;
recomputeLastDuration(now, true);
boolean stillActive = mLastAddedTime == now;
super.reset(!stillActive && detachIfReset);
return !stillActive;
}
}
/**
* State for keeping track of timing information.
*/
public static final class StopwatchTimer extends Timer {
final Uid mUid;
final ArrayList 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 timerPool,
TimeBase timeBase, Parcel in) {
super(type, timeBase, in);
mUid = uid;
mTimerPool = timerPool;
mUpdateTime = in.readLong();
}
StopwatchTimer(Uid uid, int type, ArrayList timerPool,
TimeBase timeBase) {
super(type, timeBase);
mUid = uid;
mTimerPool = timerPool;
}
void setTimeout(long timeout) {
mTimeout = timeout;
}
public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
super.writeToParcel(out, elapsedRealtimeUs);
out.writeLong(mUpdateTime);
}
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
if (mNesting > 0) {
if (DEBUG && mType < 0) {
Log.v(TAG, "old mUpdateTime=" + mUpdateTime);
}
super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
mUpdateTime = baseRealtime;
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(long elapsedRealtimeMs) {
if (mNesting++ == 0) {
final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
mUpdateTime = batteryRealtime;
if (mTimerPool != null) {
// Accumulate time to all currently active timers before adding
// this new one to the pool.
refreshTimersLocked(batteryRealtime, mTimerPool, null);
// 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;
}
long checkpointRunningLocked(long elapsedRealtimeMs) {
if (mNesting > 0) {
// We are running...
final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
if (mTimerPool != null) {
return refreshTimersLocked(batteryRealtime, mTimerPool, this);
}
final long heldTime = batteryRealtime - mUpdateTime;
mUpdateTime = batteryRealtime;
mTotalTime += heldTime;
return heldTime;
}
return 0;
}
void stopRunningLocked(long elapsedRealtimeMs) {
// Ignore attempt to stop a timer that isn't running
if (mNesting == 0) {
return;
}
if (--mNesting == 0) {
final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
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(batteryRealtime, mTimerPool, null);
// Remove this timer from the active pool
mTimerPool.remove(this);
} else {
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--;
}
}
}
void stopAllRunningLocked(long elapsedRealtimeMs) {
if (mNesting > 0) {
mNesting = 1;
stopRunningLocked(elapsedRealtimeMs);
}
}
// 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 long refreshTimersLocked(long batteryRealtime,
final ArrayList pool, StopwatchTimer self) {
long selfTime = 0;
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) {
final long myTime = heldTime / N;
if (t == self) {
selfTime = myTime;
}
t.mTotalTime += myTime;
}
t.mUpdateTime = batteryRealtime;
}
return selfTime;
}
@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(boolean detachIfReset) {
boolean canDetach = mNesting <= 0;
super.reset(canDetach && detachIfReset);
if (mNesting > 0) {
mUpdateTime = mTimeBase.getRealtime(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;
}
}
public abstract class OverflowArrayMap {
private static final String OVERFLOW_NAME = "*overflow*";
final ArrayMap mMap = new ArrayMap<>();
T mCurOverflow;
ArrayMap mActiveOverflow;
public OverflowArrayMap() {
}
public ArrayMap getMap() {
return mMap;
}
public void clear() {
mMap.clear();
mCurOverflow = null;
mActiveOverflow = null;
}
public void add(String name, T obj) {
mMap.put(name, obj);
if (OVERFLOW_NAME.equals(name)) {
mCurOverflow = obj;
}
}
public void cleanup() {
if (mActiveOverflow != null) {
if (mActiveOverflow.size() == 0) {
mActiveOverflow = null;
}
}
if (mActiveOverflow == null) {
// There is no currently active overflow, so we should no longer have
// an overflow entry.
if (mMap.containsKey(OVERFLOW_NAME)) {
Slog.wtf(TAG, "Cleaning up with no active overflow, but have overflow entry "
+ mMap.get(OVERFLOW_NAME));
mMap.remove(OVERFLOW_NAME);
}
mCurOverflow = null;
} else {
// There is currently active overflow, so we should still have an overflow entry.
if (mCurOverflow == null || !mMap.containsKey(OVERFLOW_NAME)) {
Slog.wtf(TAG, "Cleaning up with active overflow, but no overflow entry: cur="
+ mCurOverflow + " map=" + mMap.get(OVERFLOW_NAME));
}
}
}
public T startObject(String name) {
T obj = mMap.get(name);
if (obj != null) {
return obj;
}
// No object exists for the given name, but do we currently have it
// running as part of the overflow?
if (mActiveOverflow != null) {
MutableInt over = mActiveOverflow.get(name);
if (over != null) {
// We are already actively counting this name in the overflow object.
obj = mCurOverflow;
if (obj == null) {
// Shouldn't be here, but we'll try to recover.
Slog.wtf(TAG, "Have active overflow " + name + " but null overflow");
obj = mCurOverflow = instantiateObject();
mMap.put(OVERFLOW_NAME, obj);
}
over.value++;
return obj;
}
}
// No object exists for given name nor in the overflow; we need to make
// a new one.
final int N = mMap.size();
if (N >= MAX_WAKELOCKS_PER_UID) {
// Went over the limit on number of objects to track; this one goes
// in to the overflow.
obj = mCurOverflow;
if (obj == null) {
// Need to start overflow now...
obj = mCurOverflow = instantiateObject();
mMap.put(OVERFLOW_NAME, obj);
}
if (mActiveOverflow == null) {
mActiveOverflow = new ArrayMap<>();
}
mActiveOverflow.put(name, new MutableInt(1));
return obj;
}
// Normal case where we just need to make a new object.
obj = instantiateObject();
mMap.put(name, obj);
return obj;
}
public T stopObject(String name) {
T obj = mMap.get(name);
if (obj != null) {
return obj;
}
// No object exists for the given name, but do we currently have it
// running as part of the overflow?
if (mActiveOverflow != null) {
MutableInt over = mActiveOverflow.get(name);
if (over != null) {
// We are already actively counting this name in the overflow object.
obj = mCurOverflow;
if (obj != null) {
over.value--;
if (over.value <= 0) {
mActiveOverflow.remove(name);
}
return obj;
}
}
}
// Huh, they are stopping an active operation but we can't find one!
// That's not good.
Slog.wtf(TAG, "Unable to find object for " + name + " mapsize="
+ mMap.size() + " activeoverflow=" + mActiveOverflow
+ " curoverflow=" + mCurOverflow);
return null;
}
public abstract T instantiateObject();
}
/*
* Get the wakeup reason counter, and create a new one if one
* doesn't already exist.
*/
public SamplingTimer getWakeupReasonTimerLocked(String name) {
SamplingTimer timer = mWakeupReasonStats.get(name);
if (timer == null) {
timer = new SamplingTimer(mOnBatteryTimeBase, true);
mWakeupReasonStats.put(name, timer);
}
return timer;
}
private final Map readKernelWakelockStats() {
FileInputStream is;
byte[] buffer = new byte[8192];
int len;
boolean wakeup_sources = false;
try {
try {
is = new FileInputStream("/proc/wakelocks");
} catch (java.io.FileNotFoundException e) {
try {
is = new FileInputStream("/d/wakeup_sources");
wakeup_sources = true;
} catch (java.io.FileNotFoundException e2) {
return null;
}
}
len = is.read(buffer);
is.close();
} catch (java.io.IOException e) {
return null;
}
if (len > 0) {
int i;
for (i=0; i parseProcWakelocks(
byte[] wlBuffer, int len, boolean wakeup_sources) {
String name;
int count;
long totalTime;
int startIndex;
int 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 m = mProcWakelockFileStats;
sKernelWakelockUpdateVersion++;
while (endIndex < len) {
for (endIndex=startIndex;
endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
endIndex++);
endIndex++; // endIndex is an exclusive upper bound.
// Don't go over the end of the buffer, Process.parseProcLine might
// write to wlBuffer[endIndex]
if (endIndex >= (len - 1) ) {
return m;
}
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,
wakeup_sources ? WAKEUP_SOURCES_FORMAT :
PROC_WAKELOCKS_FORMAT,
nameStringArray, wlData, null);
name = nameStringArray[0];
count = (int) wlData[1];
if (wakeup_sources) {
// convert milliseconds to microseconds
totalTime = wlData[2] * 1000;
} else {
// 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 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(mOnBatteryScreenOffTimeBase, true /* track reported values */);
mKernelWakelockStats.put(name, kwlt);
}
return kwlt;
}
private int getCurrentBluetoothPingCount() {
if (mBtHeadset != null) {
List deviceList = mBtHeadset.getConnectedDevices();
if (deviceList.size() > 0) {
return mBtHeadset.getBatteryUsageHint(deviceList.get(0));
}
}
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;
}
private int writeHistoryTag(HistoryTag tag) {
Integer idxObj = mHistoryTagPool.get(tag);
int idx;
if (idxObj != null) {
idx = idxObj;
} else {
idx = mNextHistoryTagIdx;
HistoryTag key = new HistoryTag();
key.setTo(tag);
tag.poolIdx = idx;
mHistoryTagPool.put(key, idx);
mNextHistoryTagIdx++;
mNumHistoryTagChars += key.string.length() + 1;
}
return idx;
}
private void readHistoryTag(int index, HistoryTag tag) {
tag.string = mReadHistoryStrings[index];
tag.uid = mReadHistoryUids[index];
tag.poolIdx = index;
}
// Part of initial delta int that specifies the time delta.
static final int DELTA_TIME_MASK = 0x7ffff;
static final int DELTA_TIME_LONG = 0x7ffff; // The delta is a following long
static final int DELTA_TIME_INT = 0x7fffe; // The delta is a following int
static final int DELTA_TIME_ABS = 0x7fffd; // Following is an entire abs update.
// Flag in delta int: a new battery level int follows.
static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000;
// Flag in delta int: a new full state and battery status int follows.
static final int DELTA_STATE_FLAG = 0x00100000;
// Flag in delta int: a new full state2 int follows.
static final int DELTA_STATE2_FLAG = 0x00200000;
// Flag in delta int: contains a wakelock or wakeReason tag.
static final int DELTA_WAKELOCK_FLAG = 0x00400000;
// Flag in delta int: contains an event description.
static final int DELTA_EVENT_FLAG = 0x00800000;
// These upper bits are the frequently changing state bits.
static final int DELTA_STATE_MASK = 0xff000000;
// These are the pieces of battery state that are packed in to the upper bits of
// the state int that have been packed in to the first delta int. They must fit
// in DELTA_STATE_MASK.
static final int STATE_BATTERY_STATUS_MASK = 0x00000007;
static final int STATE_BATTERY_STATUS_SHIFT = 29;
static final int STATE_BATTERY_HEALTH_MASK = 0x00000007;
static final int STATE_BATTERY_HEALTH_SHIFT = 26;
static final int STATE_BATTERY_PLUG_MASK = 0x00000003;
static final int STATE_BATTERY_PLUG_SHIFT = 24;
public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
dest.writeInt(DELTA_TIME_ABS);
cur.writeToParcel(dest, 0);
return;
}
final long deltaTime = cur.time - last.time;
final int lastBatteryLevelInt = buildBatteryLevelInt(last);
final int lastStateInt = buildStateInt(last);
int deltaTimeToken;
if (deltaTime < 0 || deltaTime > Integer.MAX_VALUE) {
deltaTimeToken = DELTA_TIME_LONG;
} else if (deltaTime >= DELTA_TIME_ABS) {
deltaTimeToken = DELTA_TIME_INT;
} else {
deltaTimeToken = (int)deltaTime;
}
int firstToken = deltaTimeToken | (cur.states&DELTA_STATE_MASK);
final int batteryLevelInt = buildBatteryLevelInt(cur);
final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt;
if (batteryLevelIntChanged) {
firstToken |= DELTA_BATTERY_LEVEL_FLAG;
}
final int stateInt = buildStateInt(cur);
final boolean stateIntChanged = stateInt != lastStateInt;
if (stateIntChanged) {
firstToken |= DELTA_STATE_FLAG;
}
final boolean state2IntChanged = cur.states2 != last.states2;
if (state2IntChanged) {
firstToken |= DELTA_STATE2_FLAG;
}
if (cur.wakelockTag != null || cur.wakeReasonTag != null) {
firstToken |= DELTA_WAKELOCK_FLAG;
}
if (cur.eventCode != HistoryItem.EVENT_NONE) {
firstToken |= DELTA_EVENT_FLAG;
}
dest.writeInt(firstToken);
if (DEBUG) Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken)
+ " deltaTime=" + deltaTime);
if (deltaTimeToken >= DELTA_TIME_INT) {
if (deltaTimeToken == DELTA_TIME_INT) {
if (DEBUG) Slog.i(TAG, "WRITE DELTA: int deltaTime=" + (int)deltaTime);
dest.writeInt((int)deltaTime);
} else {
if (DEBUG) Slog.i(TAG, "WRITE DELTA: long deltaTime=" + deltaTime);
dest.writeLong(deltaTime);
}
}
if (batteryLevelIntChanged) {
dest.writeInt(batteryLevelInt);
if (DEBUG) Slog.i(TAG, "WRITE DELTA: batteryToken=0x"
+ Integer.toHexString(batteryLevelInt)
+ " batteryLevel=" + cur.batteryLevel
+ " batteryTemp=" + cur.batteryTemperature
+ " batteryVolt=" + (int)cur.batteryVoltage);
}
if (stateIntChanged) {
dest.writeInt(stateInt);
if (DEBUG) Slog.i(TAG, "WRITE DELTA: stateToken=0x"
+ Integer.toHexString(stateInt)
+ " batteryStatus=" + cur.batteryStatus
+ " batteryHealth=" + cur.batteryHealth
+ " batteryPlugType=" + cur.batteryPlugType
+ " states=0x" + Integer.toHexString(cur.states));
}
if (state2IntChanged) {
dest.writeInt(cur.states2);
if (DEBUG) Slog.i(TAG, "WRITE DELTA: states2=0x"
+ Integer.toHexString(cur.states2));
}
if (cur.wakelockTag != null || cur.wakeReasonTag != null) {
int wakeLockIndex;
int wakeReasonIndex;
if (cur.wakelockTag != null) {
wakeLockIndex = writeHistoryTag(cur.wakelockTag);
if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
+ " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
} else {
wakeLockIndex = 0xffff;
}
if (cur.wakeReasonTag != null) {
wakeReasonIndex = writeHistoryTag(cur.wakeReasonTag);
if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx
+ " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string);
} else {
wakeReasonIndex = 0xffff;
}
dest.writeInt((wakeReasonIndex<<16) | wakeLockIndex);
}
if (cur.eventCode != HistoryItem.EVENT_NONE) {
int index = writeHistoryTag(cur.eventTag);
int codeAndIndex = (cur.eventCode&0xffff) | (index<<16);
dest.writeInt(codeAndIndex);
if (DEBUG) Slog.i(TAG, "WRITE DELTA: event=" + cur.eventCode + " tag=#"
+ cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
+ cur.eventTag.string);
}
}
private int buildBatteryLevelInt(HistoryItem h) {
return ((((int)h.batteryLevel)<<25)&0xfe000000)
| ((((int)h.batteryTemperature)<<14)&0x01ffc000)
| (((int)h.batteryVoltage)&0x00003fff);
}
private int buildStateInt(HistoryItem h) {
int plugType = 0;
if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_AC) != 0) {
plugType = 1;
} else if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_USB) != 0) {
plugType = 2;
} else if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0) {
plugType = 3;
}
return ((h.batteryStatus&STATE_BATTERY_STATUS_MASK)<>16)&0xffff;
if (wakeLockIndex != 0xffff) {
cur.wakelockTag = cur.localWakelockTag;
readHistoryTag(wakeLockIndex, cur.wakelockTag);
if (DEBUG) Slog.i(TAG, "READ DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
+ " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
} else {
cur.wakelockTag = null;
}
if (wakeReasonIndex != 0xffff) {
cur.wakeReasonTag = cur.localWakeReasonTag;
readHistoryTag(wakeReasonIndex, cur.wakeReasonTag);
if (DEBUG) Slog.i(TAG, "READ DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx
+ " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string);
} else {
cur.wakeReasonTag = null;
}
cur.numReadInts += 1;
} else {
cur.wakelockTag = null;
cur.wakeReasonTag = null;
}
if ((firstToken&DELTA_EVENT_FLAG) != 0) {
cur.eventTag = cur.localEventTag;
final int codeAndIndex = src.readInt();
cur.eventCode = (codeAndIndex&0xffff);
final int index = ((codeAndIndex>>16)&0xffff);
readHistoryTag(index, cur.eventTag);
cur.numReadInts += 1;
if (DEBUG) Slog.i(TAG, "READ DELTA: event=" + cur.eventCode + " tag=#"
+ cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
+ cur.eventTag.string);
} else {
cur.eventCode = HistoryItem.EVENT_NONE;
}
}
@Override
public void commitCurrentHistoryBatchLocked() {
mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
}
void addHistoryBufferLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
if (!mHaveBatteryLevel || !mRecordingHistory) {
return;
}
final long timeDiff = (mHistoryBaseTime+elapsedRealtimeMs) - mHistoryLastWritten.time;
final int diffStates = mHistoryLastWritten.states^cur.states;
final int diffStates2 = mHistoryLastWritten.states2^cur.states2;
final int lastDiffStates = mHistoryLastWritten.states^mHistoryLastLastWritten.states;
final int lastDiffStates2 = mHistoryLastWritten.states2^mHistoryLastLastWritten.states2;
if (DEBUG) Slog.i(TAG, "ADD: tdelta=" + timeDiff + " diff="
+ Integer.toHexString(diffStates) + " lastDiff="
+ Integer.toHexString(lastDiffStates) + " diff2="
+ Integer.toHexString(diffStates2) + " lastDiff2="
+ Integer.toHexString(lastDiffStates2));
if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
&& timeDiff < 1000 && (diffStates&lastDiffStates) == 0
&& (diffStates2&lastDiffStates2) == 0
&& (mHistoryLastWritten.wakelockTag == null || cur.wakelockTag == null)
&& (mHistoryLastWritten.wakeReasonTag == null || cur.wakeReasonTag == null)
&& (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE
|| cur.eventCode == HistoryItem.EVENT_NONE)
&& mHistoryLastWritten.batteryLevel == cur.batteryLevel
&& mHistoryLastWritten.batteryStatus == cur.batteryStatus
&& mHistoryLastWritten.batteryHealth == cur.batteryHealth
&& mHistoryLastWritten.batteryPlugType == cur.batteryPlugType
&& mHistoryLastWritten.batteryTemperature == cur.batteryTemperature
&& mHistoryLastWritten.batteryVoltage == cur.batteryVoltage) {
// We can merge this new change in with the last one. Merging is
// allowed as long as only the states have changed, and within those states
// as long as no bit has changed both between now and the last entry, as
// well as the last entry and the one before it (so we capture any toggles).
if (DEBUG) Slog.i(TAG, "ADD: rewinding back to " + mHistoryBufferLastPos);
mHistoryBuffer.setDataSize(mHistoryBufferLastPos);
mHistoryBuffer.setDataPosition(mHistoryBufferLastPos);
mHistoryBufferLastPos = -1;
elapsedRealtimeMs = mHistoryLastWritten.time - mHistoryBaseTime;
// If the last written history had a wakelock tag, we need to retain it.
// Note that the condition above made sure that we aren't in a case where
// both it and the current history item have a wakelock tag.
if (mHistoryLastWritten.wakelockTag != null) {
cur.wakelockTag = cur.localWakelockTag;
cur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag);
}
// If the last written history had a wake reason tag, we need to retain it.
// Note that the condition above made sure that we aren't in a case where
// both it and the current history item have a wakelock tag.
if (mHistoryLastWritten.wakeReasonTag != null) {
cur.wakeReasonTag = cur.localWakeReasonTag;
cur.wakeReasonTag.setTo(mHistoryLastWritten.wakeReasonTag);
}
// If the last written history had an event, we need to retain it.
// Note that the condition above made sure that we aren't in a case where
// both it and the current history item have an event.
if (mHistoryLastWritten.eventCode != HistoryItem.EVENT_NONE) {
cur.eventCode = mHistoryLastWritten.eventCode;
cur.eventTag = cur.localEventTag;
cur.eventTag.setTo(mHistoryLastWritten.eventTag);
}
mHistoryLastWritten.setTo(mHistoryLastLastWritten);
}
final int dataSize = mHistoryBuffer.dataSize();
if (dataSize >= MAX_HISTORY_BUFFER) {
if (!mHistoryOverflow) {
mHistoryOverflow = true;
addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_UPDATE, cur);
addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_OVERFLOW, cur);
return;
}
// 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 (mHistoryLastWritten.batteryLevel == cur.batteryLevel &&
(dataSize >= MAX_MAX_HISTORY_BUFFER
|| ((mHistoryLastWritten.states^cur.states)
& HistoryItem.MOST_INTERESTING_STATES) == 0
|| ((mHistoryLastWritten.states2^cur.states2)
& HistoryItem.MOST_INTERESTING_STATES2) == 0)) {
return;
}
addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_UPDATE, cur);
return;
}
if (dataSize == 0) {
// The history is currently empty; we need it to start with a time stamp.
cur.currentTime = System.currentTimeMillis();
mLastRecordedClockTime = cur.currentTime;
mLastRecordedClockRealtime = elapsedRealtimeMs;
addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_RESET, cur);
}
addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_UPDATE, cur);
}
private void addHistoryBufferLocked(long elapsedRealtimeMs, long uptimeMs, byte cmd,
HistoryItem cur) {
if (mIteratingHistory) {
throw new IllegalStateException("Can't do this while iterating history!");
}
mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
mHistoryLastLastWritten.setTo(mHistoryLastWritten);
mHistoryLastWritten.setTo(mHistoryBaseTime + elapsedRealtimeMs, cmd, cur);
writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
mLastHistoryElapsedRealtime = elapsedRealtimeMs;
cur.wakelockTag = null;
cur.wakeReasonTag = null;
cur.eventCode = HistoryItem.EVENT_NONE;
cur.eventTag = null;
if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
+ " now " + mHistoryBuffer.dataPosition()
+ " size is now " + mHistoryBuffer.dataSize());
}
int mChangedStates = 0;
int mChangedStates2 = 0;
void addHistoryRecordLocked(long elapsedRealtimeMs, long uptimeMs) {
if (mTrackRunningHistoryElapsedRealtime != 0) {
final long diffElapsed = elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtime;
final long diffUptime = uptimeMs - mTrackRunningHistoryUptime;
if (diffUptime < (diffElapsed-20)) {
final long wakeElapsedTime = elapsedRealtimeMs - (diffElapsed - diffUptime);
mHistoryAddTmp.setTo(mHistoryLastWritten);
mHistoryAddTmp.wakelockTag = null;
mHistoryAddTmp.wakeReasonTag = null;
mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
addHistoryRecordInnerLocked(wakeElapsedTime, uptimeMs, mHistoryAddTmp);
}
}
mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
mTrackRunningHistoryElapsedRealtime = elapsedRealtimeMs;
mTrackRunningHistoryUptime = uptimeMs;
addHistoryRecordInnerLocked(elapsedRealtimeMs, uptimeMs, mHistoryCur);
}
void addHistoryRecordInnerLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, cur);
if (!USE_OLD_HISTORY) {
return;
}
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+elapsedRealtimeMs) < (mHistoryEnd.time+1000)
&& ((mHistoryEnd.states^cur.states)&mChangedStates) == 0
&& ((mHistoryEnd.states2^cur.states2)&mChangedStates2) == 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
&& (mHistoryBaseTime+elapsedRealtimeMs) < (mHistoryEnd.time+500)
&& mHistoryLastEnd.sameNonEvent(cur)) {
mHistoryLastEnd.next = null;
mHistoryEnd.next = mHistoryCache;
mHistoryCache = mHistoryEnd;
mHistoryEnd = mHistoryLastEnd;
mHistoryLastEnd = null;
} else {
mChangedStates |= mHistoryEnd.states^cur.states;
mChangedStates2 |= mHistoryEnd.states^cur.states2;
mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, cur);
}
return;
}
mChangedStates = 0;
mChangedStates2 = 0;
if (mNumHistoryItems == MAX_HISTORY_ITEMS
|| mNumHistoryItems == MAX_MAX_HISTORY_ITEMS) {
addHistoryRecordLocked(elapsedRealtimeMs, 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
== cur.batteryLevel &&
(mNumHistoryItems >= MAX_MAX_HISTORY_ITEMS
|| ((mHistoryEnd.states^cur.states)
& HistoryItem.MOST_INTERESTING_STATES) == 0)) {
return;
}
}
addHistoryRecordLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE);
}
void addHistoryEventLocked(long elapsedRealtimeMs, long uptimeMs, int code,
String name, int uid) {
mHistoryCur.eventCode = code;
mHistoryCur.eventTag = mHistoryCur.localEventTag;
mHistoryCur.eventTag.string = name;
mHistoryCur.eventTag.uid = uid;
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
}
void addHistoryRecordLocked(long elapsedRealtimeMs, long uptimeMs, byte cmd, HistoryItem cur) {
HistoryItem rec = mHistoryCache;
if (rec != null) {
mHistoryCache = rec.next;
} else {
rec = new HistoryItem();
}
rec.setTo(mHistoryBaseTime + elapsedRealtimeMs, cmd, cur);
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 (DEBUG_HISTORY) Slog.i(TAG, "********** CLEARING HISTORY!");
if (USE_OLD_HISTORY) {
if (mHistory != null) {
mHistoryEnd.next = mHistoryCache;
mHistoryCache = mHistory;
mHistory = mHistoryLastEnd = mHistoryEnd = null;
}
mNumHistoryItems = 0;
}
mHistoryBaseTime = 0;
mLastHistoryElapsedRealtime = 0;
mTrackRunningHistoryElapsedRealtime = 0;
mTrackRunningHistoryUptime = 0;
mHistoryBuffer.setDataSize(0);
mHistoryBuffer.setDataPosition(0);
mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER / 2);
mHistoryLastLastWritten.clear();
mHistoryLastWritten.clear();
mHistoryTagPool.clear();
mNextHistoryTagIdx = 0;
mNumHistoryTagChars = 0;
mHistoryBufferLastPos = -1;
mHistoryOverflow = false;
mLastRecordedClockTime = 0;
mLastRecordedClockRealtime = 0;
}
public void updateTimeBasesLocked(boolean unplugged, boolean screenOff, long uptime,
long realtime) {
if (mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime)) {
if (unplugged) {
// Track bt headset ping count
mBluetoothPingStart = getCurrentBluetoothPingCount();
mBluetoothPingCount = 0;
} else {
// Track bt headset ping count
mBluetoothPingCount = getBluetoothPingCount();
mBluetoothPingStart = -1;
}
}
boolean unpluggedScreenOff = unplugged && screenOff;
if (unpluggedScreenOff != mOnBatteryScreenOffTimeBase.isRunning()) {
updateKernelWakelocksLocked();
requestWakelockCpuUpdate();
if (!unpluggedScreenOff) {
// We are switching to no longer tracking wake locks, but we want
// the next CPU update we receive to take them in to account.
mDistributeWakelockCpu = true;
}
mOnBatteryScreenOffTimeBase.setRunning(unpluggedScreenOff, uptime, realtime);
}
}
public void addIsolatedUidLocked(int isolatedUid, int appUid) {
mIsolatedUids.put(isolatedUid, appUid);
}
public void removeIsolatedUidLocked(int isolatedUid, int appUid) {
int curUid = mIsolatedUids.get(isolatedUid, -1);
if (curUid == appUid) {
mIsolatedUids.delete(isolatedUid);
}
}
public int mapUid(int uid) {
int isolated = mIsolatedUids.get(uid, -1);
return isolated > 0 ? isolated : uid;
}
public void noteEventLocked(int code, String name, int uid) {
uid = mapUid(uid);
if (!mActiveEvents.updateState(code, name, uid, 0)) {
return;
}
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, code, name, uid);
}
public void noteCurrentTimeChangedLocked() {
final long currentTime = System.currentTimeMillis();
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (isStartClockTimeValid()) {
// Has the time changed sufficiently that it is really worth recording?
if (mLastRecordedClockTime != 0) {
long expectedClockTime = mLastRecordedClockTime
+ (elapsedRealtime - mLastRecordedClockRealtime);
if (currentTime >= (expectedClockTime-500)
&& currentTime <= (expectedClockTime+500)) {
// Not sufficiently changed, skip!
return;
}
}
}
recordCurrentTimeChangeLocked(currentTime, elapsedRealtime, uptime);
if (isStartClockTimeValid()) {
mStartClockTime = currentTime;
}
}
public void noteProcessStartLocked(String name, int uid) {
uid = mapUid(uid);
if (isOnBattery()) {
Uid u = getUidStatsLocked(uid);
u.getProcessStatsLocked(name).incStartsLocked();
}
if (!mActiveEvents.updateState(HistoryItem.EVENT_PROC_START, name, uid, 0)) {
return;
}
if (!mRecordAllHistory) {
return;
}
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_START, name, uid);
}
public void noteProcessStateLocked(String name, int uid, int state) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
getUidStatsLocked(uid).updateProcessStateLocked(name, state, elapsedRealtime);
}
public void noteProcessFinishLocked(String name, int uid) {
uid = mapUid(uid);
if (!mActiveEvents.updateState(HistoryItem.EVENT_PROC_FINISH, name, uid, 0)) {
return;
}
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
getUidStatsLocked(uid).updateProcessStateLocked(name, Uid.PROCESS_STATE_NONE,
elapsedRealtime);
if (!mRecordAllHistory) {
return;
}
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_FINISH, name, uid);
}
public void noteSyncStartLocked(String name, int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
getUidStatsLocked(uid).noteStartSyncLocked(name, elapsedRealtime);
if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_START, name, uid, 0)) {
return;
}
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_SYNC_START, name, uid);
}
public void noteSyncFinishLocked(String name, int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
getUidStatsLocked(uid).noteStopSyncLocked(name, elapsedRealtime);
if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_FINISH, name, uid, 0)) {
return;
}
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_SYNC_FINISH, name, uid);
}
public void noteJobStartLocked(String name, int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
getUidStatsLocked(uid).noteStartJobLocked(name, elapsedRealtime);
if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_START, name, uid, 0)) {
return;
}
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_JOB_START, name, uid);
}
public void noteJobFinishLocked(String name, int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
getUidStatsLocked(uid).noteStopJobLocked(name, elapsedRealtime);
if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_FINISH, name, uid, 0)) {
return;
}
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_JOB_FINISH, name, uid);
}
private void requestWakelockCpuUpdate() {
if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
}
}
public void setRecordAllHistoryLocked(boolean enabled) {
mRecordAllHistory = enabled;
if (!enabled) {
// Clear out any existing state.
mActiveEvents.removeEvents(HistoryItem.EVENT_WAKE_LOCK);
// Record the currently running processes as stopping, now that we are no
// longer tracking them.
HashMap active = mActiveEvents.getStateForEvent(
HistoryItem.EVENT_PROC);
if (active != null) {
long mSecRealtime = SystemClock.elapsedRealtime();
final long mSecUptime = SystemClock.uptimeMillis();
for (HashMap.Entry ent : active.entrySet()) {
SparseIntArray uids = ent.getValue();
for (int j=0; j active = mActiveEvents.getStateForEvent(
HistoryItem.EVENT_PROC);
if (active != null) {
long mSecRealtime = SystemClock.elapsedRealtime();
final long mSecUptime = SystemClock.uptimeMillis();
for (HashMap.Entry ent : active.entrySet()) {
SparseIntArray uids = ent.getValue();
for (int j=0; j= 0) {
//if (uid == 0) {
// Slog.wtf(TAG, "Acquiring wake lock from root: " + name);
//}
requestWakelockCpuUpdate();
getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type, elapsedRealtime);
}
}
public void noteStopWakeLocked(int uid, int pid, String name, String historyName, int type,
long elapsedRealtime, long uptime) {
uid = mapUid(uid);
if (type == WAKE_TYPE_PARTIAL) {
mWakeLockNesting--;
if (mRecordAllHistory) {
if (historyName == null) {
historyName = name;
}
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName,
uid, 0)) {
addHistoryEventLocked(elapsedRealtime, uptime,
HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, uid);
}
}
if (mWakeLockNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
+ Integer.toHexString(mHistoryCur.states));
mInitialAcquireWakeName = null;
mInitialAcquireWakeUid = -1;
addHistoryRecordLocked(elapsedRealtime, uptime);
}
}
if (uid >= 0) {
requestWakelockCpuUpdate();
getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type, elapsedRealtime);
}
}
public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name,
String historyName, int type, boolean unimportantForLogging) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
final int N = ws.size();
for (int i=0; i 0 ? (realtime - p.mWakeStartMs) : 0);
}
}
return 0;
}
public void reportExcessiveWakeLocked(int uid, String proc, long overTime, long usedTime) {
uid = mapUid(uid);
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 = mapUid(uid);
Uid u = mUidStats.get(uid);
if (u != null) {
u.reportExcessiveCpuLocked(proc, overTime, usedTime);
}
}
int mSensorNesting;
public void noteStartSensorLocked(int uid, int sensor) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (mSensorNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
}
mSensorNesting++;
getUidStatsLocked(uid).noteStartSensor(sensor, elapsedRealtime);
}
public void noteStopSensorLocked(int uid, int sensor) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
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(elapsedRealtime, uptime);
}
getUidStatsLocked(uid).noteStopSensor(sensor, elapsedRealtime);
}
int mGpsNesting;
public void noteStartGpsLocked(int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (mGpsNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
}
mGpsNesting++;
getUidStatsLocked(uid).noteStartGps(elapsedRealtime);
}
public void noteStopGpsLocked(int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
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(elapsedRealtime, uptime);
}
getUidStatsLocked(uid).noteStopGps(elapsedRealtime);
}
public void noteScreenStateLocked(int state) {
if (mScreenState != state) {
final int oldState = mScreenState;
mScreenState = state;
if (DEBUG) Slog.v(TAG, "Screen state: oldState=" + Display.stateToString(oldState)
+ ", newState=" + Display.stateToString(state));
if (state != Display.STATE_UNKNOWN) {
int stepState = state-1;
if (stepState < 4) {
mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_SCREEN_STATE) ^ stepState;
mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_SCREEN_STATE) | stepState;
} else {
Slog.wtf(TAG, "Unexpected screen state: " + state);
}
}
if (state == Display.STATE_ON) {
// Screen turning on.
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mScreenOnTimer.startRunningLocked(elapsedRealtime);
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(elapsedRealtime);
}
updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), false,
SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
// Fake a wake lock, so we consider the device waked as long
// as the screen is on.
noteStartWakeLocked(-1, -1, "screen", null, WAKE_TYPE_PARTIAL, false,
elapsedRealtime, uptime);
// Update discharge amounts.
if (mOnBatteryInternal) {
updateDischargeScreenLevelsLocked(false, true);
}
} else if (oldState == Display.STATE_ON) {
// Screen turning off or dozing.
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mScreenOnTimer.stopRunningLocked(elapsedRealtime);
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
}
noteStopWakeLocked(-1, -1, "screen", "screen", WAKE_TYPE_PARTIAL,
elapsedRealtime, uptime);
updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true,
SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
// Update discharge amounts.
if (mOnBatteryInternal) {
updateDischargeScreenLevelsLocked(true, false);
}
}
}
}
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) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
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(elapsedRealtime, uptime);
if (mScreenState == Display.STATE_ON) {
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
}
mScreenBrightnessTimer[bin].startRunningLocked(elapsedRealtime);
}
mScreenBrightnessBin = bin;
}
}
public void noteUserActivityLocked(int uid, int event) {
if (mOnBatteryInternal) {
uid = mapUid(uid);
getUidStatsLocked(uid).noteUserActivityLocked(event);
}
}
public void noteInteractiveLocked(boolean interactive) {
if (mInteractive != interactive) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
mInteractive = interactive;
if (DEBUG) Slog.v(TAG, "Interactive: " + interactive);
if (interactive) {
mInteractiveTimer.startRunningLocked(elapsedRealtime);
} else {
mInteractiveTimer.stopRunningLocked(elapsedRealtime);
}
}
}
public void noteMobileRadioPowerState(int powerState, long timestampNs) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (mMobileRadioPowerState != powerState) {
long realElapsedRealtimeMs;
final boolean active =
powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
|| powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
if (active) {
mMobileRadioActiveStartTime = realElapsedRealtimeMs = elapsedRealtime;
mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
} else {
realElapsedRealtimeMs = timestampNs / (1000*1000);
long lastUpdateTimeMs = mMobileRadioActiveStartTime;
if (realElapsedRealtimeMs < lastUpdateTimeMs) {
Slog.wtf(TAG, "Data connection inactive timestamp " + realElapsedRealtimeMs
+ " is before start time " + lastUpdateTimeMs);
realElapsedRealtimeMs = elapsedRealtime;
} else if (realElapsedRealtimeMs < elapsedRealtime) {
mMobileRadioActiveAdjustedTime.addCountLocked(elapsedRealtime
- realElapsedRealtimeMs);
}
mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
}
if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mMobileRadioPowerState = powerState;
if (active) {
mMobileRadioActiveTimer.startRunningLocked(elapsedRealtime);
mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
} else {
mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs);
updateNetworkActivityLocked(NET_UPDATE_MOBILE, realElapsedRealtimeMs);
mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs);
}
}
}
public void noteLowPowerMode(boolean enabled) {
if (mLowPowerModeEnabled != enabled) {
int stepState = enabled ? STEP_LEVEL_MODE_POWER_SAVE : 0;
mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_POWER_SAVE) ^ stepState;
mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_POWER_SAVE) | stepState;
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mLowPowerModeEnabled = enabled;
if (enabled) {
mHistoryCur.states2 |= HistoryItem.STATE2_LOW_POWER_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Low power mode enabled to: "
+ Integer.toHexString(mHistoryCur.states2));
mLowPowerModeEnabledTimer.startRunningLocked(elapsedRealtime);
} else {
mHistoryCur.states2 &= ~HistoryItem.STATE2_LOW_POWER_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Low power mode disabled to: "
+ Integer.toHexString(mHistoryCur.states2));
mLowPowerModeEnabledTimer.stopRunningLocked(elapsedRealtime);
}
addHistoryRecordLocked(elapsedRealtime, uptime);
}
}
public void notePhoneOnLocked() {
if (!mPhoneOn) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mHistoryCur.states |= HistoryItem.STATE_PHONE_IN_CALL_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mPhoneOn = true;
mPhoneOnTimer.startRunningLocked(elapsedRealtime);
}
}
public void notePhoneOffLocked() {
if (mPhoneOn) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mHistoryCur.states &= ~HistoryItem.STATE_PHONE_IN_CALL_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mPhoneOn = false;
mPhoneOnTimer.stopRunningLocked(elapsedRealtime);
}
}
void stopAllPhoneSignalStrengthTimersLocked(int except) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
for (int i = 0; i < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
if (i == except) {
continue;
}
while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
mPhoneSignalStrengthsTimer[i].stopRunningLocked(elapsedRealtime);
}
}
}
private int fixPhoneServiceState(int state, int signalBin) {
if (mPhoneSimStateRaw == TelephonyManager.SIM_STATE_ABSENT) {
// In this case we will always be STATE_OUT_OF_SERVICE, so need
// to infer that we are scanning from other data.
if (state == ServiceState.STATE_OUT_OF_SERVICE
&& signalBin > SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
state = ServiceState.STATE_IN_SERVICE;
}
}
return state;
}
private void updateAllPhoneStateLocked(int state, int simState, int strengthBin) {
boolean scanning = false;
boolean newHistory = false;
mPhoneServiceStateRaw = state;
mPhoneSimStateRaw = simState;
mPhoneSignalStrengthBinRaw = strengthBin;
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (simState == TelephonyManager.SIM_STATE_ABSENT) {
// In this case we will always be STATE_OUT_OF_SERVICE, so need
// to infer that we are scanning from other data.
if (state == ServiceState.STATE_OUT_OF_SERVICE
&& strengthBin > SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
state = ServiceState.STATE_IN_SERVICE;
}
}
// If the phone is powered off, stop all timers.
if (state == ServiceState.STATE_POWER_OFF) {
strengthBin = -1;
// If we are in service, make sure the correct signal string timer is running.
} else if (state == ServiceState.STATE_IN_SERVICE) {
// Bin will be changed below.
// 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;
strengthBin = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
if (!mPhoneSignalScanningTimer.isRunningLocked()) {
mHistoryCur.states |= HistoryItem.STATE_PHONE_SCANNING_FLAG;
newHistory = true;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: "
+ Integer.toHexString(mHistoryCur.states));
mPhoneSignalScanningTimer.startRunningLocked(elapsedRealtime);
}
}
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));
newHistory = true;
mPhoneSignalScanningTimer.stopRunningLocked(elapsedRealtime);
}
}
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 " + state + " to: "
+ Integer.toHexString(mHistoryCur.states));
newHistory = true;
mPhoneServiceState = state;
}
if (mPhoneSignalStrengthBin != strengthBin) {
if (mPhoneSignalStrengthBin >= 0) {
mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(
elapsedRealtime);
}
if (strengthBin >= 0) {
if (!mPhoneSignalStrengthsTimer[strengthBin].isRunningLocked()) {
mPhoneSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtime);
}
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK)
| (strengthBin << HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + strengthBin + " to: "
+ Integer.toHexString(mHistoryCur.states));
newHistory = true;
} else {
stopAllPhoneSignalStrengthTimersLocked(-1);
}
mPhoneSignalStrengthBin = strengthBin;
}
if (newHistory) {
addHistoryRecordLocked(elapsedRealtime, uptime);
}
}
/**
* Telephony stack updates the phone state.
* @param state phone state from ServiceState.getState()
*/
public void notePhoneStateLocked(int state, int simState) {
updateAllPhoneStateLocked(state, simState, mPhoneSignalStrengthBinRaw);
}
public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
// Bin the strength.
int bin = signalStrength.getLevel();
updateAllPhoneStateLocked(mPhoneServiceStateRaw, mPhoneSimStateRaw, bin);
}
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;
case TelephonyManager.NETWORK_TYPE_LTE:
bin = DATA_CONNECTION_LTE;
break;
case TelephonyManager.NETWORK_TYPE_EHRPD:
bin = DATA_CONNECTION_EHRPD;
break;
case TelephonyManager.NETWORK_TYPE_HSPAP:
bin = DATA_CONNECTION_HSPAP;
break;
default:
bin = DATA_CONNECTION_OTHER;
break;
}
}
if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
if (mPhoneDataConnectionType != bin) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
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(elapsedRealtime, uptime);
if (mPhoneDataConnectionType >= 0) {
mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(
elapsedRealtime);
}
mPhoneDataConnectionType = bin;
mPhoneDataConnectionsTimer[bin].startRunningLocked(elapsedRealtime);
}
}
public void noteWifiOnLocked() {
if (!mWifiOn) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mWifiOn = true;
mWifiOnTimer.startRunningLocked(elapsedRealtime);
}
}
public void noteWifiOffLocked() {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (mWifiOn) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mWifiOn = false;
mWifiOnTimer.stopRunningLocked(elapsedRealtime);
}
}
public void noteAudioOnLocked(int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (mAudioOnNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mAudioOnTimer.startRunningLocked(elapsedRealtime);
}
mAudioOnNesting++;
getUidStatsLocked(uid).noteAudioTurnedOnLocked(elapsedRealtime);
}
public void noteAudioOffLocked(int uid) {
if (mAudioOnNesting == 0) {
return;
}
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (--mAudioOnNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mAudioOnTimer.stopRunningLocked(elapsedRealtime);
}
getUidStatsLocked(uid).noteAudioTurnedOffLocked(elapsedRealtime);
}
public void noteVideoOnLocked(int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (mVideoOnNesting == 0) {
mHistoryCur.states2 |= HistoryItem.STATE2_VIDEO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mVideoOnTimer.startRunningLocked(elapsedRealtime);
}
mVideoOnNesting++;
getUidStatsLocked(uid).noteVideoTurnedOnLocked(elapsedRealtime);
}
public void noteVideoOffLocked(int uid) {
if (mVideoOnNesting == 0) {
return;
}
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (--mVideoOnNesting == 0) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mVideoOnTimer.stopRunningLocked(elapsedRealtime);
}
getUidStatsLocked(uid).noteVideoTurnedOffLocked(elapsedRealtime);
}
public void noteResetAudioLocked() {
if (mAudioOnNesting > 0) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mAudioOnNesting = 0;
mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mAudioOnTimer.stopAllRunningLocked(elapsedRealtime);
for (int i=0; i 0) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mAudioOnNesting = 0;
mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mVideoOnTimer.stopAllRunningLocked(elapsedRealtime);
for (int i=0; i " + wifiState);
if (mWifiState != wifiState) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
if (mWifiState >= 0) {
mWifiStateTimer[mWifiState].stopRunningLocked(elapsedRealtime);
}
mWifiState = wifiState;
mWifiStateTimer[wifiState].startRunningLocked(elapsedRealtime);
}
}
public void noteWifiSupplicantStateChangedLocked(int supplState, boolean failedAuth) {
if (DEBUG) Log.i(TAG, "WiFi suppl state -> " + supplState);
if (mWifiSupplState != supplState) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (mWifiSupplState >= 0) {
mWifiSupplStateTimer[mWifiSupplState].stopRunningLocked(elapsedRealtime);
}
mWifiSupplState = supplState;
mWifiSupplStateTimer[supplState].startRunningLocked(elapsedRealtime);
mHistoryCur.states2 =
(mHistoryCur.states2&~HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK)
| (supplState << HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Wifi suppl state " + supplState + " to: "
+ Integer.toHexString(mHistoryCur.states2));
addHistoryRecordLocked(elapsedRealtime, uptime);
}
}
void stopAllWifiSignalStrengthTimersLocked(int except) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
for (int i = 0; i < NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
if (i == except) {
continue;
}
while (mWifiSignalStrengthsTimer[i].isRunningLocked()) {
mWifiSignalStrengthsTimer[i].stopRunningLocked(elapsedRealtime);
}
}
}
public void noteWifiRssiChangedLocked(int newRssi) {
int strengthBin = WifiManager.calculateSignalLevel(newRssi, NUM_WIFI_SIGNAL_STRENGTH_BINS);
if (DEBUG) Log.i(TAG, "WiFi rssi -> " + newRssi + " bin=" + strengthBin);
if (mWifiSignalStrengthBin != strengthBin) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (mWifiSignalStrengthBin >= 0) {
mWifiSignalStrengthsTimer[mWifiSignalStrengthBin].stopRunningLocked(
elapsedRealtime);
}
if (strengthBin >= 0) {
if (!mWifiSignalStrengthsTimer[strengthBin].isRunningLocked()) {
mWifiSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtime);
}
mHistoryCur.states2 =
(mHistoryCur.states2&~HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK)
| (strengthBin << HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Wifi signal strength " + strengthBin + " to: "
+ Integer.toHexString(mHistoryCur.states2));
addHistoryRecordLocked(elapsedRealtime, uptime);
} else {
stopAllWifiSignalStrengthTimersLocked(-1);
}
mWifiSignalStrengthBin = strengthBin;
}
}
public void noteBluetoothOnLocked() {
if (!mBluetoothOn) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mHistoryCur.states |= HistoryItem.STATE_BLUETOOTH_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mBluetoothOn = true;
mBluetoothOnTimer.startRunningLocked(elapsedRealtime);
}
}
public void noteBluetoothOffLocked() {
if (mBluetoothOn) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mHistoryCur.states &= ~HistoryItem.STATE_BLUETOOTH_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mBluetoothOn = false;
mBluetoothOnTimer.stopRunningLocked(elapsedRealtime);
}
}
public void noteBluetoothStateLocked(int bluetoothState) {
if (DEBUG) Log.i(TAG, "Bluetooth state -> " + bluetoothState);
if (mBluetoothState != bluetoothState) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
if (mBluetoothState >= 0) {
mBluetoothStateTimer[mBluetoothState].stopRunningLocked(elapsedRealtime);
}
mBluetoothState = bluetoothState;
mBluetoothStateTimer[bluetoothState].startRunningLocked(elapsedRealtime);
}
}
int mWifiFullLockNesting = 0;
public void noteFullWifiLockAcquiredLocked(int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
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(elapsedRealtime, uptime);
}
mWifiFullLockNesting++;
getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked(elapsedRealtime);
}
public void noteFullWifiLockReleasedLocked(int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
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(elapsedRealtime, uptime);
}
getUidStatsLocked(uid).noteFullWifiLockReleasedLocked(elapsedRealtime);
}
int mWifiScanNesting = 0;
public void noteWifiScanStartedLocked(int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (mWifiScanNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
}
mWifiScanNesting++;
getUidStatsLocked(uid).noteWifiScanStartedLocked(elapsedRealtime);
}
public void noteWifiScanStoppedLocked(int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mWifiScanNesting--;
if (mWifiScanNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan stopped for: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
}
getUidStatsLocked(uid).noteWifiScanStoppedLocked(elapsedRealtime);
}
public void noteWifiBatchedScanStartedLocked(int uid, int csph) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph, elapsedRealtime);
}
public void noteWifiBatchedScanStoppedLocked(int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked(elapsedRealtime);
}
int mWifiMulticastNesting = 0;
public void noteWifiMulticastEnabledLocked(int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
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(elapsedRealtime, uptime);
}
mWifiMulticastNesting++;
getUidStatsLocked(uid).noteWifiMulticastEnabledLocked(elapsedRealtime);
}
public void noteWifiMulticastDisabledLocked(int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
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(elapsedRealtime, uptime);
}
getUidStatsLocked(uid).noteWifiMulticastDisabledLocked(elapsedRealtime);
}
public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i= 0) {
return array;
}
String[] newArray = new String[array.length+1];
System.arraycopy(array, 0, newArray, 0, array.length);
newArray[array.length] = str;
return newArray;
}
private static String[] excludeFromStringArray(String[] array, String str) {
int index = ArrayUtils.indexOf(array, str);
if (index >= 0) {
String[] newArray = new String[array.length-1];
if (index > 0) {
System.arraycopy(array, 0, newArray, 0, index);
}
if (index < array.length-1) {
System.arraycopy(array, index+1, newArray, index, array.length-index-1);
}
return newArray;
}
return array;
}
public void noteNetworkInterfaceTypeLocked(String iface, int networkType) {
if (TextUtils.isEmpty(iface)) return;
if (ConnectivityManager.isNetworkTypeMobile(networkType)) {
mMobileIfaces = includeInStringArray(mMobileIfaces, iface);
if (DEBUG) Slog.d(TAG, "Note mobile iface " + iface + ": " + mMobileIfaces);
} else {
mMobileIfaces = excludeFromStringArray(mMobileIfaces, iface);
if (DEBUG) Slog.d(TAG, "Note non-mobile iface " + iface + ": " + mMobileIfaces);
}
if (ConnectivityManager.isNetworkTypeWifi(networkType)) {
mWifiIfaces = includeInStringArray(mWifiIfaces, iface);
if (DEBUG) Slog.d(TAG, "Note wifi iface " + iface + ": " + mWifiIfaces);
} else {
mWifiIfaces = excludeFromStringArray(mWifiIfaces, iface);
if (DEBUG) Slog.d(TAG, "Note non-wifi iface " + iface + ": " + mWifiIfaces);
}
}
public void noteNetworkStatsEnabledLocked() {
// During device boot, qtaguid isn't enabled until after the inital
// loading of battery stats. Now that they're enabled, take our initial
// snapshot for future delta calculation.
updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
}
@Override public long getScreenOnTime(long elapsedRealtimeUs, int which) {
return mScreenOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override public int getScreenOnCount(int which) {
return mScreenOnTimer.getCountLocked(which);
}
@Override public long getScreenBrightnessTime(int brightnessBin,
long elapsedRealtimeUs, int which) {
return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
elapsedRealtimeUs, which);
}
@Override public long getInteractiveTime(long elapsedRealtimeUs, int which) {
return mInteractiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override public long getLowPowerModeEnabledTime(long elapsedRealtimeUs, int which) {
return mLowPowerModeEnabledTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override public int getLowPowerModeEnabledCount(int which) {
return mLowPowerModeEnabledTimer.getCountLocked(which);
}
@Override public long getPhoneOnTime(long elapsedRealtimeUs, int which) {
return mPhoneOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override public int getPhoneOnCount(int which) {
return mPhoneOnTimer.getCountLocked(which);
}
@Override public long getPhoneSignalStrengthTime(int strengthBin,
long elapsedRealtimeUs, int which) {
return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
elapsedRealtimeUs, which);
}
@Override public long getPhoneSignalScanningTime(
long elapsedRealtimeUs, int which) {
return mPhoneSignalScanningTimer.getTotalTimeLocked(
elapsedRealtimeUs, which);
}
@Override public int getPhoneSignalStrengthCount(int strengthBin, int which) {
return mPhoneSignalStrengthsTimer[strengthBin].getCountLocked(which);
}
@Override public long getPhoneDataConnectionTime(int dataType,
long elapsedRealtimeUs, int which) {
return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
elapsedRealtimeUs, which);
}
@Override public int getPhoneDataConnectionCount(int dataType, int which) {
return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
}
@Override public long getMobileRadioActiveTime(long elapsedRealtimeUs, int which) {
return mMobileRadioActiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override public int getMobileRadioActiveCount(int which) {
return mMobileRadioActiveTimer.getCountLocked(which);
}
@Override public long getMobileRadioActiveAdjustedTime(int which) {
return mMobileRadioActiveAdjustedTime.getCountLocked(which);
}
@Override public long getMobileRadioActiveUnknownTime(int which) {
return mMobileRadioActiveUnknownTime.getCountLocked(which);
}
@Override public int getMobileRadioActiveUnknownCount(int which) {
return (int)mMobileRadioActiveUnknownCount.getCountLocked(which);
}
@Override public long getWifiOnTime(long elapsedRealtimeUs, int which) {
return mWifiOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override public long getGlobalWifiRunningTime(long elapsedRealtimeUs, int which) {
return mGlobalWifiRunningTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override public long getWifiStateTime(int wifiState,
long elapsedRealtimeUs, int which) {
return mWifiStateTimer[wifiState].getTotalTimeLocked(
elapsedRealtimeUs, which);
}
@Override public int getWifiStateCount(int wifiState, int which) {
return mWifiStateTimer[wifiState].getCountLocked(which);
}
@Override public long getWifiSupplStateTime(int state,
long elapsedRealtimeUs, int which) {
return mWifiSupplStateTimer[state].getTotalTimeLocked(
elapsedRealtimeUs, which);
}
@Override public int getWifiSupplStateCount(int state, int which) {
return mWifiSupplStateTimer[state].getCountLocked(which);
}
@Override public long getWifiSignalStrengthTime(int strengthBin,
long elapsedRealtimeUs, int which) {
return mWifiSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
elapsedRealtimeUs, which);
}
@Override public int getWifiSignalStrengthCount(int strengthBin, int which) {
return mWifiSignalStrengthsTimer[strengthBin].getCountLocked(which);
}
@Override public long getBluetoothOnTime(long elapsedRealtimeUs, int which) {
return mBluetoothOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override public long getBluetoothStateTime(int bluetoothState,
long elapsedRealtimeUs, int which) {
return mBluetoothStateTimer[bluetoothState].getTotalTimeLocked(
elapsedRealtimeUs, which);
}
@Override public int getBluetoothStateCount(int bluetoothState, int which) {
return mBluetoothStateTimer[bluetoothState].getCountLocked(which);
}
@Override public long getFlashlightOnTime(long elapsedRealtimeUs, int which) {
return mFlashlightOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override public long getFlashlightOnCount(int which) {
return mFlashlightOnTimer.getCountLocked(which);
}
@Override
public long getNetworkActivityBytes(int type, int which) {
if (type >= 0 && type < mNetworkByteActivityCounters.length) {
return mNetworkByteActivityCounters[type].getCountLocked(which);
} else {
return 0;
}
}
@Override
public long getNetworkActivityPackets(int type, int which) {
if (type >= 0 && type < mNetworkPacketActivityCounters.length) {
return mNetworkPacketActivityCounters[type].getCountLocked(which);
} else {
return 0;
}
}
boolean isStartClockTimeValid() {
return mStartClockTime > 365*24*60*60*1000L;
}
@Override public long getStartClockTime() {
if (!isStartClockTimeValid()) {
// If the last clock time we got was very small, then we hadn't had a real
// time yet, so try to get it again.
mStartClockTime = System.currentTimeMillis();
if (isStartClockTimeValid()) {
recordCurrentTimeChangeLocked(mStartClockTime, SystemClock.elapsedRealtime(),
SystemClock.uptimeMillis());
}
}
return mStartClockTime;
}
@Override public String getStartPlatformVersion() {
return mStartPlatformVersion;
}
@Override public String getEndPlatformVersion() {
return mEndPlatformVersion;
}
@Override public int getParcelVersion() {
return VERSION;
}
@Override public boolean getIsOnBattery() {
return mOnBattery;
}
@Override public SparseArray getUidStats() {
return mUidStats;
}
/**
* The statistics associated with a particular uid.
*/
public final class Uid extends BatteryStats.Uid {
final int mUid;
boolean mWifiRunning;
StopwatchTimer mWifiRunningTimer;
boolean mFullWifiLockOut;
StopwatchTimer mFullWifiLockTimer;
boolean mWifiScanStarted;
StopwatchTimer mWifiScanTimer;
static final int NO_BATCHED_SCAN_STARTED = -1;
int mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
StopwatchTimer[] mWifiBatchedScanTimer;
boolean mWifiMulticastEnabled;
StopwatchTimer mWifiMulticastTimer;
StopwatchTimer mAudioTurnedOnTimer;
StopwatchTimer mVideoTurnedOnTimer;
StopwatchTimer mForegroundActivityTimer;
static final int PROCESS_STATE_NONE = NUM_PROCESS_STATE;
int mProcessState = PROCESS_STATE_NONE;
StopwatchTimer[] mProcessStateTimer;
BatchTimer mVibratorOnTimer;
Counter[] mUserActivityCounters;
LongSamplingCounter[] mNetworkByteActivityCounters;
LongSamplingCounter[] mNetworkPacketActivityCounters;
LongSamplingCounter mMobileRadioActiveTime;
LongSamplingCounter mMobileRadioActiveCount;
/**
* The statistics we have collected for this uid's wake locks.
*/
final OverflowArrayMap mWakelockStats = new OverflowArrayMap() {
@Override public Wakelock instantiateObject() { return new Wakelock(); }
};
/**
* The statistics we have collected for this uid's syncs.
*/
final OverflowArrayMap mSyncStats = new OverflowArrayMap() {
@Override public StopwatchTimer instantiateObject() {
return new StopwatchTimer(Uid.this, SYNC, null, mOnBatteryTimeBase);
}
};
/**
* The statistics we have collected for this uid's jobs.
*/
final OverflowArrayMap mJobStats = new OverflowArrayMap() {
@Override public StopwatchTimer instantiateObject() {
return new StopwatchTimer(Uid.this, JOB, null, mOnBatteryTimeBase);
}
};
/**
* The statistics we have collected for this uid's sensor activations.
*/
final SparseArray mSensorStats = new SparseArray();
/**
* The statistics we have collected for this uid's processes.
*/
final ArrayMap mProcessStats = new ArrayMap();
/**
* The statistics we have collected for this uid's processes.
*/
final ArrayMap mPackageStats = new ArrayMap();
/**
* The transient wake stats we have collected for this uid's pids.
*/
final SparseArray mPids = new SparseArray();
public Uid(int uid) {
mUid = uid;
mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
mWifiRunningTimers, mOnBatteryTimeBase);
mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
mFullWifiLockTimers, mOnBatteryTimeBase);
mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
mWifiScanTimers, mOnBatteryTimeBase);
mWifiBatchedScanTimer = new StopwatchTimer[NUM_WIFI_BATCHED_SCAN_BINS];
mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
mWifiMulticastTimers, mOnBatteryTimeBase);
mProcessStateTimer = new StopwatchTimer[NUM_PROCESS_STATE];
}
@Override
public Map getWakelockStats() {
return mWakelockStats.getMap();
}
@Override
public Map getSyncStats() {
return mSyncStats.getMap();
}
@Override
public Map getJobStats() {
return mJobStats.getMap();
}
@Override
public SparseArray getSensorStats() {
return mSensorStats;
}
@Override
public Map getProcessStats() {
return mProcessStats;
}
@Override
public Map getPackageStats() {
return mPackageStats;
}
@Override
public int getUid() {
return mUid;
}
@Override
public void noteWifiRunningLocked(long elapsedRealtimeMs) {
if (!mWifiRunning) {
mWifiRunning = true;
if (mWifiRunningTimer == null) {
mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
mWifiRunningTimers, mOnBatteryTimeBase);
}
mWifiRunningTimer.startRunningLocked(elapsedRealtimeMs);
}
}
@Override
public void noteWifiStoppedLocked(long elapsedRealtimeMs) {
if (mWifiRunning) {
mWifiRunning = false;
mWifiRunningTimer.stopRunningLocked(elapsedRealtimeMs);
}
}
@Override
public void noteFullWifiLockAcquiredLocked(long elapsedRealtimeMs) {
if (!mFullWifiLockOut) {
mFullWifiLockOut = true;
if (mFullWifiLockTimer == null) {
mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
mFullWifiLockTimers, mOnBatteryTimeBase);
}
mFullWifiLockTimer.startRunningLocked(elapsedRealtimeMs);
}
}
@Override
public void noteFullWifiLockReleasedLocked(long elapsedRealtimeMs) {
if (mFullWifiLockOut) {
mFullWifiLockOut = false;
mFullWifiLockTimer.stopRunningLocked(elapsedRealtimeMs);
}
}
@Override
public void noteWifiScanStartedLocked(long elapsedRealtimeMs) {
if (!mWifiScanStarted) {
mWifiScanStarted = true;
if (mWifiScanTimer == null) {
mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
mWifiScanTimers, mOnBatteryTimeBase);
}
mWifiScanTimer.startRunningLocked(elapsedRealtimeMs);
}
}
@Override
public void noteWifiScanStoppedLocked(long elapsedRealtimeMs) {
if (mWifiScanStarted) {
mWifiScanStarted = false;
mWifiScanTimer.stopRunningLocked(elapsedRealtimeMs);
}
}
@Override
public void noteWifiBatchedScanStartedLocked(int csph, long elapsedRealtimeMs) {
int bin = 0;
while (csph > 8 && bin < NUM_WIFI_BATCHED_SCAN_BINS) {
csph = csph >> 3;
bin++;
}
if (mWifiBatchedScanBinStarted == bin) return;
if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
stopRunningLocked(elapsedRealtimeMs);
}
mWifiBatchedScanBinStarted = bin;
if (mWifiBatchedScanTimer[bin] == null) {
makeWifiBatchedScanBin(bin, null);
}
mWifiBatchedScanTimer[bin].startRunningLocked(elapsedRealtimeMs);
}
@Override
public void noteWifiBatchedScanStoppedLocked(long elapsedRealtimeMs) {
if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
stopRunningLocked(elapsedRealtimeMs);
mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
}
}
@Override
public void noteWifiMulticastEnabledLocked(long elapsedRealtimeMs) {
if (!mWifiMulticastEnabled) {
mWifiMulticastEnabled = true;
if (mWifiMulticastTimer == null) {
mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
mWifiMulticastTimers, mOnBatteryTimeBase);
}
mWifiMulticastTimer.startRunningLocked(elapsedRealtimeMs);
}
}
@Override
public void noteWifiMulticastDisabledLocked(long elapsedRealtimeMs) {
if (mWifiMulticastEnabled) {
mWifiMulticastEnabled = false;
mWifiMulticastTimer.stopRunningLocked(elapsedRealtimeMs);
}
}
public StopwatchTimer createAudioTurnedOnTimerLocked() {
if (mAudioTurnedOnTimer == null) {
mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
mAudioTurnedOnTimers, mOnBatteryTimeBase);
}
return mAudioTurnedOnTimer;
}
public void noteAudioTurnedOnLocked(long elapsedRealtimeMs) {
createAudioTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
}
public void noteAudioTurnedOffLocked(long elapsedRealtimeMs) {
if (mAudioTurnedOnTimer != null) {
mAudioTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
}
}
public void noteResetAudioLocked(long elapsedRealtimeMs) {
if (mAudioTurnedOnTimer != null) {
mAudioTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
}
}
public StopwatchTimer createVideoTurnedOnTimerLocked() {
if (mVideoTurnedOnTimer == null) {
mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
mVideoTurnedOnTimers, mOnBatteryTimeBase);
}
return mVideoTurnedOnTimer;
}
public void noteVideoTurnedOnLocked(long elapsedRealtimeMs) {
createVideoTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
}
public void noteVideoTurnedOffLocked(long elapsedRealtimeMs) {
if (mVideoTurnedOnTimer != null) {
mVideoTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
}
}
public void noteResetVideoLocked(long elapsedRealtimeMs) {
if (mVideoTurnedOnTimer != null) {
mVideoTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
}
}
public StopwatchTimer createForegroundActivityTimerLocked() {
if (mForegroundActivityTimer == null) {
mForegroundActivityTimer = new StopwatchTimer(
Uid.this, FOREGROUND_ACTIVITY, null, mOnBatteryTimeBase);
}
return mForegroundActivityTimer;
}
@Override
public void noteActivityResumedLocked(long elapsedRealtimeMs) {
// We always start, since we want multiple foreground PIDs to nest
createForegroundActivityTimerLocked().startRunningLocked(elapsedRealtimeMs);
}
@Override
public void noteActivityPausedLocked(long elapsedRealtimeMs) {
if (mForegroundActivityTimer != null) {
mForegroundActivityTimer.stopRunningLocked(elapsedRealtimeMs);
}
}
void updateUidProcessStateLocked(int state, long elapsedRealtimeMs) {
if (mProcessState == state) return;
if (mProcessState != PROCESS_STATE_NONE) {
mProcessStateTimer[mProcessState].stopRunningLocked(elapsedRealtimeMs);
}
mProcessState = state;
if (state != PROCESS_STATE_NONE) {
if (mProcessStateTimer[state] == null) {
makeProcessState(state, null);
}
mProcessStateTimer[state].startRunningLocked(elapsedRealtimeMs);
}
}
public BatchTimer createVibratorOnTimerLocked() {
if (mVibratorOnTimer == null) {
mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON, mOnBatteryTimeBase);
}
return mVibratorOnTimer;
}
public void noteVibratorOnLocked(long durationMillis) {
createVibratorOnTimerLocked().addDuration(BatteryStatsImpl.this, durationMillis);
}
public void noteVibratorOffLocked() {
if (mVibratorOnTimer != null) {
mVibratorOnTimer.abortLastDuration(BatteryStatsImpl.this);
}
}
@Override
public long getWifiRunningTime(long elapsedRealtimeUs, int which) {
if (mWifiRunningTimer == null) {
return 0;
}
return mWifiRunningTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override
public long getFullWifiLockTime(long elapsedRealtimeUs, int which) {
if (mFullWifiLockTimer == null) {
return 0;
}
return mFullWifiLockTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override
public long getWifiScanTime(long elapsedRealtimeUs, int which) {
if (mWifiScanTimer == null) {
return 0;
}
return mWifiScanTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override
public long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which) {
if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0;
if (mWifiBatchedScanTimer[csphBin] == null) {
return 0;
}
return mWifiBatchedScanTimer[csphBin].getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override
public long getWifiMulticastTime(long elapsedRealtimeUs, int which) {
if (mWifiMulticastTimer == null) {
return 0;
}
return mWifiMulticastTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override
public long getAudioTurnedOnTime(long elapsedRealtimeUs, int which) {
if (mAudioTurnedOnTimer == null) {
return 0;
}
return mAudioTurnedOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override
public long getVideoTurnedOnTime(long elapsedRealtimeUs, int which) {
if (mVideoTurnedOnTimer == null) {
return 0;
}
return mVideoTurnedOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override
public Timer getForegroundActivityTimer() {
return mForegroundActivityTimer;
}
void makeProcessState(int i, Parcel in) {
if (i < 0 || i >= NUM_PROCESS_STATE) return;
if (in == null) {
mProcessStateTimer[i] = new StopwatchTimer(this, PROCESS_STATE, null,
mOnBatteryTimeBase);
} else {
mProcessStateTimer[i] = new StopwatchTimer(this, PROCESS_STATE, null,
mOnBatteryTimeBase, in);
}
}
@Override
public long getProcessStateTime(int state, long elapsedRealtimeUs, int which) {
if (state < 0 || state >= NUM_PROCESS_STATE) return 0;
if (mProcessStateTimer[state] == null) {
return 0;
}
return mProcessStateTimer[state].getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override
public Timer getVibratorOnTimer() {
return mVibratorOnTimer;
}
@Override
public void noteUserActivityLocked(int type) {
if (mUserActivityCounters == null) {
initUserActivityLocked();
}
if (type >= 0 && type < NUM_USER_ACTIVITY_TYPES) {
mUserActivityCounters[type].stepAtomic();
} else {
Slog.w(TAG, "Unknown user activity type " + type + " was specified.",
new Throwable());
}
}
@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 makeWifiBatchedScanBin(int i, Parcel in) {
if (i < 0 || i >= NUM_WIFI_BATCHED_SCAN_BINS) return;
ArrayList collected = mWifiBatchedScanTimers.get(i);
if (collected == null) {
collected = new ArrayList();
mWifiBatchedScanTimers.put(i, collected);
}
if (in == null) {
mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
mOnBatteryTimeBase);
} else {
mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
mOnBatteryTimeBase, in);
}
}
void initUserActivityLocked() {
mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
for (int i=0; i= 0 && type < NUM_NETWORK_ACTIVITY_TYPES) {
mNetworkByteActivityCounters[type].addCountLocked(deltaBytes);
mNetworkPacketActivityCounters[type].addCountLocked(deltaPackets);
} else {
Slog.w(TAG, "Unknown network activity type " + type + " was specified.",
new Throwable());
}
}
void noteMobileRadioActiveTimeLocked(long batteryUptime) {
if (mNetworkByteActivityCounters == null) {
initNetworkActivityLocked();
}
mMobileRadioActiveTime.addCountLocked(batteryUptime);
mMobileRadioActiveCount.addCountLocked(1);
}
@Override
public boolean hasNetworkActivity() {
return mNetworkByteActivityCounters != null;
}
@Override
public long getNetworkActivityBytes(int type, int which) {
if (mNetworkByteActivityCounters != null && type >= 0
&& type < mNetworkByteActivityCounters.length) {
return mNetworkByteActivityCounters[type].getCountLocked(which);
} else {
return 0;
}
}
@Override
public long getNetworkActivityPackets(int type, int which) {
if (mNetworkPacketActivityCounters != null && type >= 0
&& type < mNetworkPacketActivityCounters.length) {
return mNetworkPacketActivityCounters[type].getCountLocked(which);
} else {
return 0;
}
}
@Override
public long getMobileRadioActiveTime(int which) {
return mMobileRadioActiveTime != null
? mMobileRadioActiveTime.getCountLocked(which) : 0;
}
@Override
public int getMobileRadioActiveCount(int which) {
return mMobileRadioActiveCount != null
? (int)mMobileRadioActiveCount.getCountLocked(which) : 0;
}
void initNetworkActivityLocked() {
mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
}
mMobileRadioActiveTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveCount = new LongSamplingCounter(mOnBatteryTimeBase);
}
/**
* 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(false);
active |= mWifiRunning;
}
if (mFullWifiLockTimer != null) {
active |= !mFullWifiLockTimer.reset(false);
active |= mFullWifiLockOut;
}
if (mWifiScanTimer != null) {
active |= !mWifiScanTimer.reset(false);
active |= mWifiScanStarted;
}
if (mWifiBatchedScanTimer != null) {
for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
if (mWifiBatchedScanTimer[i] != null) {
active |= !mWifiBatchedScanTimer[i].reset(false);
}
}
active |= (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED);
}
if (mWifiMulticastTimer != null) {
active |= !mWifiMulticastTimer.reset(false);
active |= mWifiMulticastEnabled;
}
if (mAudioTurnedOnTimer != null) {
active |= !mAudioTurnedOnTimer.reset(false);
}
if (mVideoTurnedOnTimer != null) {
active |= !mVideoTurnedOnTimer.reset(false);
}
if (mForegroundActivityTimer != null) {
active |= !mForegroundActivityTimer.reset(false);
}
if (mProcessStateTimer != null) {
for (int i = 0; i < NUM_PROCESS_STATE; i++) {
if (mProcessStateTimer[i] != null) {
active |= !mProcessStateTimer[i].reset(false);
}
}
active |= (mProcessState != PROCESS_STATE_NONE);
}
if (mVibratorOnTimer != null) {
if (mVibratorOnTimer.reset(false)) {
mVibratorOnTimer.detach();
mVibratorOnTimer = null;
} else {
active = true;
}
}
if (mUserActivityCounters != null) {
for (int i=0; i wakeStats = mWakelockStats.getMap();
for (int iw=wakeStats.size()-1; iw>=0; iw--) {
Wakelock wl = wakeStats.valueAt(iw);
if (wl.reset()) {
wakeStats.removeAt(iw);
} else {
active = true;
}
}
mWakelockStats.cleanup();
final ArrayMap syncStats = mSyncStats.getMap();
for (int is=syncStats.size()-1; is>=0; is--) {
StopwatchTimer timer = syncStats.valueAt(is);
if (timer.reset(false)) {
syncStats.removeAt(is);
timer.detach();
} else {
active = true;
}
}
mSyncStats.cleanup();
final ArrayMap jobStats = mJobStats.getMap();
for (int ij=jobStats.size()-1; ij>=0; ij--) {
StopwatchTimer timer = jobStats.valueAt(ij);
if (timer.reset(false)) {
jobStats.removeAt(ij);
timer.detach();
} else {
active = true;
}
}
mJobStats.cleanup();
for (int ise=mSensorStats.size()-1; ise>=0; ise--) {
Sensor s = mSensorStats.valueAt(ise);
if (s.reset()) {
mSensorStats.removeAt(ise);
} else {
active = true;
}
}
for (int ip=mProcessStats.size()-1; ip>=0; ip--) {
Proc proc = mProcessStats.valueAt(ip);
if (proc.mProcessState == PROCESS_STATE_NONE) {
proc.detach();
mProcessStats.removeAt(ip);
} else {
proc.reset();
active = true;
}
}
if (mPids.size() > 0) {
for (int i=mPids.size()-1; i>=0; i--) {
Pid pid = mPids.valueAt(i);
if (pid.mWakeNesting > 0) {
active = true;
} else {
mPids.removeAt(i);
}
}
}
if (mPackageStats.size() > 0) {
Iterator> it = mPackageStats.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pkgEntry = it.next();
Pkg p = pkgEntry.getValue();
p.detach();
if (p.mServiceStats.size() > 0) {
Iterator> it2
= p.mServiceStats.entrySet().iterator();
while (it2.hasNext()) {
Map.Entry servEntry = it2.next();
servEntry.getValue().detach();
}
}
}
mPackageStats.clear();
}
if (!active) {
if (mWifiRunningTimer != null) {
mWifiRunningTimer.detach();
}
if (mFullWifiLockTimer != null) {
mFullWifiLockTimer.detach();
}
if (mWifiScanTimer != null) {
mWifiScanTimer.detach();
}
for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
if (mWifiBatchedScanTimer[i] != null) {
mWifiBatchedScanTimer[i].detach();
}
}
if (mWifiMulticastTimer != null) {
mWifiMulticastTimer.detach();
}
if (mAudioTurnedOnTimer != null) {
mAudioTurnedOnTimer.detach();
mAudioTurnedOnTimer = null;
}
if (mVideoTurnedOnTimer != null) {
mVideoTurnedOnTimer.detach();
mVideoTurnedOnTimer = null;
}
if (mForegroundActivityTimer != null) {
mForegroundActivityTimer.detach();
mForegroundActivityTimer = null;
}
if (mUserActivityCounters != null) {
for (int i=0; i wakeStats = mWakelockStats.getMap();
int NW = wakeStats.size();
out.writeInt(NW);
for (int iw=0; iw syncStats = mSyncStats.getMap();
int NS = syncStats.size();
out.writeInt(NS);
for (int is=0; is jobStats = mJobStats.getMap();
int NJ = jobStats.size();
out.writeInt(NJ);
for (int ij=0; ij pkgEntry : mPackageStats.entrySet()) {
out.writeString(pkgEntry.getKey());
Uid.Pkg pkg = pkgEntry.getValue();
pkg.writeToParcelLocked(out);
}
if (mWifiRunningTimer != null) {
out.writeInt(1);
mWifiRunningTimer.writeToParcel(out, elapsedRealtimeUs);
} else {
out.writeInt(0);
}
if (mFullWifiLockTimer != null) {
out.writeInt(1);
mFullWifiLockTimer.writeToParcel(out, elapsedRealtimeUs);
} else {
out.writeInt(0);
}
if (mWifiScanTimer != null) {
out.writeInt(1);
mWifiScanTimer.writeToParcel(out, elapsedRealtimeUs);
} else {
out.writeInt(0);
}
for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
if (mWifiBatchedScanTimer[i] != null) {
out.writeInt(1);
mWifiBatchedScanTimer[i].writeToParcel(out, elapsedRealtimeUs);
} else {
out.writeInt(0);
}
}
if (mWifiMulticastTimer != null) {
out.writeInt(1);
mWifiMulticastTimer.writeToParcel(out, elapsedRealtimeUs);
} else {
out.writeInt(0);
}
if (mAudioTurnedOnTimer != null) {
out.writeInt(1);
mAudioTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs);
} else {
out.writeInt(0);
}
if (mVideoTurnedOnTimer != null) {
out.writeInt(1);
mVideoTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs);
} else {
out.writeInt(0);
}
if (mForegroundActivityTimer != null) {
out.writeInt(1);
mForegroundActivityTimer.writeToParcel(out, elapsedRealtimeUs);
} else {
out.writeInt(0);
}
for (int i = 0; i < NUM_PROCESS_STATE; i++) {
if (mProcessStateTimer[i] != null) {
out.writeInt(1);
mProcessStateTimer[i].writeToParcel(out, elapsedRealtimeUs);
} else {
out.writeInt(0);
}
}
if (mVibratorOnTimer != null) {
out.writeInt(1);
mVibratorOnTimer.writeToParcel(out, elapsedRealtimeUs);
} else {
out.writeInt(0);
}
if (mUserActivityCounters != null) {
out.writeInt(1);
for (int i=0; i pool,
TimeBase timeBase, Parcel in) {
if (in.readInt() == 0) {
return null;
}
return new StopwatchTimer(Uid.this, type, pool, timeBase, in);
}
boolean reset() {
boolean wlactive = false;
if (mTimerFull != null) {
wlactive |= !mTimerFull.reset(false);
}
if (mTimerPartial != null) {
wlactive |= !mTimerPartial.reset(false);
}
if (mTimerWindow != null) {
wlactive |= !mTimerWindow.reset(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(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
mPartialTimers, screenOffTimeBase, in);
mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
mFullTimers, timeBase, in);
mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
mWindowTimers, timeBase, in);
}
void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
Timer.writeTimerToParcel(out, mTimerPartial, elapsedRealtimeUs);
Timer.writeTimerToParcel(out, mTimerFull, elapsedRealtimeUs);
Timer.writeTimerToParcel(out, mTimerWindow, elapsedRealtimeUs);
}
@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 StopwatchTimer getStopwatchTimer(int type) {
StopwatchTimer t;
switch (type) {
case WAKE_TYPE_PARTIAL:
t = mTimerPartial;
if (t == null) {
t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
mPartialTimers, mOnBatteryScreenOffTimeBase);
mTimerPartial = t;
}
return t;
case WAKE_TYPE_FULL:
t = mTimerFull;
if (t == null) {
t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
mFullTimers, mOnBatteryTimeBase);
mTimerFull = t;
}
return t;
case WAKE_TYPE_WINDOW:
t = mTimerWindow;
if (t == null) {
t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
mWindowTimers, mOnBatteryTimeBase);
mTimerWindow = t;
}
return t;
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(TimeBase timeBase, Parcel in) {
if (in.readInt() == 0) {
return null;
}
ArrayList pool = mSensorTimers.get(mHandle);
if (pool == null) {
pool = new ArrayList();
mSensorTimers.put(mHandle, pool);
}
return new StopwatchTimer(Uid.this, 0, pool, timeBase, in);
}
boolean reset() {
if (mTimer.reset(true)) {
mTimer = null;
return true;
}
return false;
}
void readFromParcelLocked(TimeBase timeBase, Parcel in) {
mTimer = readTimerFromParcel(timeBase, in);
}
void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
Timer.writeTimerToParcel(out, mTimer, elapsedRealtimeUs);
}
@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 TimeBaseObs {
/**
* The name of this process.
*/
final String mName;
/**
* Remains true until removed from the stats.
*/
boolean mActive = true;
/**
* 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;
/**
* Amount of time the process was running in the foreground.
*/
long mForegroundTime;
/**
* Number of times the process has been started.
*/
int mStarts;
/**
* 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 amount of foreground time loaded from a previous save.
*/
long mLoadedForegroundTime;
/**
* The number of times the process has started from a previous save.
*/
int mLoadedStarts;
/**
* 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 amount of foreground time loaded from the previous run
*/
long mLastForegroundTime;
/**
* The number of times the process has started from the previous run.
*/
int mLastStarts;
/**
* The amount of user time when last unplugged.
*/
long mUnpluggedUserTime;
/**
* The amount of system time when last unplugged.
*/
long mUnpluggedSystemTime;
/**
* The amount of foreground time since unplugged.
*/
long mUnpluggedForegroundTime;
/**
* The number of times the process has started before unplugged.
*/
int mUnpluggedStarts;
/**
* Current process state.
*/
int mProcessState = PROCESS_STATE_NONE;
SamplingCounter[] mSpeedBins;
ArrayList mExcessivePower;
Proc(String name) {
mName = name;
mOnBatteryTimeBase.add(this);
mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
mUnpluggedUserTime = mUserTime;
mUnpluggedSystemTime = mSystemTime;
mUnpluggedForegroundTime = mForegroundTime;
mUnpluggedStarts = mStarts;
}
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
}
void reset() {
mUserTime = mSystemTime = mForegroundTime = 0;
mStarts = 0;
mLoadedUserTime = mLoadedSystemTime = mLoadedForegroundTime = 0;
mLoadedStarts = 0;
mLastUserTime = mLastSystemTime = mLastForegroundTime = 0;
mLastStarts = 0;
mUnpluggedUserTime = mUnpluggedSystemTime = mUnpluggedForegroundTime = 0;
mUnpluggedStarts = 0;
for (int i = 0; i < mSpeedBins.length; i++) {
SamplingCounter c = mSpeedBins[i];
if (c != null) {
c.reset(false);
}
}
mExcessivePower = null;
}
void detach() {
mActive = false;
mOnBatteryTimeBase.remove(this);
for (int i = 0; i < mSpeedBins.length; i++) {
SamplingCounter c = mSpeedBins[i];
if (c != null) {
mOnBatteryTimeBase.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 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 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 10000) {
Slog.w(TAG, "File corrupt: too many excessive power entries " + N);
return false;
}
mExcessivePower = new ArrayList();
for (int i=0; i= steps ? bins : steps];
for (int i = 0; i < bins; i++) {
if (in.readInt() != 0) {
mSpeedBins[i] = new SamplingCounter(mOnBatteryTimeBase, 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 boolean isActive() {
return mActive;
}
@Override
public long getUserTime(int which) {
long 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 = 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 = 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 = 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(mOnBatteryTimeBase);
}
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 TimeBaseObs {
/**
* 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 mServiceStats = new HashMap();
Pkg() {
mOnBatteryScreenOffTimeBase.add(this);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
mUnpluggedWakeups = mWakeups;
}
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
}
void detach() {
mOnBatteryScreenOffTimeBase.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 servEntry : mServiceStats.entrySet()) {
out.writeString(servEntry.getKey());
Uid.Pkg.Serv serv = servEntry.getValue();
serv.writeToParcelLocked(out);
}
}
@Override
public Map getServiceStats() {
return mServiceStats;
}
@Override
public int getWakeups(int which) {
int 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 TimeBaseObs {
/**
* 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() {
mOnBatteryTimeBase.add(this);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime,
long baseRealtime) {
mUnpluggedStartTime = getStartTimeToNowLocked(baseUptime);
mUnpluggedStarts = mStarts;
mUnpluggedLaunches = mLaunches;
}
public void onTimeStopped(long elapsedRealtime, long baseUptime,
long baseRealtime) {
}
void detach() {
mOnBatteryTimeBase.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 = 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 = 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 = 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(name);
mProcessStats.put(name, ps);
}
return ps;
}
public void updateProcessStateLocked(String procName, int state, long elapsedRealtimeMs) {
int procState;
if (state <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
procState = PROCESS_STATE_FOREGROUND;
} else if (state <= ActivityManager.PROCESS_STATE_RECEIVER) {
procState = PROCESS_STATE_ACTIVE;
} else {
procState = PROCESS_STATE_RUNNING;
}
updateRealProcessStateLocked(procName, procState, elapsedRealtimeMs);
}
public void updateRealProcessStateLocked(String procName, int procState,
long elapsedRealtimeMs) {
Proc proc = getProcessStatsLocked(procName);
if (proc.mProcessState != procState) {
boolean changed;
if (procState < proc.mProcessState) {
// Has this process become more important? If so,
// we may need to change the uid if the currrent uid proc state
// is not as important as what we are now setting.
changed = mProcessState > procState;
} else {
// Has this process become less important? If so,
// we may need to change the uid if the current uid proc state
// is the same importance as the old setting.
changed = mProcessState == proc.mProcessState;
}
proc.mProcessState = procState;
if (changed) {
// uid's state may have changed; compute what the new state should be.
int uidProcState = PROCESS_STATE_NONE;
for (int ip=mProcessStats.size()-1; ip>=0; ip--) {
proc = mProcessStats.valueAt(ip);
if (proc.mProcessState < uidProcState) {
uidProcState = proc.mProcessState;
}
}
updateUidProcessStateLocked(uidProcState, elapsedRealtimeMs);
}
}
}
public SparseArray 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 void readSyncSummaryFromParcelLocked(String name, Parcel in) {
StopwatchTimer timer = mSyncStats.instantiateObject();
timer.readSummaryFromParcelLocked(in);
mSyncStats.add(name, timer);
}
public void readJobSummaryFromParcelLocked(String name, Parcel in) {
StopwatchTimer timer = mJobStats.instantiateObject();
timer.readSummaryFromParcelLocked(in);
mJobStats.add(name, timer);
}
public void readWakeSummaryFromParcelLocked(String wlName, Parcel in) {
Wakelock wl = new Wakelock();
mWakelockStats.add(wlName, wl);
if (in.readInt() != 0) {
wl.getStopwatchTimer(WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
wl.getStopwatchTimer(WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
wl.getStopwatchTimer(WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
}
}
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 timers = mSensorTimers.get(sensor);
if (timers == null) {
timers = new ArrayList();
mSensorTimers.put(sensor, timers);
}
t = new StopwatchTimer(Uid.this, BatteryStats.SENSOR, timers, mOnBatteryTimeBase);
se.mTimer = t;
return t;
}
public void noteStartSyncLocked(String name, long elapsedRealtimeMs) {
StopwatchTimer t = mSyncStats.startObject(name);
if (t != null) {
t.startRunningLocked(elapsedRealtimeMs);
}
}
public void noteStopSyncLocked(String name, long elapsedRealtimeMs) {
StopwatchTimer t = mSyncStats.stopObject(name);
if (t != null) {
t.stopRunningLocked(elapsedRealtimeMs);
}
}
public void noteStartJobLocked(String name, long elapsedRealtimeMs) {
StopwatchTimer t = mJobStats.startObject(name);
if (t != null) {
t.startRunningLocked(elapsedRealtimeMs);
}
}
public void noteStopJobLocked(String name, long elapsedRealtimeMs) {
StopwatchTimer t = mJobStats.stopObject(name);
if (t != null) {
t.stopRunningLocked(elapsedRealtimeMs);
}
}
public void noteStartWakeLocked(int pid, String name, int type, long elapsedRealtimeMs) {
Wakelock wl = mWakelockStats.startObject(name);
if (wl != null) {
wl.getStopwatchTimer(type).startRunningLocked(elapsedRealtimeMs);
}
if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
Pid p = getPidStatsLocked(pid);
if (p.mWakeNesting++ == 0) {
p.mWakeStartMs = elapsedRealtimeMs;
}
}
}
public void noteStopWakeLocked(int pid, String name, int type, long elapsedRealtimeMs) {
Wakelock wl = mWakelockStats.stopObject(name);
if (wl != null) {
wl.getStopwatchTimer(type).stopRunningLocked(elapsedRealtimeMs);
}
if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
Pid p = mPids.get(pid);
if (p != null && p.mWakeNesting > 0) {
if (p.mWakeNesting-- == 1) {
p.mWakeSumMs += elapsedRealtimeMs - p.mWakeStartMs;
p.mWakeStartMs = 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, long elapsedRealtimeMs) {
StopwatchTimer t = getSensorTimerLocked(sensor, true);
if (t != null) {
t.startRunningLocked(elapsedRealtimeMs);
}
}
public void noteStopSensor(int sensor, long elapsedRealtimeMs) {
// Don't create a timer if one doesn't already exist
StopwatchTimer t = getSensorTimerLocked(sensor, false);
if (t != null) {
t.stopRunningLocked(elapsedRealtimeMs);
}
}
public void noteStartGps(long elapsedRealtimeMs) {
StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
if (t != null) {
t.startRunningLocked(elapsedRealtimeMs);
}
}
public void noteStopGps(long elapsedRealtimeMs) {
StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
if (t != null) {
t.stopRunningLocked(elapsedRealtimeMs);
}
}
public BatteryStatsImpl getBatteryStats() {
return BatteryStatsImpl.this;
}
}
public BatteryStatsImpl(File systemDir, Handler handler) {
if (systemDir != null) {
mFile = new JournaledFile(new File(systemDir, "batterystats.bin"),
new File(systemDir, "batterystats.bin.tmp"));
} else {
mFile = null;
}
mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
mHandler = new MyHandler(handler.getLooper());
mStartCount++;
mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase);
for (int i=0; i= 0 && numStepLevels > 0) {
long duration = elapsedRealtime - lastStepTime;
for (int i=0; i STEP_LEVEL_TIME_MASK) {
thisDuration = STEP_LEVEL_TIME_MASK;
}
steps[0] = thisDuration | modeBits;
}
stepCount += numStepLevels;
if (stepCount > steps.length) {
stepCount = steps.length;
}
}
return stepCount;
}
public void setBatteryState(int status, int health, int plugType, int level,
int temp, int volt) {
synchronized(this) {
final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
final long uptime = SystemClock.uptimeMillis();
final long elapsedRealtime = SystemClock.elapsedRealtime();
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;
if (!mRecordingHistory) {
mRecordingHistory = true;
startRecordingHistory(elapsedRealtime, uptime, true);
}
} else if (level < 96) {
if (!mRecordingHistory) {
mRecordingHistory = true;
startRecordingHistory(elapsedRealtime, uptime, true);
}
}
mCurrentBatteryLevel = level;
if (mDischargePlugLevel < 0) {
mDischargePlugLevel = level;
}
if (onBattery != mOnBattery) {
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.batteryStatus = (byte)status;
mHistoryCur.batteryHealth = (byte)health;
mHistoryCur.batteryPlugType = (byte)plugType;
mHistoryCur.batteryTemperature = (short)temp;
mHistoryCur.batteryVoltage = (char)volt;
setOnBatteryLocked(elapsedRealtime, uptime, 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 (temp >= (mHistoryCur.batteryTemperature+10)
|| temp <= (mHistoryCur.batteryTemperature-10)) {
mHistoryCur.batteryTemperature = (short)temp;
changed = true;
}
if (volt > (mHistoryCur.batteryVoltage+20)
|| volt < (mHistoryCur.batteryVoltage-20)) {
mHistoryCur.batteryVoltage = (char)volt;
changed = true;
}
if (changed) {
addHistoryRecordLocked(elapsedRealtime, uptime);
}
long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT)
| (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT)
| (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
if (onBattery) {
if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
mNumDischargeStepDurations = addLevelSteps(mDischargeStepDurations,
mNumDischargeStepDurations, mLastDischargeStepTime,
mLastDischargeStepLevel - level, modeBits, elapsedRealtime);
mLastDischargeStepLevel = level;
mMinDischargeStepLevel = level;
mLastDischargeStepTime = elapsedRealtime;
mInitStepMode = mCurStepMode;
mModStepMode = 0;
}
} else {
if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
mNumChargeStepDurations = addLevelSteps(mChargeStepDurations,
mNumChargeStepDurations, mLastChargeStepTime,
level - mLastChargeStepLevel, modeBits, elapsedRealtime);
mLastChargeStepLevel = level;
mMaxChargeStepLevel = level;
mLastChargeStepTime = elapsedRealtime;
mInitStepMode = mCurStepMode;
mModStepMode = 0;
}
}
}
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 = DEBUG;
}
}
}
public void updateKernelWakelocksLocked() {
Map 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 ent : m.entrySet()) {
String name = ent.getKey();
KernelWakelockStats kws = ent.getValue();
SamplingTimer kwlt = mKernelWakelockStats.get(name);
if (kwlt == null) {
kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase,
true /* track reported val */);
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 ent : mKernelWakelockStats.entrySet()) {
SamplingTimer st = ent.getValue();
if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
st.setStale();
}
}
}
}
static final int NET_UPDATE_MOBILE = 1<<0;
static final int NET_UPDATE_WIFI = 1<<1;
static final int NET_UPDATE_ALL = 0xffff;
private void updateNetworkActivityLocked(int which, long elapsedRealtimeMs) {
if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return;
if ((which&NET_UPDATE_MOBILE) != 0 && mMobileIfaces.length > 0) {
final NetworkStats snapshot;
final NetworkStats last = mCurMobileSnapshot;
try {
snapshot = mNetworkStatsFactory.readNetworkStatsDetail(UID_ALL,
mMobileIfaces, NetworkStats.TAG_NONE, mLastMobileSnapshot);
} catch (IOException e) {
Log.wtf(TAG, "Failed to read mobile network stats", e);
return;
}
mCurMobileSnapshot = snapshot;
mLastMobileSnapshot = last;
if (mOnBatteryInternal) {
final NetworkStats delta = NetworkStats.subtract(snapshot, last,
null, null, mTmpNetworkStats);
mTmpNetworkStats = delta;
long radioTime = mMobileRadioActivePerAppTimer.checkpointRunningLocked(
elapsedRealtimeMs);
long totalPackets = delta.getTotalPackets();
final int size = delta.size();
for (int i = 0; i < size; i++) {
final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
final Uid u = getUidStatsLocked(mapUid(entry.uid));
u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes,
entry.rxPackets);
u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes,
entry.txPackets);
if (radioTime > 0) {
// Distribute total radio active time in to this app.
long appPackets = entry.rxPackets + entry.txPackets;
long appRadioTime = (radioTime*appPackets)/totalPackets;
u.noteMobileRadioActiveTimeLocked(appRadioTime);
// Remove this app from the totals, so that we don't lose any time
// due to rounding.
radioTime -= appRadioTime;
totalPackets -= appPackets;
}
mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
entry.rxBytes);
mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
entry.txBytes);
mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
entry.rxPackets);
mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
entry.txPackets);
}
if (radioTime > 0) {
// Whoops, there is some radio time we can't blame on an app!
mMobileRadioActiveUnknownTime.addCountLocked(radioTime);
mMobileRadioActiveUnknownCount.addCountLocked(1);
}
}
}
if ((which&NET_UPDATE_WIFI) != 0 && mWifiIfaces.length > 0) {
final NetworkStats snapshot;
final NetworkStats last = mCurWifiSnapshot;
try {
snapshot = mNetworkStatsFactory.readNetworkStatsDetail(UID_ALL,
mWifiIfaces, NetworkStats.TAG_NONE, mLastWifiSnapshot);
} catch (IOException e) {
Log.wtf(TAG, "Failed to read wifi network stats", e);
return;
}
mCurWifiSnapshot = snapshot;
mLastWifiSnapshot = last;
if (mOnBatteryInternal) {
final NetworkStats delta = NetworkStats.subtract(snapshot, last,
null, null, mTmpNetworkStats);
mTmpNetworkStats = delta;
final int size = delta.size();
for (int i = 0; i < size; i++) {
final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
if (DEBUG) {
final NetworkStats.Entry cur = snapshot.getValues(i, null);
Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes
+ " tx=" + entry.txBytes + ", cur rx=" + cur.rxBytes
+ " tx=" + cur.txBytes);
}
if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
final Uid u = getUidStatsLocked(mapUid(entry.uid));
u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
entry.rxPackets);
u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes,
entry.txPackets);
mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
entry.rxBytes);
mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
entry.txBytes);
mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
entry.rxPackets);
mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
entry.txPackets);
}
}
}
}
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_CURRENT: return (curTime-mUptimeStart);
case STATS_SINCE_UNPLUGGED: return (curTime-mOnBatteryTimeBase.getUptimeStart());
}
return 0;
}
@Override
public long computeRealtime(long curTime, int which) {
switch (which) {
case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
case STATS_CURRENT: return (curTime-mRealtimeStart);
case STATS_SINCE_UNPLUGGED: return (curTime-mOnBatteryTimeBase.getRealtimeStart());
}
return 0;
}
@Override
public long computeBatteryUptime(long curTime, int which) {
return mOnBatteryTimeBase.computeUptime(curTime, which);
}
@Override
public long computeBatteryRealtime(long curTime, int which) {
return mOnBatteryTimeBase.computeRealtime(curTime, which);
}
@Override
public long computeBatteryScreenOffUptime(long curTime, int which) {
return mOnBatteryScreenOffTimeBase.computeUptime(curTime, which);
}
@Override
public long computeBatteryScreenOffRealtime(long curTime, int which) {
return mOnBatteryScreenOffTimeBase.computeRealtime(curTime, which);
}
private long computeTimePerLevel(long[] steps, int numSteps) {
// For now we'll do a simple average across all steps.
if (numSteps <= 0) {
return -1;
}
long total = 0;
for (int i=0; i=0; i--) {
averageTime = (averageTime + buckets[i]) / 2;
}
return averageTime;
*/
}
@Override
public long computeBatteryTimeRemaining(long curTime) {
if (!mOnBattery) {
return -1;
}
/* Simple implementation just looks at the average discharge per level across the
entire sample period.
int discharge = (getLowDischargeAmountSinceCharge()+getHighDischargeAmountSinceCharge())/2;
if (discharge < 2) {
return -1;
}
long duration = computeBatteryRealtime(curTime, STATS_SINCE_CHARGED);
if (duration < 1000*1000) {
return -1;
}
long usPerLevel = duration/discharge;
return usPerLevel * mCurrentBatteryLevel;
*/
if (mNumDischargeStepDurations < 1) {
return -1;
}
long msPerLevel = computeTimePerLevel(mDischargeStepDurations, mNumDischargeStepDurations);
if (msPerLevel <= 0) {
return -1;
}
return (msPerLevel * mCurrentBatteryLevel) * 1000;
}
public int getNumDischargeStepDurations() {
return mNumDischargeStepDurations;
}
public long[] getDischargeStepDurationsArray() {
return mDischargeStepDurations;
}
@Override
public long computeChargeTimeRemaining(long curTime) {
if (mOnBattery) {
// Not yet working.
return -1;
}
/* Broken
int curLevel = mCurrentBatteryLevel;
int plugLevel = mDischargePlugLevel;
if (plugLevel < 0 || curLevel < (plugLevel+1)) {
return -1;
}
long duration = computeBatteryRealtime(curTime, STATS_SINCE_UNPLUGGED);
if (duration < 1000*1000) {
return -1;
}
long usPerLevel = duration/(curLevel-plugLevel);
return usPerLevel * (100-curLevel);
*/
if (mNumChargeStepDurations < 1) {
return -1;
}
long msPerLevel = computeTimePerLevel(mChargeStepDurations, mNumChargeStepDurations);
if (msPerLevel <= 0) {
return -1;
}
return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000;
}
public int getNumChargeStepDurations() {
return mNumChargeStepDurations;
}
public long[] getChargeStepDurationsArray() {
return mChargeStepDurations;
}
long getBatteryUptimeLocked() {
return mOnBatteryTimeBase.getUptime(SystemClock.uptimeMillis() * 1000);
}
@Override
public long getBatteryUptime(long curTime) {
return mOnBatteryTimeBase.getUptime(curTime);
}
@Override
public long getBatteryRealtime(long curTime) {
return mOnBatteryTimeBase.getRealtime(curTime);
}
@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) {
int val = mLowDischargeAmountSinceCharge;
if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
val += mDischargeUnplugLevel-mDischargeCurrentLevel-1;
}
return val;
}
}
@Override
public int getHighDischargeAmountSinceCharge() {
synchronized(this) {
int val = mHighDischargeAmountSinceCharge;
if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {
val += mDischargeUnplugLevel-mDischargeCurrentLevel;
}
return val;
}
}
@Override
public int getDischargeAmount(int which) {
int dischargeAmount = which == STATS_SINCE_CHARGED
? getHighDischargeAmountSinceCharge()
: (getDischargeStartLevel() - getDischargeCurrentLevel());
if (dischargeAmount < 0) {
dischargeAmount = 0;
}
return dischargeAmount;
}
public int getDischargeAmountScreenOn() {
synchronized(this) {
int val = mDischargeAmountScreenOn;
if (mOnBattery && mScreenState == Display.STATE_ON
&& mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
}
return val;
}
}
public int getDischargeAmountScreenOnSinceCharge() {
synchronized(this) {
int val = mDischargeAmountScreenOnSinceCharge;
if (mOnBattery && mScreenState == Display.STATE_ON
&& mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
}
return val;
}
}
public int getDischargeAmountScreenOff() {
synchronized(this) {
int val = mDischargeAmountScreenOff;
if (mOnBattery && mScreenState != Display.STATE_ON
&& mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
}
return val;
}
}
public int getDischargeAmountScreenOffSinceCharge() {
synchronized(this) {
int val = mDischargeAmountScreenOffSinceCharge;
if (mOnBattery && mScreenState != Display.STATE_ON
&& mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
}
return val;
}
}
@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 = mapUid(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 = mapUid(uid);
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 = mapUid(uid);
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 (int ip=wifiUid.mProcessStats.size()-1; ip>=0; ip--) {
Uid.Proc proc = wifiUid.mProcessStats.valueAt(ip);
long totalRunningTime = getGlobalWifiRunningTime(uSecTime, which);
for (int i=0; i 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 0) {
mRecordingHistory = true;
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (USE_OLD_HISTORY) {
addHistoryRecordLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
}
addHistoryBufferLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
startRecordingHistory(elapsedRealtime, uptime, false);
}
}
public int describeContents() {
return 0;
}
void readHistory(Parcel in, boolean andOldHistory) {
final long historyBaseTime = in.readLong();
mHistoryBuffer.setDataSize(0);
mHistoryBuffer.setDataPosition(0);
mHistoryTagPool.clear();
mNextHistoryTagIdx = 0;
mNumHistoryTagChars = 0;
int numTags = in.readInt();
for (int i=0; i= mNextHistoryTagIdx) {
mNextHistoryTagIdx = idx+1;
}
mNumHistoryTagChars += tag.string.length() + 1;
}
int bufSize = in.readInt();
int curPos = in.dataPosition();
if (bufSize >= (MAX_MAX_HISTORY_BUFFER*3)) {
Slog.w(TAG, "File corrupt: history data buffer too large " + bufSize);
} else if ((bufSize&~3) != bufSize) {
Slog.w(TAG, "File corrupt: history data buffer not aligned " + bufSize);
} else {
if (DEBUG_HISTORY) Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
+ " bytes at " + curPos);
mHistoryBuffer.appendFrom(in, curPos, bufSize);
in.setDataPosition(curPos + bufSize);
}
if (andOldHistory) {
readOldHistory(in);
}
if (DEBUG_HISTORY) {
StringBuilder sb = new StringBuilder(128);
sb.append("****************** OLD mHistoryBaseTime: ");
TimeUtils.formatDuration(mHistoryBaseTime, sb);
Slog.i(TAG, sb.toString());
}
mHistoryBaseTime = historyBaseTime;
if (DEBUG_HISTORY) {
StringBuilder sb = new StringBuilder(128);
sb.append("****************** NEW mHistoryBaseTime: ");
TimeUtils.formatDuration(mHistoryBaseTime, sb);
Slog.i(TAG, sb.toString());
}
// We are just arbitrarily going to insert 1 minute from the sample of
// the last run until samples in this run.
if (mHistoryBaseTime > 0) {
long oldnow = SystemClock.elapsedRealtime();
mHistoryBaseTime = mHistoryBaseTime - oldnow + 1;
if (DEBUG_HISTORY) {
StringBuilder sb = new StringBuilder(128);
sb.append("****************** ADJUSTED mHistoryBaseTime: ");
TimeUtils.formatDuration(mHistoryBaseTime, sb);
Slog.i(TAG, sb.toString());
}
}
}
void readOldHistory(Parcel in) {
if (!USE_OLD_HISTORY) {
return;
}
mHistory = mHistoryEnd = mHistoryCache = null;
long time;
while (in.dataAvail() > 0 && (time=in.readLong()) >= 0) {
HistoryItem rec = new HistoryItem(time, in);
addHistoryRecordLocked(rec);
}
}
void writeHistory(Parcel out, boolean inclData, boolean andOldHistory) {
if (DEBUG_HISTORY) {
StringBuilder sb = new StringBuilder(128);
sb.append("****************** WRITING mHistoryBaseTime: ");
TimeUtils.formatDuration(mHistoryBaseTime, sb);
sb.append(" mLastHistoryElapsedRealtime: ");
TimeUtils.formatDuration(mLastHistoryElapsedRealtime, sb);
Slog.i(TAG, sb.toString());
}
out.writeLong(mHistoryBaseTime + mLastHistoryElapsedRealtime);
if (!inclData) {
out.writeInt(0);
out.writeInt(0);
return;
}
out.writeInt(mHistoryTagPool.size());
for (HashMap.Entry ent : mHistoryTagPool.entrySet()) {
HistoryTag tag = ent.getKey();
out.writeInt(ent.getValue());
out.writeString(tag.string);
out.writeInt(tag.uid);
}
out.writeInt(mHistoryBuffer.dataSize());
if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
+ mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
if (andOldHistory) {
writeOldHistory(out);
}
}
void writeOldHistory(Parcel out) {
if (!USE_OLD_HISTORY) {
return;
}
HistoryItem rec = mHistory;
while (rec != null) {
if (rec.time >= 0) rec.writeToParcel(out, 0);
rec = rec.next;
}
out.writeLong(-1);
}
public 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, true);
mStartCount = in.readInt();
mUptime = in.readLong();
mRealtime = in.readLong();
mStartClockTime = in.readLong();
mStartPlatformVersion = in.readString();
mEndPlatformVersion = in.readString();
mOnBatteryTimeBase.readSummaryFromParcel(in);
mOnBatteryScreenOffTimeBase.readSummaryFromParcel(in);
mDischargeUnplugLevel = in.readInt();
mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
mCurrentBatteryLevel = in.readInt();
mLowDischargeAmountSinceCharge = in.readInt();
mHighDischargeAmountSinceCharge = in.readInt();
mDischargeAmountScreenOnSinceCharge = in.readInt();
mDischargeAmountScreenOffSinceCharge = in.readInt();
mNumDischargeStepDurations = in.readInt();
in.readLongArray(mDischargeStepDurations);
mNumChargeStepDurations = in.readInt();
in.readLongArray(mChargeStepDurations);
mStartCount++;
mScreenState = Display.STATE_UNKNOWN;
mScreenOnTimer.readSummaryFromParcelLocked(in);
for (int i=0; i 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);
}
}
int NWR = in.readInt();
if (NWR > 10000) {
Slog.w(TAG, "File corrupt: too many wakeup reasons " + NWR);
return;
}
for (int iwr = 0; iwr < NWR; iwr++) {
if (in.readInt() != 0) {
String reasonName = in.readString();
getWakeupReasonTimerLocked(reasonName).readSummaryFromParcelLocked(in);
}
}
sNumSpeedSteps = in.readInt();
if (sNumSpeedSteps < 0 || sNumSpeedSteps > 100) {
throw new BadParcelableException("Bad speed steps in data: " + sNumSpeedSteps);
}
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.mWifiScanStarted = false;
if (in.readInt() != 0) {
u.mWifiScanTimer.readSummaryFromParcelLocked(in);
}
u.mWifiBatchedScanBinStarted = Uid.NO_BATCHED_SCAN_STARTED;
for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
if (in.readInt() != 0) {
u.makeWifiBatchedScanBin(i, null);
u.mWifiBatchedScanTimer[i].readSummaryFromParcelLocked(in);
}
}
u.mWifiMulticastEnabled = false;
if (in.readInt() != 0) {
u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
u.createAudioTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
u.createVideoTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
u.createForegroundActivityTimerLocked().readSummaryFromParcelLocked(in);
}
u.mProcessState = Uid.PROCESS_STATE_NONE;
for (int i = 0; i < Uid.NUM_PROCESS_STATE; i++) {
if (in.readInt() != 0) {
u.makeProcessState(i, null);
u.mProcessStateTimer[i].readSummaryFromParcelLocked(in);
}
}
if (in.readInt() != 0) {
u.createVibratorOnTimerLocked().readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
if (u.mUserActivityCounters == null) {
u.initUserActivityLocked();
}
for (int i=0; i 100) {
Slog.w(TAG, "File corrupt: too many wake locks " + NW);
return;
}
for (int iw = 0; iw < NW; iw++) {
String wlName = in.readString();
u.readWakeSummaryFromParcelLocked(wlName, in);
}
int NS = in.readInt();
if (NS > 100) {
Slog.w(TAG, "File corrupt: too many syncs " + NS);
return;
}
for (int is = 0; is < NS; is++) {
String name = in.readString();
u.readSyncSummaryFromParcelLocked(name, in);
}
int NJ = in.readInt();
if (NJ > 100) {
Slog.w(TAG, "File corrupt: too many job timers " + NJ);
return;
}
for (int ij = 0; ij < NJ; ij++) {
String name = in.readString();
u.readJobSummaryFromParcelLocked(name, in);
}
int NP = in.readInt();
if (NP > 1000) {
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 > 1000) {
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.mForegroundTime = p.mLoadedForegroundTime = in.readLong();
p.mStarts = p.mLoadedStarts = in.readInt();
int NSB = in.readInt();
if (NSB > 100) {
Slog.w(TAG, "File corrupt: too many speed bins " + NSB);
return;
}
p.mSpeedBins = new SamplingCounter[NSB];
for (int i=0; i 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();
NS = in.readInt();
if (NS > 1000) {
Slog.w(TAG, "File corrupt: too many services " + NS);
return;
}
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();
}
}
}
}
/**
* 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, boolean inclHistory) {
pullPendingStateUpdatesLocked();
// Pull the clock time. This may update the time and make a new history entry
// if we had originally pulled a time before the RTC was set.
long startClockTime = getStartClockTime();
final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
out.writeInt(VERSION);
writeHistory(out, inclHistory, true);
out.writeInt(mStartCount);
out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
out.writeLong(startClockTime);
out.writeString(mStartPlatformVersion);
out.writeString(mEndPlatformVersion);
mOnBatteryTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
mOnBatteryScreenOffTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
out.writeInt(mDischargeUnplugLevel);
out.writeInt(mDischargePlugLevel);
out.writeInt(mDischargeCurrentLevel);
out.writeInt(mCurrentBatteryLevel);
out.writeInt(getLowDischargeAmountSinceCharge());
out.writeInt(getHighDischargeAmountSinceCharge());
out.writeInt(getDischargeAmountScreenOnSinceCharge());
out.writeInt(getDischargeAmountScreenOffSinceCharge());
out.writeInt(mNumDischargeStepDurations);
out.writeLongArray(mDischargeStepDurations);
out.writeInt(mNumChargeStepDurations);
out.writeLongArray(mChargeStepDurations);
mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
for (int i=0; i ent : mKernelWakelockStats.entrySet()) {
Timer kwlt = ent.getValue();
if (kwlt != null) {
out.writeInt(1);
out.writeString(ent.getKey());
kwlt.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
}
out.writeInt(mWakeupReasonStats.size());
for (Map.Entry ent : mWakeupReasonStats.entrySet()) {
SamplingTimer timer = ent.getValue();
if (timer != null) {
out.writeInt(1);
out.writeString(ent.getKey());
timer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} 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_SYS);
} else {
out.writeInt(0);
}
if (u.mFullWifiLockTimer != null) {
out.writeInt(1);
u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
if (u.mWifiScanTimer != null) {
out.writeInt(1);
u.mWifiScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
if (u.mWifiBatchedScanTimer[i] != null) {
out.writeInt(1);
u.mWifiBatchedScanTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
}
if (u.mWifiMulticastTimer != null) {
out.writeInt(1);
u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
if (u.mAudioTurnedOnTimer != null) {
out.writeInt(1);
u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
if (u.mVideoTurnedOnTimer != null) {
out.writeInt(1);
u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
if (u.mForegroundActivityTimer != null) {
out.writeInt(1);
u.mForegroundActivityTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
for (int i = 0; i < Uid.NUM_PROCESS_STATE; i++) {
if (u.mProcessStateTimer[i] != null) {
out.writeInt(1);
u.mProcessStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
}
if (u.mVibratorOnTimer != null) {
out.writeInt(1);
u.mVibratorOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
if (u.mUserActivityCounters == null) {
out.writeInt(0);
} else {
out.writeInt(1);
for (int i=0; i wakeStats = u.mWakelockStats.getMap();
int NW = wakeStats.size();
out.writeInt(NW);
for (int iw=0; iw syncStats = u.mSyncStats.getMap();
int NS = syncStats.size();
out.writeInt(NS);
for (int is=0; is jobStats = u.mJobStats.getMap();
int NJ = jobStats.size();
out.writeInt(NJ);
for (int ij=0; ij 0) {
for (Map.Entry ent
: u.mPackageStats.entrySet()) {
out.writeString(ent.getKey());
Uid.Pkg ps = ent.getValue();
out.writeInt(ps.mWakeups);
NS = ps.mServiceStats.size();
out.writeInt(NS);
if (NS > 0) {
for (Map.Entry sent
: ps.mServiceStats.entrySet()) {
out.writeString(sent.getKey());
BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
long time = ss.getStartTimeToNowLocked(
mOnBatteryTimeBase.getUptime(NOW_SYS));
out.writeLong(time);
out.writeInt(ss.mStarts);
out.writeInt(ss.mLaunches);
}
}
}
}
}
}
public void readFromParcel(Parcel in) {
readFromParcelLocked(in);
}
void readFromParcelLocked(Parcel in) {
int magic = in.readInt();
if (magic != MAGIC) {
throw new ParcelFormatException("Bad magic number: #" + Integer.toHexString(magic));
}
readHistory(in, false);
mStartCount = in.readInt();
mStartClockTime = in.readLong();
mStartPlatformVersion = in.readString();
mEndPlatformVersion = in.readString();
mUptime = in.readLong();
mUptimeStart = in.readLong();
mRealtime = in.readLong();
mRealtimeStart = in.readLong();
mOnBattery = in.readInt() != 0;
mOnBatteryInternal = false; // we are no longer really running.
mOnBatteryTimeBase.readFromParcel(in);
mOnBatteryScreenOffTimeBase.readFromParcel(in);
mScreenState = Display.STATE_UNKNOWN;
mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase, in);
for (int i=0; i ent : mKernelWakelockStats.entrySet()) {
SamplingTimer kwlt = ent.getValue();
if (kwlt != null) {
out.writeInt(1);
out.writeString(ent.getKey());
kwlt.writeToParcel(out, uSecRealtime);
} else {
out.writeInt(0);
}
}
out.writeInt(mWakeupReasonStats.size());
for (Map.Entry ent : mWakeupReasonStats.entrySet()) {
SamplingTimer timer = ent.getValue();
if (timer != null) {
out.writeInt(1);
out.writeString(ent.getKey());
timer.writeToParcel(out, uSecRealtime);
} 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, uSecRealtime);
}
} else {
out.writeInt(0);
}
}
public static final Parcelable.Creator CREATOR =
new Parcelable.Creator() {
public BatteryStatsImpl createFromParcel(Parcel in) {
return new BatteryStatsImpl(in);
}
public BatteryStatsImpl[] newArray(int size) {
return new BatteryStatsImpl[size];
}
};
public void prepareForDumpLocked() {
// Need to retrieve current kernel wake lock stats before printing.
pullPendingStateUpdatesLocked();
// Pull the clock time. This may update the time and make a new history entry
// if we had originally pulled a time before the RTC was set.
getStartClockTime();
}
public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
if (DEBUG) {
pw.println("mOnBatteryTimeBase:");
mOnBatteryTimeBase.dump(pw, " ");
pw.println("mOnBatteryScreenOffTimeBase:");
mOnBatteryScreenOffTimeBase.dump(pw, " ");
Printer pr = new PrintWriterPrinter(pw);
pr.println("*** Screen timer:");
mScreenOnTimer.logState(pr, " ");
for (int i=0; i