/*
* 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 android.annotation.Nullable;
import android.app.ActivityManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkStats;
import android.net.wifi.WifiActivityEnergyInfo;
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.SparseLongArray;
import android.util.TimeUtils;
import android.util.Xml;
import android.view.Display;
import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
import com.android.server.NetworkManagementSocketTagger;
import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
/**
* All information we are collecting about things that can happen that impact
* battery life. All times are represented in microseconds except where indicated
* otherwise.
*/
public final class BatteryStatsImpl extends BatteryStats {
private static final String TAG = "BatteryStatsImpl";
private static final boolean DEBUG = false;
public static final boolean DEBUG_ENERGY = false;
private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY || 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 = 130 + (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;
public final AtomicFile mDailyFile;
static final int MSG_UPDATE_WAKELOCKS = 1;
static final int MSG_REPORT_POWER_CHANGE = 2;
static final int MSG_REPORT_CHARGING = 3;
static final long DELAY_UPDATE_WAKELOCKS = 5*1000;
private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
private final KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader();
private final KernelCpuSpeedReader mKernelCpuSpeedReader = new KernelCpuSpeedReader();
public interface BatteryCallback {
public void batteryNeedsCpuUpdate();
public void batteryPowerChanged(boolean onBattery);
public void batterySendBroadcast(Intent intent);
}
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:
synchronized (BatteryStatsImpl.this) {
updateCpuTimeLocked();
}
if (cb != null) {
cb.batteryNeedsCpuUpdate();
}
break;
case MSG_REPORT_POWER_CHANGE:
if (cb != null) {
cb.batteryPowerChanged(msg.arg1 != 0);
}
break;
case MSG_REPORT_CHARGING:
if (cb != null) {
final String action;
synchronized (BatteryStatsImpl.this) {
action = mCharging ? BatteryManager.ACTION_CHARGING
: BatteryManager.ACTION_DISCHARGING;
}
Intent intent = new Intent(action);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
cb.batterySendBroadcast(intent);
}
break;
}
}
}
public interface ExternalStatsSync {
void scheduleSync(String reason);
void scheduleWifiSync(String reason);
void scheduleCpuSyncDueToRemovedUid(int uid);
}
public final MyHandler mHandler;
private final ExternalStatsSync mExternalSync;
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<BatteryStatsImpl.Uid> mUidStats =
new SparseArray<BatteryStatsImpl.Uid>();
// A set of pools of currently active timers. When a timer is queried, we will divide the
// elapsed time by the number of active timers to arrive at that timer's share of the time.
// In order to do this, we must refresh each timer whenever the number of active timers
// changes.
final ArrayList<StopwatchTimer> mPartialTimers = new ArrayList<>();
final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<>();
final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<>();
final ArrayList<StopwatchTimer> mDrawTimers = new ArrayList<>();
final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers = new SparseArray<>();
final ArrayList<StopwatchTimer> mWifiRunningTimers = new ArrayList<>();
final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<>();
final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<>();
final ArrayList<StopwatchTimer> mWifiScanTimers = new ArrayList<>();
final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers = new SparseArray<>();
final ArrayList<StopwatchTimer> mAudioTurnedOnTimers = new ArrayList<>();
final ArrayList<StopwatchTimer> mVideoTurnedOnTimers = new ArrayList<>();
final ArrayList<StopwatchTimer> mFlashlightTurnedOnTimers = new ArrayList<>();
final ArrayList<StopwatchTimer> mCameraTurnedOnTimers = new ArrayList<>();
// Last partial timers we use for distributing CPU usage.
final ArrayList<StopwatchTimer> 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<HistoryTag, Integer> mHistoryTagPool = new HashMap<>();
String[] mReadHistoryStrings;
int[] mReadHistoryUids;
int mReadHistoryChars;
int mNextHistoryTagIdx = 0;
int mNumHistoryTagChars = 0;
int mHistoryBufferLastPos = -1;
boolean mHistoryOverflow = false;
int mActiveHistoryStates = 0xffffffff;
int mActiveHistoryStates2 = 0xffffffff;
long mLastHistoryElapsedRealtime = 0;
long mTrackRunningHistoryElapsedRealtime = 0;
long mTrackRunningHistoryUptime = 0;
final HistoryItem mHistoryCur = new HistoryItem();
HistoryItem mHistory;
HistoryItem mHistoryEnd;
HistoryItem mHistoryLastEnd;
HistoryItem mHistoryCache;
// Used by computeHistoryStepDetails
HistoryStepDetails mLastHistoryStepDetails = null;
byte mLastHistoryStepLevel = 0;
final HistoryStepDetails mCurHistoryStepDetails = new HistoryStepDetails();
final HistoryStepDetails mReadHistoryStepDetails = new HistoryStepDetails();
final HistoryStepDetails mTmpHistoryStepDetails = new HistoryStepDetails();
/**
* Total time (in milliseconds) spent executing in user code.
*/
long mLastStepCpuUserTime;
long mCurStepCpuUserTime;
/**
* Total time (in milliseconds) spent executing in kernel code.
*/
long mLastStepCpuSystemTime;
long mCurStepCpuSystemTime;
/**
* Times from /proc/stat (but measured in milliseconds).
*/
long mLastStepStatUserTime;
long mLastStepStatSystemTime;
long mLastStepStatIOWaitTime;
long mLastStepStatIrqTime;
long mLastStepStatSoftIrqTime;
long mLastStepStatIdleTime;
long mCurStepStatUserTime;
long mCurStepStatSystemTime;
long mCurStepStatIOWaitTime;
long mCurStepStatIrqTime;
long mCurStepStatSoftIrqTime;
long mCurStepStatIdleTime;
private HistoryItem mHistoryIterator;
private boolean mReadOverflow;
private boolean mIteratingHistory;
int mStartCount;
long mStartClockTime;
String mStartPlatformVersion;
String mEndPlatformVersion;
long mUptime;
long mUptimeStart;
long mRealtime;
long mRealtimeStart;
int mWakeLockNesting;
boolean mWakeLockImportant;
public 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 mPowerSaveModeEnabled;
StopwatchTimer mPowerSaveModeEnabledTimer;
boolean mDeviceIdling;
StopwatchTimer mDeviceIdlingTimer;
boolean mDeviceIdleModeEnabled;
StopwatchTimer mDeviceIdleModeEnabledTimer;
boolean mPhoneOn;
StopwatchTimer mPhoneOnTimer;
int mAudioOnNesting;
StopwatchTimer mAudioOnTimer;
int mVideoOnNesting;
StopwatchTimer mVideoOnTimer;
int mFlashlightOnNesting;
StopwatchTimer mFlashlightOnTimer;
int mCameraOnNesting;
StopwatchTimer mCameraOnTimer;
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];
final LongSamplingCounter[] mBluetoothActivityCounters =
new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
final LongSamplingCounter[] mWifiActivityCounters =
new LongSamplingCounter[NUM_CONTROLLER_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];
int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
long mMobileRadioActiveStartTime;
StopwatchTimer mMobileRadioActiveTimer;
StopwatchTimer mMobileRadioActivePerAppTimer;
LongSamplingCounter mMobileRadioActiveAdjustedTime;
LongSamplingCounter mMobileRadioActiveUnknownTime;
LongSamplingCounter mMobileRadioActiveUnknownCount;
int mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
/**
* These provide time bases that discount the time the device is plugged
* in to power.
*/
boolean mOnBattery;
boolean mOnBatteryInternal;
/**
* External reporting of whether the device is actually charging.
*/
boolean mCharging = true;
int mLastChargingStateLevel;
/*
* 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;
int mMinDischargeStepLevel;
final LevelStepTracker mDischargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS);
final LevelStepTracker mDailyDischargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS*2);
ArrayList<PackageChange> mDailyPackageChanges;
int mLastChargeStepLevel;
int mMaxChargeStepLevel;
final LevelStepTracker mChargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS);
final LevelStepTracker mDailyChargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS*2);
static final int MAX_DAILY_ITEMS = 10;
long mDailyStartTime = 0;
long mNextMinDailyDeadline = 0;
long mNextMaxDailyDeadline = 0;
final ArrayList<DailyItem> mDailyItems = new ArrayList<>();
long mLastWriteTime = 0; // Milliseconds
private int mPhoneServiceState = -1;
private int mPhoneServiceStateRaw = -1;
private int mPhoneSimStateRaw = -1;
private int mNumConnectivityChange;
private int mLoadedNumConnectivityChange;
private int mUnpluggedNumConnectivityChange;
private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
private PowerProfile mPowerProfile;
private boolean mHasWifiEnergyReporting = false;
private boolean mHasBluetoothEnergyReporting = false;
/*
* Holds a SamplingTimer associated with each kernel wakelock name being tracked.
*/
private final HashMap<String, SamplingTimer> mKernelWakelockStats = new HashMap<>();
public Map<String, ? extends Timer> getKernelWakelockStats() {
return mKernelWakelockStats;
}
String mLastWakeupReason = null;
long mLastWakeupUptimeMs = 0;
private final HashMap<String, SamplingTimer> mWakeupReasonStats = new HashMap<>();
public Map<String, ? extends Timer> getWakeupReasonStats() {
return mWakeupReasonStats;
}
public BatteryStatsImpl() {
mFile = null;
mCheckinFile = null;
mDailyFile = null;
mHandler = null;
mExternalSync = 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<TimeBaseObs> 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 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;
/**
* The total time this timer has been running until the latest mark has been set.
* Subtract this from mTotalTime to get the time spent running since the mark was set.
*/
long mTimeBeforeMark;
/**
* 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();
mTimeBeforeMark = 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 = mTimeBeforeMark = 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);
out.writeLong(mTimeBeforeMark);
}
@Override
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);
}
}
@Override
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;
}
@Override
public long getTimeSinceMarkLocked(long elapsedRealtimeUs) {
long val = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
return val - mTimeBeforeMark;
}
@Override
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;
// When reading the summary, we set the mark to be the latest information.
mTimeBeforeMark = mTotalTime;
}
}
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<StopwatchTimer> mTimerPool;
int mNesting;
/**
* The last time at which we updated the timer. If mNesting is > 0,
* subtract this from the current battery time to find the amount of
* time we have been running since we last computed an update.
*/
long mUpdateTime;
/**
* The total time at which the timer was acquired, to determine if it
* was actually held for an interesting duration.
*/
long mAcquireTime;
long mTimeout;
/**
* For partial wake locks, keep track of whether we are in the list
* to consume CPU cycles.
*/
boolean mInList;
StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
TimeBase timeBase, Parcel in) {
super(type, timeBase, in);
mUid = uid;
mTimerPool = timerPool;
mUpdateTime = in.readLong();
}
StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> 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;
}
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<StopwatchTimer> 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;
}
@Override
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;
}
@Override
void detach() {
super.detach();
if (mTimerPool != null) {
mTimerPool.remove(this);
}
}
@Override
void readSummaryFromParcelLocked(Parcel in) {
super.readSummaryFromParcelLocked(in);
mNesting = 0;
}
/**
* Set the mark so that we can query later for the total time the timer has
* accumulated since this point. The timer can be running or not.
*
* @param elapsedRealtimeMs the current elapsed realtime in milliseconds.
*/
public void setMark(long elapsedRealtimeMs) {
final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
if (mNesting > 0) {
// We are running.
if (mTimerPool != null) {
refreshTimersLocked(batteryRealtime, mTimerPool, this);
} else {
mTotalTime += batteryRealtime - mUpdateTime;
mUpdateTime = batteryRealtime;
}
}
mTimeBeforeMark = mTotalTime;
}
}
public abstract class OverflowArrayMap<T> {
private static final String OVERFLOW_NAME = "*overflow*";
final ArrayMap<String, T> mMap = new ArrayMap<>();
T mCurOverflow;
ArrayMap<String, MutableInt> mActiveOverflow;
public OverflowArrayMap() {
}
public ArrayMap<String, T> 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;
}
/*
* 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 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;
// We use the low bit of the battery state int to indicate that we have full details
// from a battery level change.
static final int BATTERY_DELTA_LEVEL_FLAG = 0x00000001;
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 includeStepDetails = mLastHistoryStepLevel > cur.batteryLevel
? BATTERY_DELTA_LEVEL_FLAG : 0;
final boolean computeStepDetails = includeStepDetails != 0
|| mLastHistoryStepDetails == null;
final int batteryLevelInt = buildBatteryLevelInt(cur) | includeStepDetails;
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);
}
if (computeStepDetails) {
computeHistoryStepDetails(mCurHistoryStepDetails, mLastHistoryStepDetails);
if (includeStepDetails != 0) {
mCurHistoryStepDetails.writeToParcel(dest);
}
cur.stepDetails = mCurHistoryStepDetails;
mLastHistoryStepDetails = mCurHistoryStepDetails;
} else {
cur.stepDetails = null;
}
if (mLastHistoryStepLevel < cur.batteryLevel) {
mLastHistoryStepDetails = null;
}
mLastHistoryStepLevel = cur.batteryLevel;
}
private int buildBatteryLevelInt(HistoryItem h) {
return ((((int)h.batteryLevel)<<25)&0xfe000000)
| ((((int)h.batteryTemperature)<<14)&0x01ff8000)
| ((((int)h.batteryVoltage)<<1)&0x00007fff);
}
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)<<STATE_BATTERY_STATUS_SHIFT)
| ((h.batteryHealth&STATE_BATTERY_HEALTH_MASK)<<STATE_BATTERY_HEALTH_SHIFT)
| ((plugType&STATE_BATTERY_PLUG_MASK)<<STATE_BATTERY_PLUG_SHIFT)
| (h.states&(~DELTA_STATE_MASK));
}
private void computeHistoryStepDetails(final HistoryStepDetails out,
final HistoryStepDetails last) {
final HistoryStepDetails tmp = last != null ? mTmpHistoryStepDetails : out;
// Perform a CPU update right after we do this collection, so we have started
// collecting good data for the next step.
requestImmediateCpuUpdate();
if (last == null) {
// We are not generating a delta, so all we need to do is reset the stats
// we will later be doing a delta from.
final int NU = mUidStats.size();
for (int i=0; i<NU; i++) {
final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
uid.mLastStepUserTime = uid.mCurStepUserTime;
uid.mLastStepSystemTime = uid.mCurStepSystemTime;
}
mLastStepCpuUserTime = mCurStepCpuUserTime;
mLastStepCpuSystemTime = mCurStepCpuSystemTime;
mLastStepStatUserTime = mCurStepStatUserTime;
mLastStepStatSystemTime = mCurStepStatSystemTime;
mLastStepStatIOWaitTime = mCurStepStatIOWaitTime;
mLastStepStatIrqTime = mCurStepStatIrqTime;
mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime;
mLastStepStatIdleTime = mCurStepStatIdleTime;
tmp.clear();
return;
}
if (DEBUG) {
Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTime + " sys="
+ mLastStepStatSystemTime + " io=" + mLastStepStatIOWaitTime
+ " irq=" + mLastStepStatIrqTime + " sirq="
+ mLastStepStatSoftIrqTime + " idle=" + mLastStepStatIdleTime);
Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTime + " sys="
+ mCurStepStatSystemTime + " io=" + mCurStepStatIOWaitTime
+ " irq=" + mCurStepStatIrqTime + " sirq="
+ mCurStepStatSoftIrqTime + " idle=" + mCurStepStatIdleTime);
}
out.userTime = (int)(mCurStepCpuUserTime - mLastStepCpuUserTime);
out.systemTime = (int)(mCurStepCpuSystemTime - mLastStepCpuSystemTime);
out.statUserTime = (int)(mCurStepStatUserTime - mLastStepStatUserTime);
out.statSystemTime = (int)(mCurStepStatSystemTime - mLastStepStatSystemTime);
out.statIOWaitTime = (int)(mCurStepStatIOWaitTime - mLastStepStatIOWaitTime);
out.statIrqTime = (int)(mCurStepStatIrqTime - mLastStepStatIrqTime);
out.statSoftIrqTime = (int)(mCurStepStatSoftIrqTime - mLastStepStatSoftIrqTime);
out.statIdlTime = (int)(mCurStepStatIdleTime - mLastStepStatIdleTime);
out.appCpuUid1 = out.appCpuUid2 = out.appCpuUid3 = -1;
out.appCpuUTime1 = out.appCpuUTime2 = out.appCpuUTime3 = 0;
out.appCpuSTime1 = out.appCpuSTime2 = out.appCpuSTime3 = 0;
final int NU = mUidStats.size();
for (int i=0; i<NU; i++) {
final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
final int totalUTime = (int)(uid.mCurStepUserTime - uid.mLastStepUserTime);
final int totalSTime = (int)(uid.mCurStepSystemTime - uid.mLastStepSystemTime);
final int totalTime = totalUTime + totalSTime;
uid.mLastStepUserTime = uid.mCurStepUserTime;
uid.mLastStepSystemTime = uid.mCurStepSystemTime;
if (totalTime <= (out.appCpuUTime3+out.appCpuSTime3)) {
continue;
}
if (totalTime <= (out.appCpuUTime2+out.appCpuSTime2)) {
out.appCpuUid3 = uid.mUid;
out.appCpuUTime3 = totalUTime;
out.appCpuSTime3 = totalSTime;
} else {
out.appCpuUid3 = out.appCpuUid2;
out.appCpuUTime3 = out.appCpuUTime2;
out.appCpuSTime3 = out.appCpuSTime2;
if (totalTime <= (out.appCpuUTime1+out.appCpuSTime1)) {
out.appCpuUid2 = uid.mUid;
out.appCpuUTime2 = totalUTime;
out.appCpuSTime2 = totalSTime;
} else {
out.appCpuUid2 = out.appCpuUid1;
out.appCpuUTime2 = out.appCpuUTime1;
out.appCpuSTime2 = out.appCpuSTime1;
out.appCpuUid1 = uid.mUid;
out.appCpuUTime1 = totalUTime;
out.appCpuSTime1 = totalSTime;
}
}
}
mLastStepCpuUserTime = mCurStepCpuUserTime;
mLastStepCpuSystemTime = mCurStepCpuSystemTime;
mLastStepStatUserTime = mCurStepStatUserTime;
mLastStepStatSystemTime = mCurStepStatSystemTime;
mLastStepStatIOWaitTime = mCurStepStatIOWaitTime;
mLastStepStatIrqTime = mCurStepStatIrqTime;
mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime;
mLastStepStatIdleTime = mCurStepStatIdleTime;
}
public void readHistoryDelta(Parcel src, HistoryItem cur) {
int firstToken = src.readInt();
int deltaTimeToken = firstToken&DELTA_TIME_MASK;
cur.cmd = HistoryItem.CMD_UPDATE;
cur.numReadInts = 1;
if (DEBUG) Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)
+ " deltaTimeToken=" + deltaTimeToken);
if (deltaTimeToken < DELTA_TIME_ABS) {
cur.time += deltaTimeToken;
} else if (deltaTimeToken == DELTA_TIME_ABS) {
cur.time = src.readLong();
cur.numReadInts += 2;
if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time);
cur.readFromParcel(src);
return;
} else if (deltaTimeToken == DELTA_TIME_INT) {
int delta = src.readInt();
cur.time += delta;
cur.numReadInts += 1;
if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
} else {
long delta = src.readLong();
if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
cur.time += delta;
cur.numReadInts += 2;
}
final int batteryLevelInt;
if ((firstToken&DELTA_BATTERY_LEVEL_FLAG) != 0) {
batteryLevelInt = src.readInt();
cur.batteryLevel = (byte)((batteryLevelInt>>25)&0x7f);
cur.batteryTemperature = (short)((batteryLevelInt<<7)>>21);
cur.batteryVoltage = (char)(batteryLevelInt&0x3fff);
cur.numReadInts += 1;
if (DEBUG) Slog.i(TAG, "READ DELTA: batteryToken=0x"
+ Integer.toHexString(batteryLevelInt)
+ " batteryLevel=" + cur.batteryLevel
+ " batteryTemp=" + cur.batteryTemperature
+ " batteryVolt=" + (int)cur.batteryVoltage);
} else {
batteryLevelInt = 0;
}
if ((firstToken&DELTA_STATE_FLAG) != 0) {
int stateInt = src.readInt();
cur.states = (firstToken&DELTA_STATE_MASK) | (stateInt&(~DELTA_STATE_MASK));
cur.batteryStatus = (byte)((stateInt>>STATE_BATTERY_STATUS_SHIFT)
& STATE_BATTERY_STATUS_MASK);
cur.batteryHealth = (byte)((stateInt>>STATE_BATTERY_HEALTH_SHIFT)
& STATE_BATTERY_HEALTH_MASK);
cur.batteryPlugType = (byte)((stateInt>>STATE_BATTERY_PLUG_SHIFT)
& STATE_BATTERY_PLUG_MASK);
switch (cur.batteryPlugType) {
case 1:
cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_AC;
break;
case 2:
cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_USB;
break;
case 3:
cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
break;
}
cur.numReadInts += 1;
if (DEBUG) Slog.i(TAG, "READ DELTA: stateToken=0x"
+ Integer.toHexString(stateInt)
+ " batteryStatus=" + cur.batteryStatus
+ " batteryHealth=" + cur.batteryHealth
+ " batteryPlugType=" + cur.batteryPlugType
+ " states=0x" + Integer.toHexString(cur.states));
} else {
cur.states = (firstToken&DELTA_STATE_MASK) | (cur.states&(~DELTA_STATE_MASK));
}
if ((firstToken&DELTA_STATE2_FLAG) != 0) {
cur.states2 = src.readInt();
if (DEBUG) Slog.i(TAG, "READ DELTA: states2=0x"
+ Integer.toHexString(cur.states2));
}
if ((firstToken&DELTA_WAKELOCK_FLAG) != 0) {
int indexes = src.readInt();
int wakeLockIndex = indexes&0xffff;
int wakeReasonIndex = (indexes>>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;
}
if ((batteryLevelInt&BATTERY_DELTA_LEVEL_FLAG) != 0) {
cur.stepDetails = mReadHistoryStepDetails;
cur.stepDetails.readFromParcel(src);
} else {
cur.stepDetails = null;
}
}
@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&mActiveHistoryStates);
final int diffStates2 = mHistoryLastWritten.states2^(cur.states2&mActiveHistoryStates2);
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.stepDetails == 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;
}
// After overflow, we allow various bit-wise states to settle to 0.
boolean writeAnyway = false;
final int curStates = cur.states & HistoryItem.SETTLE_TO_ZERO_STATES
& mActiveHistoryStates;
if (mHistoryLastWritten.states != curStates) {
// mActiveHistoryStates keeps track of which bits in .states are now being
// forced to 0.
int old = mActiveHistoryStates;
mActiveHistoryStates &= curStates | ~HistoryItem.SETTLE_TO_ZERO_STATES;
writeAnyway |= old != mActiveHistoryStates;
}
final int curStates2 = cur.states2 & HistoryItem.SETTLE_TO_ZERO_STATES2
& mActiveHistoryStates2;
if (mHistoryLastWritten.states2 != curStates2) {
// mActiveHistoryStates2 keeps track of which bits in .states2 are now being
// forced to 0.
int old = mActiveHistoryStates2;
mActiveHistoryStates2 &= curStates2 | ~HistoryItem.SETTLE_TO_ZERO_STATES2;
writeAnyway |= old != mActiveHistoryStates2;
}
// 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 (!writeAnyway && 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();
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);
mHistoryLastWritten.states &= mActiveHistoryStates;
mHistoryLastWritten.states2 &= mActiveHistoryStates2;
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&mActiveHistoryStates) == 0
&& ((mHistoryEnd.states2^cur.states2)&mChangedStates2&mActiveHistoryStates2) == 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&mActiveHistoryStates);
mChangedStates2 |= mHistoryEnd.states^(cur.states2&mActiveHistoryStates2);
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&mActiveHistoryStates))
& HistoryItem.MOST_INTERESTING_STATES) == 0)) {
return;
}
}
addHistoryRecordLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE);
}
public 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;
mActiveHistoryStates = 0xffffffff;
mActiveHistoryStates2 = 0xffffffff;
}
public void updateTimeBasesLocked(boolean unplugged, boolean screenOff, long uptime,
long realtime) {
mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime);
boolean unpluggedScreenOff = unplugged && screenOff;
if (unpluggedScreenOff != mOnBatteryScreenOffTimeBase.isRunning()) {
updateKernelWakelocksLocked();
if (DEBUG_ENERGY_CPU) {
Slog.d(TAG, "Updating cpu time because screen is now " +
(unpluggedScreenOff ? "off" : "on"));
}
updateCpuTimeLocked();
mOnBatteryScreenOffTimeBase.setRunning(unpluggedScreenOff, uptime, realtime);
}
}
public void addIsolatedUidLocked(int isolatedUid, int appUid) {
mIsolatedUids.put(isolatedUid, appUid);
}
/**
* Schedules a read of the latest cpu times before removing the isolated UID.
* @see #removeIsolatedUidLocked(int)
*/
public void scheduleRemoveIsolatedUidLocked(int isolatedUid, int appUid) {
int curUid = mIsolatedUids.get(isolatedUid, -1);
if (curUid == appUid) {
if (mExternalSync != null) {
mExternalSync.scheduleCpuSyncDueToRemovedUid(isolatedUid);
}
}
}
/**
* This should only be called after the cpu times have been read.
* @see #scheduleRemoveIsolatedUidLocked(int, int)
*/
public void removeIsolatedUidLocked(int isolatedUid) {
mIsolatedUids.delete(isolatedUid);
mKernelUidCpuTimeReader.removeUid(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);
}
boolean ensureStartClockTime(final long currentTime) {
final long ABOUT_ONE_YEAR = 365*24*60*60*1000L;
if (currentTime > ABOUT_ONE_YEAR && mStartClockTime < (currentTime-ABOUT_ONE_YEAR)) {
// If the start clock time has changed by more than a year, then presumably
// the previous time was completely bogus. So we are going to figure out a
// new time based on how much time has elapsed since we started counting.
mStartClockTime = currentTime - (SystemClock.elapsedRealtime()-(mRealtimeStart/1000));
return true;
}
return false;
}
public void noteCurrentTimeChangedLocked() {
final long currentTime = System.currentTimeMillis();
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
recordCurrentTimeChangeLocked(currentTime, elapsedRealtime, uptime);
ensureStartClockTime(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 noteProcessCrashLocked(String name, int uid) {
uid = mapUid(uid);
if (isOnBattery()) {
Uid u = getUidStatsLocked(uid);
u.getProcessStatsLocked(name).incNumCrashesLocked();
}
}
public void noteProcessAnrLocked(String name, int uid) {
uid = mapUid(uid);
if (isOnBattery()) {
Uid u = getUidStatsLocked(uid);
u.getProcessStatsLocked(name).incNumAnrsLocked();
}
}
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);
}
public void noteAlarmStartLocked(String name, int uid) {
if (!mRecordAllHistory) {
return;
}
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_START, name, uid, 0)) {
return;
}
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ALARM_START, name, uid);
}
public void noteAlarmFinishLocked(String name, int uid) {
if (!mRecordAllHistory) {
return;
}
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_FINISH, name, uid, 0)) {
return;
}
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ALARM_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);
}
}
private void requestImmediateCpuUpdate() {
mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
mHandler.sendEmptyMessage(MSG_UPDATE_WAKELOCKS);
}
public void setRecordAllHistoryLocked(boolean enabled) {
mRecordAllHistory = enabled;
if (!enabled) {
// Clear out any existing state.
mActiveEvents.removeEvents(HistoryItem.EVENT_WAKE_LOCK);
mActiveEvents.removeEvents(HistoryItem.EVENT_ALARM);
// Record the currently running processes as stopping, now that we are no
// longer tracking them.
HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
HistoryItem.EVENT_PROC);
if (active != null) {
long mSecRealtime = SystemClock.elapsedRealtime();
final long mSecUptime = SystemClock.uptimeMillis();
for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
SparseIntArray uids = ent.getValue();
for (int j=0; j<uids.size(); j++) {
addHistoryEventLocked(mSecRealtime, mSecUptime,
HistoryItem.EVENT_PROC_FINISH, ent.getKey(), uids.keyAt(j));
}
}
}
} else {
// Record the currently running processes as starting, now that we are tracking them.
HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
HistoryItem.EVENT_PROC);
if (active != null) {
long mSecRealtime = SystemClock.elapsedRealtime();
final long mSecUptime = SystemClock.uptimeMillis();
for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
SparseIntArray uids = ent.getValue();
for (int j=0; j<uids.size(); j++) {
addHistoryEventLocked(mSecRealtime, mSecUptime,
HistoryItem.EVENT_PROC_START, ent.getKey(), uids.keyAt(j));
}
}
}
}
}
public void setNoAutoReset(boolean enabled) {
mNoAutoReset = enabled;
}
private String mInitialAcquireWakeName;
private int mInitialAcquireWakeUid = -1;
public void noteStartWakeLocked(int uid, int pid, String name, String historyName, int type,
boolean unimportantForLogging, long elapsedRealtime, long uptime) {
uid = mapUid(uid);
if (type == WAKE_TYPE_PARTIAL) {
// Only care about partial wake locks, since full wake locks
// will be canceled when the user puts the screen to sleep.
aggregateLastWakeupUptimeLocked(uptime);
if (historyName == null) {
historyName = name;
}
if (mRecordAllHistory) {
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
uid, 0)) {
addHistoryEventLocked(elapsedRealtime, uptime,
HistoryItem.EVENT_WAKE_LOCK_START, historyName, uid);
}
}
if (mWakeLockNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
+ Integer.toHexString(mHistoryCur.states));
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
mWakeLockImportant = !unimportantForLogging;
addHistoryRecordLocked(elapsedRealtime, uptime);
} else if (!mWakeLockImportant && !unimportantForLogging
&& mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE) {
if (mHistoryLastWritten.wakelockTag != null) {
// We'll try to update the last tag.
mHistoryLastWritten.wakelockTag = null;
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
addHistoryRecordLocked(elapsedRealtime, uptime);
}
mWakeLockImportant = true;
}
mWakeLockNesting++;
}
if (uid >= 0) {
if (mOnBatteryScreenOffTimeBase.isRunning()) {
// We only update the cpu time when a wake lock is acquired if the screen is off.
// If the screen is on, we don't distribute the power amongst partial wakelocks.
if (DEBUG_ENERGY_CPU) {
Slog.d(TAG, "Updating cpu time because of +wake_lock");
}
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) {
if (mOnBatteryScreenOffTimeBase.isRunning()) {
if (DEBUG_ENERGY_CPU) {
Slog.d(TAG, "Updating cpu time because of -wake_lock");
}
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<N; i++) {
noteStartWakeLocked(ws.get(i), pid, name, historyName, type, unimportantForLogging,
elapsedRealtime, uptime);
}
}
public void noteChangeWakelockFromSourceLocked(WorkSource ws, int pid, String name,
String historyName, int type, WorkSource newWs, int newPid, String newName,
String newHistoryName, int newType, boolean newUnimportantForLogging) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
// For correct semantics, we start the need worksources first, so that we won't
// make inappropriate history items as if all wake locks went away and new ones
// appeared. This is okay because tracking of wake locks allows nesting.
final int NN = newWs.size();
for (int i=0; i<NN; i++) {
noteStartWakeLocked(newWs.get(i), newPid, newName, newHistoryName, newType,
newUnimportantForLogging, elapsedRealtime, uptime);
}
final int NO = ws.size();
for (int i=0; i<NO; i++) {
noteStopWakeLocked(ws.get(i), pid, name, historyName, type, elapsedRealtime, uptime);
}
}
public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name,
String historyName, int type) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
final int N = ws.size();
for (int i=0; i<N; i++) {
noteStopWakeLocked(ws.get(i), pid, name, historyName, type, elapsedRealtime, uptime);
}
}
void aggregateLastWakeupUptimeLocked(long uptimeMs) {
if (mLastWakeupReason != null) {
long deltaUptime = uptimeMs - mLastWakeupUptimeMs;
SamplingTimer timer = getWakeupReasonTimerLocked(mLastWakeupReason);
timer.addCurrentReportedCount(1);
timer.addCurrentReportedTotalTime(deltaUptime * 1000); // time is in microseconds
mLastWakeupReason = null;
}
}
public void noteWakeupReasonLocked(String reason) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (DEBUG_HISTORY) Slog.v(TAG, "Wakeup reason \"" + reason +"\": "
+ Integer.toHexString(mHistoryCur.states));
aggregateLastWakeupUptimeLocked(uptime);
mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag;
mHistoryCur.wakeReasonTag.string = reason;
mHistoryCur.wakeReasonTag.uid = 0;
mLastWakeupReason = reason;
mLastWakeupUptimeMs = uptime;
addHistoryRecordLocked(elapsedRealtime, uptime);
}
public boolean startAddingCpuLocked() {
mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
return mOnBatteryInternal;
}
public void finishAddingCpuLocked(int totalUTime, int totalSTime, int statUserTime,
int statSystemTime, int statIOWaitTime, int statIrqTime,
int statSoftIrqTime, int statIdleTime) {
if (DEBUG) Slog.d(TAG, "Adding cpu: tuser=" + totalUTime + " tsys=" + totalSTime
+ " user=" + statUserTime + " sys=" + statSystemTime
+ " io=" + statIOWaitTime + " irq=" + statIrqTime
+ " sirq=" + statSoftIrqTime + " idle=" + statIdleTime);
mCurStepCpuUserTime += totalUTime;
mCurStepCpuSystemTime += totalSTime;
mCurStepStatUserTime += statUserTime;
mCurStepStatSystemTime += statSystemTime;
mCurStepStatIOWaitTime += statIOWaitTime;
mCurStepStatIrqTime += statIrqTime;
mCurStepStatSoftIrqTime += statSoftIrqTime;
mCurStepStatIdleTime += statIdleTime;
}
public void noteProcessDiedLocked(int uid, int pid) {
uid = mapUid(uid);
Uid u = mUidStats.get(uid);
if (u != null) {
u.mPids.remove(pid);
}
}
public long getProcessWakeTime(int uid, int pid, long realtime) {
uid = mapUid(uid);
Uid u = mUidStats.get(uid);
if (u != null) {
Uid.Pid p = u.mPids.get(pid);
if (p != null) {
return p.mWakeSumMs + (p.mWakeNesting > 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) {
recordDailyStatsIfNeededLocked(true);
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 noteWakeUpLocked(String reason, int reasonUid) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_SCREEN_WAKE_UP,
reason, reasonUid);
}
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 noteConnectivityChangedLocked(int type, String extra) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_CONNECTIVITY_CHANGED,
extra, type);
mNumConnectivityChange++;
}
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);
updateMobileRadioStateLocked(realElapsedRealtimeMs);
mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs);
}
}
}
public void notePowerSaveMode(boolean enabled) {
if (mPowerSaveModeEnabled != 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();
mPowerSaveModeEnabled = enabled;
if (enabled) {
mHistoryCur.states2 |= HistoryItem.STATE2_POWER_SAVE_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode enabled to: "
+ Integer.toHexString(mHistoryCur.states2));
mPowerSaveModeEnabledTimer.startRunningLocked(elapsedRealtime);
} else {
mHistoryCur.states2 &= ~HistoryItem.STATE2_POWER_SAVE_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode disabled to: "
+ Integer.toHexString(mHistoryCur.states2));
mPowerSaveModeEnabledTimer.stopRunningLocked(elapsedRealtime);
}
addHistoryRecordLocked(elapsedRealtime, uptime);
}
}
public void noteDeviceIdleModeLocked(boolean enabled, String activeReason, int activeUid) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
boolean nowIdling = enabled;
if (mDeviceIdling && !enabled && activeReason == null) {
// We don't go out of general idling mode until explicitly taken out of
// device idle through going active or significant motion.
nowIdling = true;
}
if (mDeviceIdling != nowIdling) {
mDeviceIdling = nowIdling;
int stepState = nowIdling ? STEP_LEVEL_MODE_DEVICE_IDLE : 0;
mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_DEVICE_IDLE) ^ stepState;
mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_DEVICE_IDLE) | stepState;
if (enabled) {
mDeviceIdlingTimer.startRunningLocked(elapsedRealtime);
} else {
mDeviceIdlingTimer.stopRunningLocked(elapsedRealtime);
}
}
if (mDeviceIdleModeEnabled != enabled) {
mDeviceIdleModeEnabled = enabled;
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ACTIVE,
activeReason != null ? activeReason : "", activeUid);
if (enabled) {
mHistoryCur.states2 |= HistoryItem.STATE2_DEVICE_IDLE_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Device idle mode enabled to: "
+ Integer.toHexString(mHistoryCur.states2));
mDeviceIdleModeEnabledTimer.startRunningLocked(elapsedRealtime);
} else {
mHistoryCur.states2 &= ~HistoryItem.STATE2_DEVICE_IDLE_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Device idle mode disabled to: "
+ Integer.toHexString(mHistoryCur.states2));
mDeviceIdleModeEnabledTimer.stopRunningLocked(elapsedRealtime);
}
addHistoryRecordLocked(elapsedRealtime, uptime);
}
}
public void notePackageInstalledLocked(String pkgName, int versionCode) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_INSTALLED,
pkgName, versionCode);
PackageChange pc = new PackageChange();
pc.mPackageName = pkgName;
pc.mUpdate = true;
pc.mVersionCode = versionCode;
addPackageChange(pc);
}
public void notePackageUninstalledLocked(String pkgName) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_UNINSTALLED,
pkgName, 0);
PackageChange pc = new PackageChange();
pc.mPackageName = pkgName;
pc.mUpdate = true;
addPackageChange(pc);
}
private void addPackageChange(PackageChange pc) {
if (mDailyPackageChanges == null) {
mDailyPackageChanges = new ArrayList<>();
}
mDailyPackageChanges.add(pc);
}
public void notePhoneOnLocked() {
if (!mPhoneOn) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mHistoryCur.states2 |= HistoryItem.STATE2_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.states2 &= ~HistoryItem.STATE2_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);
scheduleSyncExternalWifiStatsLocked("wifi-off");
}
}
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);
scheduleSyncExternalWifiStatsLocked("wifi-on");
}
}
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<mUidStats.size(); i++) {
BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
uid.noteResetAudioLocked(elapsedRealtime);
}
}
}
public void noteResetVideoLocked() {
if (mVideoOnNesting > 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<mUidStats.size(); i++) {
BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
uid.noteResetVideoLocked(elapsedRealtime);
}
}
}
public void noteActivityResumedLocked(int uid) {
uid = mapUid(uid);
getUidStatsLocked(uid).noteActivityResumedLocked(SystemClock.elapsedRealtime());
}
public void noteActivityPausedLocked(int uid) {
uid = mapUid(uid);
getUidStatsLocked(uid).noteActivityPausedLocked(SystemClock.elapsedRealtime());
}
public void noteVibratorOnLocked(int uid, long durationMillis) {
uid = mapUid(uid);
getUidStatsLocked(uid).noteVibratorOnLocked(durationMillis);
}
public void noteVibratorOffLocked(int uid) {
uid = mapUid(uid);
getUidStatsLocked(uid).noteVibratorOffLocked();
}
public void noteFlashlightOnLocked(int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (mFlashlightOnNesting++ == 0) {
mHistoryCur.states2 |= HistoryItem.STATE2_FLASHLIGHT_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight on to: "
+ Integer.toHexString(mHistoryCur.states2));
addHistoryRecordLocked(elapsedRealtime, uptime);
mFlashlightOnTimer.startRunningLocked(elapsedRealtime);
}
getUidStatsLocked(uid).noteFlashlightTurnedOnLocked(elapsedRealtime);
}
public void noteFlashlightOffLocked(int uid) {
if (mFlashlightOnNesting == 0) {
return;
}
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (--mFlashlightOnNesting == 0) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: "
+ Integer.toHexString(mHistoryCur.states2));
addHistoryRecordLocked(elapsedRealtime, uptime);
mFlashlightOnTimer.stopRunningLocked(elapsedRealtime);
}
getUidStatsLocked(uid).noteFlashlightTurnedOffLocked(elapsedRealtime);
}
public void noteCameraOnLocked(int uid) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (mCameraOnNesting++ == 0) {
mHistoryCur.states2 |= HistoryItem.STATE2_CAMERA_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Camera on to: "
+ Integer.toHexString(mHistoryCur.states2));
addHistoryRecordLocked(elapsedRealtime, uptime);
mCameraOnTimer.startRunningLocked(elapsedRealtime);
}
getUidStatsLocked(uid).noteCameraTurnedOnLocked(elapsedRealtime);
}
public void noteCameraOffLocked(int uid) {
if (mCameraOnNesting == 0) {
return;
}
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (--mCameraOnNesting == 0) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: "
+ Integer.toHexString(mHistoryCur.states2));
addHistoryRecordLocked(elapsedRealtime, uptime);
mCameraOnTimer.stopRunningLocked(elapsedRealtime);
}
getUidStatsLocked(uid).noteCameraTurnedOffLocked(elapsedRealtime);
}
public void noteResetCameraLocked() {
if (mCameraOnNesting > 0) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mCameraOnNesting = 0;
mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: "
+ Integer.toHexString(mHistoryCur.states2));
addHistoryRecordLocked(elapsedRealtime, uptime);
mCameraOnTimer.stopAllRunningLocked(elapsedRealtime);
for (int i=0; i<mUidStats.size(); i++) {
BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
uid.noteResetCameraLocked(elapsedRealtime);
}
}
}
public void noteResetFlashlightLocked() {
if (mFlashlightOnNesting > 0) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mFlashlightOnNesting = 0;
mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: "
+ Integer.toHexString(mHistoryCur.states2));
addHistoryRecordLocked(elapsedRealtime, uptime);
mFlashlightOnTimer.stopAllRunningLocked(elapsedRealtime);
for (int i=0; i<mUidStats.size(); i++) {
BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
uid.noteResetFlashlightLocked(elapsedRealtime);
}
}
}
public void noteWifiRadioPowerState(int powerState, long timestampNs) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
if (mWifiRadioPowerState != powerState) {
final boolean active =
powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
|| powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
if (active) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG;
} else {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG;
}
if (DEBUG_HISTORY) Slog.v(TAG, "Wifi network active " + active + " to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mWifiRadioPowerState = powerState;
}
}
public void noteWifiRunningLocked(WorkSource ws) {
if (!mGlobalWifiRunning) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_RUNNING_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mGlobalWifiRunning = true;
mGlobalWifiRunningTimer.startRunningLocked(elapsedRealtime);
int N = ws.size();
for (int i=0; i<N; i++) {
int uid = mapUid(ws.get(i));
getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
}
scheduleSyncExternalWifiStatsLocked("wifi-running");
} else {
Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
}
}
public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
if (mGlobalWifiRunning) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
int N = oldWs.size();
for (int i=0; i<N; i++) {
int uid = mapUid(oldWs.get(i));
getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
}
N = newWs.size();
for (int i=0; i<N; i++) {
int uid = mapUid(newWs.get(i));
getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
}
} else {
Log.w(TAG, "noteWifiRunningChangedLocked -- called while WIFI not running");
}
}
public void noteWifiStoppedLocked(WorkSource ws) {
if (mGlobalWifiRunning) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_RUNNING_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mGlobalWifiRunning = false;
mGlobalWifiRunningTimer.stopRunningLocked(elapsedRealtime);
int N = ws.size();
for (int i=0; i<N; i++) {
int uid = mapUid(ws.get(i));
getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
}
scheduleSyncExternalWifiStatsLocked("wifi-stopped");
} else {
Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
}
}
public void noteWifiStateLocked(int wifiState, String accessPoint) {
if (DEBUG) Log.i(TAG, "WiFi state -> " + wifiState);
if (mWifiState != wifiState) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
if (mWifiState >= 0) {
mWifiStateTimer[mWifiState].stopRunningLocked(elapsedRealtime);
}
mWifiState = wifiState;
mWifiStateTimer[wifiState].startRunningLocked(elapsedRealtime);
scheduleSyncExternalWifiStatsLocked("wifi-state");
}
}
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;
}
}
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<N; i++) {
noteFullWifiLockAcquiredLocked(ws.get(i));
}
}
public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteFullWifiLockReleasedLocked(ws.get(i));
}
}
public void noteWifiScanStartedFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteWifiScanStartedLocked(ws.get(i));
}
}
public void noteWifiScanStoppedFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteWifiScanStoppedLocked(ws.get(i));
}
}
public void noteWifiBatchedScanStartedFromSourceLocked(WorkSource ws, int csph) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteWifiBatchedScanStartedLocked(ws.get(i), csph);
}
}
public void noteWifiBatchedScanStoppedFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteWifiBatchedScanStoppedLocked(ws.get(i));
}
}
public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteWifiMulticastEnabledLocked(ws.get(i));
}
}
public void noteWifiMulticastDisabledFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
noteWifiMulticastDisabledLocked(ws.get(i));
}
}
private static String[] includeInStringArray(String[] array, String str) {
if (ArrayUtils.indexOf(array, str) >= 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.
final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
updateMobileRadioStateLocked(elapsedRealtimeMs);
updateWifiStateLocked(null);
}
@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 getPowerSaveModeEnabledTime(long elapsedRealtimeUs, int which) {
return mPowerSaveModeEnabledTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override public int getPowerSaveModeEnabledCount(int which) {
return mPowerSaveModeEnabledTimer.getCountLocked(which);
}
@Override public long getDeviceIdleModeEnabledTime(long elapsedRealtimeUs, int which) {
return mDeviceIdleModeEnabledTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override public int getDeviceIdleModeEnabledCount(int which) {
return mDeviceIdleModeEnabledTimer.getCountLocked(which);
}
@Override public long getDeviceIdlingTime(long elapsedRealtimeUs, int which) {
return mDeviceIdlingTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override public int getDeviceIdlingCount(int which) {
return mDeviceIdlingTimer.getCountLocked(which);
}
@Override public int getNumConnectivityChange(int which) {
int val = mNumConnectivityChange;
if (which == STATS_CURRENT) {
val -= mLoadedNumConnectivityChange;
} else if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedNumConnectivityChange;
}
return val;
}
@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 boolean hasBluetoothActivityReporting() {
return mHasBluetoothEnergyReporting;
}
@Override public long getBluetoothControllerActivity(int type, int which) {
if (type >= 0 && type < mBluetoothActivityCounters.length) {
return mBluetoothActivityCounters[type].getCountLocked(which);
}
return 0;
}
@Override public boolean hasWifiActivityReporting() {
return mHasWifiEnergyReporting;
}
@Override public long getWifiControllerActivity(int type, int which) {
if (type >= 0 && type < mWifiActivityCounters.length) {
return mWifiActivityCounters[type].getCountLocked(which);
}
return 0;
}
@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 getCameraOnTime(long elapsedRealtimeUs, int which) {
return mCameraOnTimer.getTotalTimeLocked(elapsedRealtimeUs, 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;
}
}
@Override public long getStartClockTime() {
final long currentTime = System.currentTimeMillis();
if (ensureStartClockTime(currentTime)) {
recordCurrentTimeChangeLocked(currentTime, 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<? extends BatteryStats.Uid> 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 mFlashlightTurnedOnTimer;
StopwatchTimer mCameraTurnedOnTimer;
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 amount of time this uid has kept the WiFi controller in idle, tx, and rx mode.
*/
LongSamplingCounter[] mWifiControllerTime =
new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
/**
* The amount of time this uid has kept the Bluetooth controller in idle, tx, and rx mode.
*/
LongSamplingCounter[] mBluetoothControllerTime =
new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
/**
* The CPU times we had at the last history details update.
*/
long mLastStepUserTime;
long mLastStepSystemTime;
long mCurStepUserTime;
long mCurStepSystemTime;
LongSamplingCounter mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
LongSamplingCounter mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
LongSamplingCounter mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase);
LongSamplingCounter[] mSpeedBins;
/**
* The statistics we have collected for this uid's wake locks.
*/
final OverflowArrayMap<Wakelock> mWakelockStats = new OverflowArrayMap<Wakelock>() {
@Override public Wakelock instantiateObject() { return new Wakelock(); }
};
/**
* The statistics we have collected for this uid's syncs.
*/
final OverflowArrayMap<StopwatchTimer> mSyncStats = new OverflowArrayMap<StopwatchTimer>() {
@Override public StopwatchTimer instantiateObject() {
return new StopwatchTimer(Uid.this, SYNC, null, mOnBatteryTimeBase);
}
};
/**
* The statistics we have collected for this uid's jobs.
*/
final OverflowArrayMap<StopwatchTimer> mJobStats = new OverflowArrayMap<StopwatchTimer>() {
@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<Sensor> mSensorStats = new SparseArray<>();
/**
* The statistics we have collected for this uid's processes.
*/
final ArrayMap<String, Proc> mProcessStats = new ArrayMap<>();
/**
* The statistics we have collected for this uid's processes.
*/
final ArrayMap<String, Pkg> mPackageStats = new ArrayMap<>();
/**
* The transient wake stats we have collected for this uid's pids.
*/
final SparseArray<Pid> 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];
mSpeedBins = new LongSamplingCounter[getCpuSpeedSteps()];
}
@Override
public ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
return mWakelockStats.getMap();
}
@Override
public ArrayMap<String, ? extends BatteryStats.Timer> getSyncStats() {
return mSyncStats.getMap();
}
@Override
public ArrayMap<String, ? extends BatteryStats.Timer> getJobStats() {
return mJobStats.getMap();
}
@Override
public SparseArray<? extends BatteryStats.Uid.Sensor> getSensorStats() {
return mSensorStats;
}
@Override
public ArrayMap<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
return mProcessStats;
}
@Override
public ArrayMap<String, ? extends BatteryStats.Uid.Pkg> 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-1) {
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 void noteWifiControllerActivityLocked(int type, long timeMs) {
if (mWifiControllerTime[type] == null) {
mWifiControllerTime[type] = new LongSamplingCounter(mOnBatteryTimeBase);
}
mWifiControllerTime[type].addCountLocked(timeMs);
}
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 createFlashlightTurnedOnTimerLocked() {
if (mFlashlightTurnedOnTimer == null) {
mFlashlightTurnedOnTimer = new StopwatchTimer(Uid.this, FLASHLIGHT_TURNED_ON,
mFlashlightTurnedOnTimers, mOnBatteryTimeBase);
}
return mFlashlightTurnedOnTimer;
}
public void noteFlashlightTurnedOnLocked(long elapsedRealtimeMs) {
createFlashlightTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
}
public void noteFlashlightTurnedOffLocked(long elapsedRealtimeMs) {
if (mFlashlightTurnedOnTimer != null) {
mFlashlightTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
}
}
public void noteResetFlashlightLocked(long elapsedRealtimeMs) {
if (mFlashlightTurnedOnTimer != null) {
mFlashlightTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
}
}
public StopwatchTimer createCameraTurnedOnTimerLocked() {
if (mCameraTurnedOnTimer == null) {
mCameraTurnedOnTimer = new StopwatchTimer(Uid.this, CAMERA_TURNED_ON,
mCameraTurnedOnTimers, mOnBatteryTimeBase);
}
return mCameraTurnedOnTimer;
}
public void noteCameraTurnedOnLocked(long elapsedRealtimeMs) {
createCameraTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
}
public void noteCameraTurnedOffLocked(long elapsedRealtimeMs) {
if (mCameraTurnedOnTimer != null) {
mCameraTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
}
}
public void noteResetCameraLocked(long elapsedRealtimeMs) {
if (mCameraTurnedOnTimer != null) {
mCameraTurnedOnTimer.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 int getWifiScanCount(int which) {
if (mWifiScanTimer == null) {
return 0;
}
return mWifiScanTimer.getCountLocked(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 int getWifiBatchedScanCount(int csphBin, int which) {
if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0;
if (mWifiBatchedScanTimer[csphBin] == null) {
return 0;
}
return mWifiBatchedScanTimer[csphBin].getCountLocked(which);
}
@Override
public long getWifiMulticastTime(long elapsedRealtimeUs, int which) {
if (mWifiMulticastTimer == null) {
return 0;
}
return mWifiMulticastTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override
public Timer getAudioTurnedOnTimer() {
return mAudioTurnedOnTimer;
}
@Override
public Timer getVideoTurnedOnTimer() {
return mVideoTurnedOnTimer;
}
@Override
public Timer getFlashlightTurnedOnTimer() {
return mFlashlightTurnedOnTimer;
}
@Override
public Timer getCameraTurnedOnTimer() {
return mCameraTurnedOnTimer;
}
@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<StopwatchTimer> collected = mWifiBatchedScanTimers.get(i);
if (collected == null) {
collected = new ArrayList<StopwatchTimer>();
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<NUM_USER_ACTIVITY_TYPES; i++) {
mUserActivityCounters[i] = new Counter(mOnBatteryTimeBase);
}
}
void noteNetworkActivityLocked(int type, long deltaBytes, long deltaPackets) {
if (mNetworkByteActivityCounters == null) {
initNetworkActivityLocked();
}
if (type >= 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;
}
@Override
public long getUserCpuTimeUs(int which) {
return mUserCpuTime.getCountLocked(which);
}
@Override
public long getSystemCpuTimeUs(int which) {
return mSystemCpuTime.getCountLocked(which);
}
@Override
public long getCpuPowerMaUs(int which) {
return mCpuPower.getCountLocked(which);
}
@Override
public long getTimeAtCpuSpeed(int step, int which) {
if (step >= 0 && step < mSpeedBins.length) {
if (mSpeedBins[step] != null) {
return mSpeedBins[step].getCountLocked(which);
}
}
return 0;
}
@Override
public long getWifiControllerActivity(int type, int which) {
if (type >= 0 && type < NUM_CONTROLLER_ACTIVITY_TYPES &&
mWifiControllerTime[type] != null) {
return mWifiControllerTime[type].getCountLocked(which);
}
return 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 (mFlashlightTurnedOnTimer != null) {
active |= !mFlashlightTurnedOnTimer.reset(false);
}
if (mCameraTurnedOnTimer != null) {
active |= !mCameraTurnedOnTimer.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<NUM_USER_ACTIVITY_TYPES; i++) {
mUserActivityCounters[i].reset(false);
}
}
if (mNetworkByteActivityCounters != null) {
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i].reset(false);
mNetworkPacketActivityCounters[i].reset(false);
}
mMobileRadioActiveTime.reset(false);
mMobileRadioActiveCount.reset(false);
}
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
if (mWifiControllerTime[i] != null) {
mWifiControllerTime[i].reset(false);
}
if (mBluetoothControllerTime[i] != null) {
mBluetoothControllerTime[i].reset(false);
}
}
mUserCpuTime.reset(false);
mSystemCpuTime.reset(false);
mCpuPower.reset(false);
for (int i = 0; i < mSpeedBins.length; i++) {
LongSamplingCounter c = mSpeedBins[i];
if (c != null) {
c.reset(false);
}
}
final ArrayMap<String, Wakelock> 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<String, StopwatchTimer> 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<String, StopwatchTimer> 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<Map.Entry<String, Pkg>> it = mPackageStats.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Pkg> pkgEntry = it.next();
Pkg p = pkgEntry.getValue();
p.detach();
if (p.mServiceStats.size() > 0) {
Iterator<Map.Entry<String, Pkg.Serv>> it2
= p.mServiceStats.entrySet().iterator();
while (it2.hasNext()) {
Map.Entry<String, Pkg.Serv> servEntry = it2.next();
servEntry.getValue().detach();
}
}
}
mPackageStats.clear();
}
mLastStepUserTime = mLastStepSystemTime = 0;
mCurStepUserTime = mCurStepSystemTime = 0;
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 (mFlashlightTurnedOnTimer != null) {
mFlashlightTurnedOnTimer.detach();
mFlashlightTurnedOnTimer = null;
}
if (mCameraTurnedOnTimer != null) {
mCameraTurnedOnTimer.detach();
mCameraTurnedOnTimer = null;
}
if (mForegroundActivityTimer != null) {
mForegroundActivityTimer.detach();
mForegroundActivityTimer = null;
}
if (mUserActivityCounters != null) {
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
mUserActivityCounters[i].detach();
}
}
if (mNetworkByteActivityCounters != null) {
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i].detach();
mNetworkPacketActivityCounters[i].detach();
}
}
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
if (mWifiControllerTime[i] != null) {
mWifiControllerTime[i].detach();
}
if (mBluetoothControllerTime[i] != null) {
mBluetoothControllerTime[i].detach();
}
}
mPids.clear();
mUserCpuTime.detach();
mSystemCpuTime.detach();
mCpuPower.detach();
for (int i = 0; i < mSpeedBins.length; i++) {
LongSamplingCounter c = mSpeedBins[i];
if (c != null) {
c.detach();
}
}
}
return !active;
}
void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
final ArrayMap<String, Wakelock> wakeStats = mWakelockStats.getMap();
int NW = wakeStats.size();
out.writeInt(NW);
for (int iw=0; iw<NW; iw++) {
out.writeString(wakeStats.keyAt(iw));
Uid.Wakelock wakelock = wakeStats.valueAt(iw);
wakelock.writeToParcelLocked(out, elapsedRealtimeUs);
}
final ArrayMap<String, StopwatchTimer> syncStats = mSyncStats.getMap();
int NS = syncStats.size();
out.writeInt(NS);
for (int is=0; is<NS; is++) {
out.writeString(syncStats.keyAt(is));
StopwatchTimer timer = syncStats.valueAt(is);
Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs);
}
final ArrayMap<String, StopwatchTimer> jobStats = mJobStats.getMap();
int NJ = jobStats.size();
out.writeInt(NJ);
for (int ij=0; ij<NJ; ij++) {
out.writeString(jobStats.keyAt(ij));
StopwatchTimer timer = jobStats.valueAt(ij);
Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs);
}
int NSE = mSensorStats.size();
out.writeInt(NSE);
for (int ise=0; ise<NSE; ise++) {
out.writeInt(mSensorStats.keyAt(ise));
Uid.Sensor sensor = mSensorStats.valueAt(ise);
sensor.writeToParcelLocked(out, elapsedRealtimeUs);
}
int NP = mProcessStats.size();
out.writeInt(NP);
for (int ip=0; ip<NP; ip++) {
out.writeString(mProcessStats.keyAt(ip));
Uid.Proc proc = mProcessStats.valueAt(ip);
proc.writeToParcelLocked(out);
}
out.writeInt(mPackageStats.size());
for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
out.writeString(pkgEntry.getKey());
Uid.Pkg pkg = pkgEntry.getValue();
pkg.writeToParcelLocked(out);
}
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 (mFlashlightTurnedOnTimer != null) {
out.writeInt(1);
mFlashlightTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs);
} else {
out.writeInt(0);
}
if (mCameraTurnedOnTimer != null) {
out.writeInt(1);
mCameraTurnedOnTimer.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<NUM_USER_ACTIVITY_TYPES; i++) {
mUserActivityCounters[i].writeToParcel(out);
}
} else {
out.writeInt(0);
}
if (mNetworkByteActivityCounters != null) {
out.writeInt(1);
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i].writeToParcel(out);
mNetworkPacketActivityCounters[i].writeToParcel(out);
}
mMobileRadioActiveTime.writeToParcel(out);
mMobileRadioActiveCount.writeToParcel(out);
} else {
out.writeInt(0);
}
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
if (mWifiControllerTime[i] != null) {
out.writeInt(1);
mWifiControllerTime[i].writeToParcel(out);
} else {
out.writeInt(0);
}
}
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
if (mBluetoothControllerTime[i] != null) {
out.writeInt(1);
mBluetoothControllerTime[i].writeToParcel(out);
} else {
out.writeInt(0);
}
}
mUserCpuTime.writeToParcel(out);
mSystemCpuTime.writeToParcel(out);
mCpuPower.writeToParcel(out);
out.writeInt(mSpeedBins.length);
for (int i = 0; i < mSpeedBins.length; i++) {
LongSamplingCounter c = mSpeedBins[i];
if (c != null) {
out.writeInt(1);
c.writeToParcel(out);
} else {
out.writeInt(0);
}
}
}
void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
int numWakelocks = in.readInt();
mWakelockStats.clear();
for (int j = 0; j < numWakelocks; j++) {
String wakelockName = in.readString();
Uid.Wakelock wakelock = new Wakelock();
wakelock.readFromParcelLocked(timeBase, screenOffTimeBase, in);
mWakelockStats.add(wakelockName, wakelock);
}
int numSyncs = in.readInt();
mSyncStats.clear();
for (int j = 0; j < numSyncs; j++) {
String syncName = in.readString();
if (in.readInt() != 0) {
mSyncStats.add(syncName,
new StopwatchTimer(Uid.this, SYNC, null, timeBase, in));
}
}
int numJobs = in.readInt();
mJobStats.clear();
for (int j = 0; j < numJobs; j++) {
String jobName = in.readString();
if (in.readInt() != 0) {
mJobStats.add(jobName, new StopwatchTimer(Uid.this, JOB, null, timeBase, in));
}
}
int numSensors = in.readInt();
mSensorStats.clear();
for (int k = 0; k < numSensors; k++) {
int sensorNumber = in.readInt();
Uid.Sensor sensor = new Sensor(sensorNumber);
sensor.readFromParcelLocked(mOnBatteryTimeBase, in);
mSensorStats.put(sensorNumber, sensor);
}
int numProcs = in.readInt();
mProcessStats.clear();
for (int k = 0; k < numProcs; k++) {
String processName = in.readString();
Uid.Proc proc = new Proc(processName);
proc.readFromParcelLocked(in);
mProcessStats.put(processName, proc);
}
int numPkgs = in.readInt();
mPackageStats.clear();
for (int l = 0; l < numPkgs; l++) {
String packageName = in.readString();
Uid.Pkg pkg = new Pkg();
pkg.readFromParcelLocked(in);
mPackageStats.put(packageName, pkg);
}
mWifiRunning = false;
if (in.readInt() != 0) {
mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
mWifiRunningTimers, mOnBatteryTimeBase, in);
} else {
mWifiRunningTimer = null;
}
mFullWifiLockOut = false;
if (in.readInt() != 0) {
mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
mFullWifiLockTimers, mOnBatteryTimeBase, in);
} else {
mFullWifiLockTimer = null;
}
mWifiScanStarted = false;
if (in.readInt() != 0) {
mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
mWifiScanTimers, mOnBatteryTimeBase, in);
} else {
mWifiScanTimer = null;
}
mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
if (in.readInt() != 0) {
makeWifiBatchedScanBin(i, in);
} else {
mWifiBatchedScanTimer[i] = null;
}
}
mWifiMulticastEnabled = false;
if (in.readInt() != 0) {
mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
mWifiMulticastTimers, mOnBatteryTimeBase, in);
} else {
mWifiMulticastTimer = null;
}
if (in.readInt() != 0) {
mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
mAudioTurnedOnTimers, mOnBatteryTimeBase, in);
} else {
mAudioTurnedOnTimer = null;
}
if (in.readInt() != 0) {
mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
mVideoTurnedOnTimers, mOnBatteryTimeBase, in);
} else {
mVideoTurnedOnTimer = null;
}
if (in.readInt() != 0) {
mFlashlightTurnedOnTimer = new StopwatchTimer(Uid.this, FLASHLIGHT_TURNED_ON,
mFlashlightTurnedOnTimers, mOnBatteryTimeBase, in);
} else {
mFlashlightTurnedOnTimer = null;
}
if (in.readInt() != 0) {
mCameraTurnedOnTimer = new StopwatchTimer(Uid.this, CAMERA_TURNED_ON,
mCameraTurnedOnTimers, mOnBatteryTimeBase, in);
} else {
mCameraTurnedOnTimer = null;
}
if (in.readInt() != 0) {
mForegroundActivityTimer = new StopwatchTimer(
Uid.this, FOREGROUND_ACTIVITY, null, mOnBatteryTimeBase, in);
} else {
mForegroundActivityTimer = null;
}
mProcessState = PROCESS_STATE_NONE;
for (int i = 0; i < NUM_PROCESS_STATE; i++) {
if (in.readInt() != 0) {
makeProcessState(i, in);
} else {
mProcessStateTimer[i] = null;
}
}
if (in.readInt() != 0) {
mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON, mOnBatteryTimeBase, in);
} else {
mVibratorOnTimer = null;
}
if (in.readInt() != 0) {
mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
mUserActivityCounters[i] = new Counter(mOnBatteryTimeBase, in);
}
} else {
mUserActivityCounters = null;
}
if (in.readInt() != 0) {
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, in);
mNetworkPacketActivityCounters[i]
= new LongSamplingCounter(mOnBatteryTimeBase, in);
}
mMobileRadioActiveTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
} else {
mNetworkByteActivityCounters = null;
mNetworkPacketActivityCounters = null;
}
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
if (in.readInt() != 0) {
mWifiControllerTime[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
} else {
mWifiControllerTime[i] = null;
}
}
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
if (in.readInt() != 0) {
mBluetoothControllerTime[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
} else {
mBluetoothControllerTime[i] = null;
}
}
mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase, in);
int bins = in.readInt();
int steps = getCpuSpeedSteps();
mSpeedBins = new LongSamplingCounter[bins >= steps ? bins : steps];
for (int i = 0; i < bins; i++) {
if (in.readInt() != 0) {
mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
}
}
}
/**
* The statistics associated with a particular wake lock.
*/
public final class Wakelock extends BatteryStats.Uid.Wakelock {
/**
* How long (in ms) this uid has been keeping the device partially awake.
*/
StopwatchTimer mTimerPartial;
/**
* How long (in ms) this uid has been keeping the device fully awake.
*/
StopwatchTimer mTimerFull;
/**
* How long (in ms) this uid has had a window keeping the device awake.
*/
StopwatchTimer mTimerWindow;
/**
* How long (in ms) this uid has had a draw wake lock.
*/
StopwatchTimer mTimerDraw;
/**
* Reads a possibly null Timer from a Parcel. The timer is associated with the
* proper timer pool from the given BatteryStatsImpl object.
*
* @param in the Parcel to be read from.
* return a new Timer, or null.
*/
private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
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 (mTimerDraw != null) {
wlactive |= !mTimerDraw.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;
}
if (mTimerDraw != null) {
mTimerDraw.detach();
mTimerDraw = 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);
mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mDrawTimers, timeBase, in);
}
void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
Timer.writeTimerToParcel(out, mTimerPartial, elapsedRealtimeUs);
Timer.writeTimerToParcel(out, mTimerFull, elapsedRealtimeUs);
Timer.writeTimerToParcel(out, mTimerWindow, elapsedRealtimeUs);
Timer.writeTimerToParcel(out, mTimerDraw, 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;
case WAKE_TYPE_DRAW: return mTimerDraw;
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;
case WAKE_TYPE_DRAW:
t = mTimerDraw;
if (t == null) {
t = new StopwatchTimer(Uid.this, WAKE_TYPE_DRAW,
mDrawTimers, mOnBatteryTimeBase);
mTimerDraw = 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<StopwatchTimer> pool = mSensorTimers.get(mHandle);
if (pool == null) {
pool = new ArrayList<StopwatchTimer>();
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 ms) spent executing in user code.
*/
long mUserTime;
/**
* Total time (in ms) spent executing in kernel code.
*/
long mSystemTime;
/**
* Amount of time (in ms) the process was running in the foreground.
*/
long mForegroundTime;
/**
* Number of times the process has been started.
*/
int mStarts;
/**
* Number of times the process has crashed.
*/
int mNumCrashes;
/**
* Number of times the process has had an ANR.
*/
int mNumAnrs;
/**
* 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;
/**
* Number of times the process has crashed from a previous save.
*/
int mLoadedNumCrashes;
/**
* Number of times the process has had an ANR from a previous save.
*/
int mLoadedNumAnrs;
/**
* 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;
/**
* Number of times the process has crashed before unplugged.
*/
int mUnpluggedNumCrashes;
/**
* Number of times the process has had an ANR before unplugged.
*/
int mUnpluggedNumAnrs;
/**
* Current process state.
*/
int mProcessState = PROCESS_STATE_NONE;
ArrayList<ExcessivePower> mExcessivePower;
Proc(String name) {
mName = name;
mOnBatteryTimeBase.add(this);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
mUnpluggedUserTime = mUserTime;
mUnpluggedSystemTime = mSystemTime;
mUnpluggedForegroundTime = mForegroundTime;
mUnpluggedStarts = mStarts;
mUnpluggedNumCrashes = mNumCrashes;
mUnpluggedNumAnrs = mNumAnrs;
}
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
}
void reset() {
mUserTime = mSystemTime = mForegroundTime = 0;
mStarts = mNumCrashes = mNumAnrs = 0;
mLoadedUserTime = mLoadedSystemTime = mLoadedForegroundTime = 0;
mLoadedStarts = mLoadedNumCrashes = mLoadedNumAnrs = 0;
mUnpluggedUserTime = mUnpluggedSystemTime = mUnpluggedForegroundTime = 0;
mUnpluggedStarts = mUnpluggedNumCrashes = mUnpluggedNumAnrs = 0;
mExcessivePower = null;
}
void detach() {
mActive = false;
mOnBatteryTimeBase.remove(this);
}
public int countExcessivePowers() {
return mExcessivePower != null ? mExcessivePower.size() : 0;
}
public ExcessivePower getExcessivePower(int i) {
if (mExcessivePower != null) {
return mExcessivePower.get(i);
}
return null;
}
public void addExcessiveWake(long overTime, long usedTime) {
if (mExcessivePower == null) {
mExcessivePower = new ArrayList<ExcessivePower>();
}
ExcessivePower ew = new ExcessivePower();
ew.type = ExcessivePower.TYPE_WAKE;
ew.overTime = overTime;
ew.usedTime = usedTime;
mExcessivePower.add(ew);
}
public void addExcessiveCpu(long overTime, long usedTime) {
if (mExcessivePower == null) {
mExcessivePower = new ArrayList<ExcessivePower>();
}
ExcessivePower ew = new ExcessivePower();
ew.type = ExcessivePower.TYPE_CPU;
ew.overTime = overTime;
ew.usedTime = usedTime;
mExcessivePower.add(ew);
}
void writeExcessivePowerToParcelLocked(Parcel out) {
if (mExcessivePower == null) {
out.writeInt(0);
return;
}
final int N = mExcessivePower.size();
out.writeInt(N);
for (int i=0; i<N; i++) {
ExcessivePower ew = mExcessivePower.get(i);
out.writeInt(ew.type);
out.writeLong(ew.overTime);
out.writeLong(ew.usedTime);
}
}
void readExcessivePowerFromParcelLocked(Parcel in) {
final int N = in.readInt();
if (N == 0) {
mExcessivePower = null;
return;
}
if (N > 10000) {
throw new ParcelFormatException(
"File corrupt: too many excessive power entries " + N);
}
mExcessivePower = new ArrayList<>();
for (int i=0; i<N; i++) {
ExcessivePower ew = new ExcessivePower();
ew.type = in.readInt();
ew.overTime = in.readLong();
ew.usedTime = in.readLong();
mExcessivePower.add(ew);
}
}
void writeToParcelLocked(Parcel out) {
out.writeLong(mUserTime);
out.writeLong(mSystemTime);
out.writeLong(mForegroundTime);
out.writeInt(mStarts);
out.writeInt(mNumCrashes);
out.writeInt(mNumAnrs);
out.writeLong(mLoadedUserTime);
out.writeLong(mLoadedSystemTime);
out.writeLong(mLoadedForegroundTime);
out.writeInt(mLoadedStarts);
out.writeInt(mLoadedNumCrashes);
out.writeInt(mLoadedNumAnrs);
out.writeLong(mUnpluggedUserTime);
out.writeLong(mUnpluggedSystemTime);
out.writeLong(mUnpluggedForegroundTime);
out.writeInt(mUnpluggedStarts);
out.writeInt(mUnpluggedNumCrashes);
out.writeInt(mUnpluggedNumAnrs);
writeExcessivePowerToParcelLocked(out);
}
void readFromParcelLocked(Parcel in) {
mUserTime = in.readLong();
mSystemTime = in.readLong();
mForegroundTime = in.readLong();
mStarts = in.readInt();
mNumCrashes = in.readInt();
mNumAnrs = in.readInt();
mLoadedUserTime = in.readLong();
mLoadedSystemTime = in.readLong();
mLoadedForegroundTime = in.readLong();
mLoadedStarts = in.readInt();
mLoadedNumCrashes = in.readInt();
mLoadedNumAnrs = in.readInt();
mUnpluggedUserTime = in.readLong();
mUnpluggedSystemTime = in.readLong();
mUnpluggedForegroundTime = in.readLong();
mUnpluggedStarts = in.readInt();
mUnpluggedNumCrashes = in.readInt();
mUnpluggedNumAnrs = in.readInt();
readExcessivePowerFromParcelLocked(in);
}
public void addCpuTimeLocked(int utime, int stime) {
mUserTime += utime;
mSystemTime += stime;
}
public void addForegroundTimeLocked(long ttime) {
mForegroundTime += ttime;
}
public void incStartsLocked() {
mStarts++;
}
public void incNumCrashesLocked() {
mNumCrashes++;
}
public void incNumAnrsLocked() {
mNumAnrs++;
}
@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;
}
@Override
public int getNumCrashes(int which) {
int val = mNumCrashes;
if (which == STATS_CURRENT) {
val -= mLoadedNumCrashes;
} else if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedNumCrashes;
}
return val;
}
@Override
public int getNumAnrs(int which) {
int val = mNumAnrs;
if (which == STATS_CURRENT) {
val -= mLoadedNumAnrs;
} else if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedNumAnrs;
}
return val;
}
}
/**
* The statistics associated with a particular package.
*/
public final class Pkg extends BatteryStats.Uid.Pkg implements TimeBaseObs {
/**
* Number of times wakeup alarms have occurred for this app.
*/
ArrayMap<String, Counter> mWakeupAlarms = new ArrayMap<>();
/**
* The statics we have collected for this package's services.
*/
final ArrayMap<String, Serv> mServiceStats = new ArrayMap<>();
Pkg() {
mOnBatteryScreenOffTimeBase.add(this);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
}
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
}
void detach() {
mOnBatteryScreenOffTimeBase.remove(this);
}
void readFromParcelLocked(Parcel in) {
int numWA = in.readInt();
mWakeupAlarms.clear();
for (int i=0; i<numWA; i++) {
String tag = in.readString();
mWakeupAlarms.put(tag, new Counter(mOnBatteryTimeBase, in));
}
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) {
int numWA = mWakeupAlarms.size();
out.writeInt(numWA);
for (int i=0; i<numWA; i++) {
out.writeString(mWakeupAlarms.keyAt(i));
mWakeupAlarms.valueAt(i).writeToParcel(out);
}
final int NS = mServiceStats.size();
out.writeInt(NS);
for (int i=0; i<NS; i++) {
out.writeString(mServiceStats.keyAt(i));
Uid.Pkg.Serv serv = mServiceStats.valueAt(i);
serv.writeToParcelLocked(out);
}
}
@Override
public ArrayMap<String, ? extends BatteryStats.Counter> getWakeupAlarmStats() {
return mWakeupAlarms;
}
public void noteWakeupAlarmLocked(String tag) {
Counter c = mWakeupAlarms.get(tag);
if (c == null) {
c = new Counter(mOnBatteryTimeBase);
mWakeupAlarms.put(tag, c);
}
c.stepAtomic();
}
@Override
public ArrayMap<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
return mServiceStats;
}
/**
* 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;
}
}
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<? extends Pid> getPidStats() {
return mPids;
}
public Pid getPidStatsLocked(int pid) {
Pid p = mPids.get(pid);
if (p == null) {
p = new Pid();
mPids.put(pid, p);
}
return p;
}
/**
* Retrieve the statistics object for a particular service, creating
* if needed.
*/
public Pkg getPackageStatsLocked(String name) {
Pkg ps = mPackageStats.get(name);
if (ps == null) {
ps = new Pkg();
mPackageStats.put(name, ps);
}
return ps;
}
/**
* Retrieve the statistics object for a particular service, creating
* if needed.
*/
public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
Pkg ps = getPackageStatsLocked(pkg);
Pkg.Serv ss = ps.mServiceStats.get(serv);
if (ss == null) {
ss = ps.newServiceStatsLocked();
ps.mServiceStats.put(serv, ss);
}
return ss;
}
public 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);
}
if (in.readInt() != 0) {
wl.getStopwatchTimer(WAKE_TYPE_DRAW).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<StopwatchTimer> timers = mSensorTimers.get(sensor);
if (timers == null) {
timers = new ArrayList<StopwatchTimer>();
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, ExternalStatsSync externalSync) {
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"));
mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml"));
mExternalSync = externalSync;
mHandler = new MyHandler(handler.getLooper());
mStartCount++;
mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase);
}
mInteractiveTimer = new StopwatchTimer(null, -10, null, mOnBatteryTimeBase);
mPowerSaveModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
mDeviceIdleModeEnabledTimer = new StopwatchTimer(null, -11, null, mOnBatteryTimeBase);
mDeviceIdlingTimer = new StopwatchTimer(null, -12, null, mOnBatteryTimeBase);
mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null,
mOnBatteryTimeBase);
}
mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null,
mOnBatteryTimeBase);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
}
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
}
mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase);
mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase);
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase);
mWifiOnTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase);
mGlobalWifiRunningTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_WIFI_STATES; i++) {
mWifiStateTimer[i] = new StopwatchTimer(null, -600-i, null, mOnBatteryTimeBase);
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
mWifiSupplStateTimer[i] = new StopwatchTimer(null, -700-i, null, mOnBatteryTimeBase);
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i, null,
mOnBatteryTimeBase);
}
mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase);
mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase);
mOnBattery = mOnBatteryInternal = false;
long uptime = SystemClock.uptimeMillis() * 1000;
long realtime = SystemClock.elapsedRealtime() * 1000;
initTimes(uptime, realtime);
mStartPlatformVersion = mEndPlatformVersion = Build.ID;
mDischargeStartLevel = 0;
mDischargeUnplugLevel = 0;
mDischargePlugLevel = -1;
mDischargeCurrentLevel = 0;
mCurrentBatteryLevel = 0;
initDischarge();
clearHistoryLocked();
updateDailyDeadlineLocked();
}
public BatteryStatsImpl(Parcel p) {
mFile = null;
mCheckinFile = null;
mDailyFile = null;
mHandler = null;
mExternalSync = null;
clearHistoryLocked();
readFromParcel(p);
}
public void setPowerProfile(PowerProfile profile) {
synchronized (this) {
mPowerProfile = profile;
}
}
public void setCallback(BatteryCallback cb) {
mCallback = cb;
}
public void setNumSpeedSteps(int steps) {
if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
}
public void setRadioScanningTimeout(long timeout) {
if (mPhoneSignalScanningTimer != null) {
mPhoneSignalScanningTimer.setTimeout(timeout);
}
}
public void updateDailyDeadlineLocked() {
// Get the current time.
long currentTime = mDailyStartTime = System.currentTimeMillis();
Calendar calDeadline = Calendar.getInstance();
calDeadline.setTimeInMillis(currentTime);
// Move time up to the next day, ranging from 1am to 3pm.
calDeadline.set(Calendar.DAY_OF_YEAR, calDeadline.get(Calendar.DAY_OF_YEAR) + 1);
calDeadline.set(Calendar.MILLISECOND, 0);
calDeadline.set(Calendar.SECOND, 0);
calDeadline.set(Calendar.MINUTE, 0);
calDeadline.set(Calendar.HOUR_OF_DAY, 1);
mNextMinDailyDeadline = calDeadline.getTimeInMillis();
calDeadline.set(Calendar.HOUR_OF_DAY, 3);
mNextMaxDailyDeadline = calDeadline.getTimeInMillis();
}
public void recordDailyStatsIfNeededLocked(boolean settled) {
long currentTime = System.currentTimeMillis();
if (currentTime >= mNextMaxDailyDeadline) {
recordDailyStatsLocked();
} else if (settled && currentTime >= mNextMinDailyDeadline) {
recordDailyStatsLocked();
} else if (currentTime < (mDailyStartTime-(1000*60*60*24))) {
recordDailyStatsLocked();
}
}
public void recordDailyStatsLocked() {
DailyItem item = new DailyItem();
item.mStartTime = mDailyStartTime;
item.mEndTime = System.currentTimeMillis();
boolean hasData = false;
if (mDailyDischargeStepTracker.mNumStepDurations > 0) {
hasData = true;
item.mDischargeSteps = new LevelStepTracker(
mDailyDischargeStepTracker.mNumStepDurations,
mDailyDischargeStepTracker.mStepDurations);
}
if (mDailyChargeStepTracker.mNumStepDurations > 0) {
hasData = true;
item.mChargeSteps = new LevelStepTracker(
mDailyChargeStepTracker.mNumStepDurations,
mDailyChargeStepTracker.mStepDurations);
}
if (mDailyPackageChanges != null) {
hasData = true;
item.mPackageChanges = mDailyPackageChanges;
mDailyPackageChanges = null;
}
mDailyDischargeStepTracker.init();
mDailyChargeStepTracker.init();
updateDailyDeadlineLocked();
if (hasData) {
mDailyItems.add(item);
while (mDailyItems.size() > MAX_DAILY_ITEMS) {
mDailyItems.remove(0);
}
final ByteArrayOutputStream memStream = new ByteArrayOutputStream();
try {
XmlSerializer out = new FastXmlSerializer();
out.setOutput(memStream, StandardCharsets.UTF_8.name());
writeDailyItemsLocked(out);
BackgroundThread.getHandler().post(new Runnable() {
@Override
public void run() {
synchronized (mCheckinFile) {
FileOutputStream stream = null;
try {
stream = mDailyFile.startWrite();
memStream.writeTo(stream);
stream.flush();
FileUtils.sync(stream);
stream.close();
mDailyFile.finishWrite(stream);
} catch (IOException e) {
Slog.w("BatteryStats",
"Error writing battery daily items", e);
mDailyFile.failWrite(stream);
}
}
}
});
} catch (IOException e) {
}
}
}
private void writeDailyItemsLocked(XmlSerializer out) throws IOException {
StringBuilder sb = new StringBuilder(64);
out.startDocument(null, true);
out.startTag(null, "daily-items");
for (int i=0; i<mDailyItems.size(); i++) {
final DailyItem dit = mDailyItems.get(i);
out.startTag(null, "item");
out.attribute(null, "start", Long.toString(dit.mStartTime));
out.attribute(null, "end", Long.toString(dit.mEndTime));
writeDailyLevelSteps(out, "dis", dit.mDischargeSteps, sb);
writeDailyLevelSteps(out, "chg", dit.mChargeSteps, sb);
if (dit.mPackageChanges != null) {
for (int j=0; j<dit.mPackageChanges.size(); j++) {
PackageChange pc = dit.mPackageChanges.get(j);
if (pc.mUpdate) {
out.startTag(null, "upd");
out.attribute(null, "pkg", pc.mPackageName);
out.attribute(null, "ver", Integer.toString(pc.mVersionCode));
out.endTag(null, "upd");
} else {
out.startTag(null, "rem");
out.attribute(null, "pkg", pc.mPackageName);
out.endTag(null, "rem");
}
}
}
out.endTag(null, "item");
}
out.endTag(null, "daily-items");
out.endDocument();
}
private void writeDailyLevelSteps(XmlSerializer out, String tag, LevelStepTracker steps,
StringBuilder tmpBuilder) throws IOException {
if (steps != null) {
out.startTag(null, tag);
out.attribute(null, "n", Integer.toString(steps.mNumStepDurations));
for (int i=0; i<steps.mNumStepDurations; i++) {
out.startTag(null, "s");
tmpBuilder.setLength(0);
steps.encodeEntryAt(i, tmpBuilder);
out.attribute(null, "v", tmpBuilder.toString());
out.endTag(null, "s");
}
out.endTag(null, tag);
}
}
public void readDailyStatsLocked() {
Slog.d(TAG, "Reading daily items from " + mDailyFile.getBaseFile());
mDailyItems.clear();
FileInputStream stream;
try {
stream = mDailyFile.openRead();
} catch (FileNotFoundException e) {
return;
}
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, StandardCharsets.UTF_8.name());
readDailyItemsLocked(parser);
} catch (XmlPullParserException e) {
} finally {
try {
stream.close();
} catch (IOException e) {
}
}
}
private void readDailyItemsLocked(XmlPullParser parser) {
try {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
;
}
if (type != XmlPullParser.START_TAG) {
throw new IllegalStateException("no start tag found");
}
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("item")) {
readDailyItemTagLocked(parser);
} else {
Slog.w(TAG, "Unknown element under <daily-items>: "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
} catch (IllegalStateException e) {
Slog.w(TAG, "Failed parsing daily " + e);
} catch (NullPointerException e) {
Slog.w(TAG, "Failed parsing daily " + e);
} catch (NumberFormatException e) {
Slog.w(TAG, "Failed parsing daily " + e);
} catch (XmlPullParserException e) {
Slog.w(TAG, "Failed parsing daily " + e);
} catch (IOException e) {
Slog.w(TAG, "Failed parsing daily " + e);
} catch (IndexOutOfBoundsException e) {
Slog.w(TAG, "Failed parsing daily " + e);
}
}
void readDailyItemTagLocked(XmlPullParser parser) throws NumberFormatException,
XmlPullParserException, IOException {
DailyItem dit = new DailyItem();
String attr = parser.getAttributeValue(null, "start");
if (attr != null) {
dit.mStartTime = Long.parseLong(attr);
}
attr = parser.getAttributeValue(null, "end");
if (attr != null) {
dit.mEndTime = Long.parseLong(attr);
}
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("dis")) {
readDailyItemTagDetailsLocked(parser, dit, false, "dis");
} else if (tagName.equals("chg")) {
readDailyItemTagDetailsLocked(parser, dit, true, "chg");
} else if (tagName.equals("upd")) {
if (dit.mPackageChanges == null) {
dit.mPackageChanges = new ArrayList<>();
}
PackageChange pc = new PackageChange();
pc.mUpdate = true;
pc.mPackageName = parser.getAttributeValue(null, "pkg");
String verStr = parser.getAttributeValue(null, "ver");
pc.mVersionCode = verStr != null ? Integer.parseInt(verStr) : 0;
dit.mPackageChanges.add(pc);
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("rem")) {
if (dit.mPackageChanges == null) {
dit.mPackageChanges = new ArrayList<>();
}
PackageChange pc = new PackageChange();
pc.mUpdate = false;
pc.mPackageName = parser.getAttributeValue(null, "pkg");
dit.mPackageChanges.add(pc);
XmlUtils.skipCurrentTag(parser);
} else {
Slog.w(TAG, "Unknown element under <item>: "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
mDailyItems.add(dit);
}
void readDailyItemTagDetailsLocked(XmlPullParser parser, DailyItem dit, boolean isCharge,
String tag)
throws NumberFormatException, XmlPullParserException, IOException {
final String numAttr = parser.getAttributeValue(null, "n");
if (numAttr == null) {
Slog.w(TAG, "Missing 'n' attribute at " + parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
return;
}
final int num = Integer.parseInt(numAttr);
LevelStepTracker steps = new LevelStepTracker(num);
if (isCharge) {
dit.mChargeSteps = steps;
} else {
dit.mDischargeSteps = steps;
}
int i = 0;
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if ("s".equals(tagName)) {
if (i < num) {
String valueAttr = parser.getAttributeValue(null, "v");
if (valueAttr != null) {
steps.decodeEntryAt(i, valueAttr);
i++;
}
}
} else {
Slog.w(TAG, "Unknown element under <" + tag + ">: "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
steps.mNumStepDurations = i;
}
@Override
public DailyItem getDailyItemLocked(int daysAgo) {
int index = mDailyItems.size()-1-daysAgo;
return index >= 0 ? mDailyItems.get(index) : null;
}
@Override
public long getCurrentDailyStartTime() {
return mDailyStartTime;
}
@Override
public long getNextMinDailyDeadline() {
return mNextMinDailyDeadline;
}
@Override
public long getNextMaxDailyDeadline() {
return mNextMaxDailyDeadline;
}
@Override
public boolean startIteratingOldHistoryLocked() {
if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
+ " pos=" + mHistoryBuffer.dataPosition());
if ((mHistoryIterator = mHistory) == null) {
return false;
}
mHistoryBuffer.setDataPosition(0);
mHistoryReadTmp.clear();
mReadOverflow = false;
mIteratingHistory = true;
return true;
}
@Override
public boolean getNextOldHistoryLocked(HistoryItem out) {
boolean end = mHistoryBuffer.dataPosition() >= mHistoryBuffer.dataSize();
if (!end) {
readHistoryDelta(mHistoryBuffer, mHistoryReadTmp);
mReadOverflow |= mHistoryReadTmp.cmd == HistoryItem.CMD_OVERFLOW;
}
HistoryItem cur = mHistoryIterator;
if (cur == null) {
if (!mReadOverflow && !end) {
Slog.w(TAG, "Old history ends before new history!");
}
return false;
}
out.setTo(cur);
mHistoryIterator = cur.next;
if (!mReadOverflow) {
if (end) {
Slog.w(TAG, "New history ends before old history!");
} else if (!out.same(mHistoryReadTmp)) {
PrintWriter pw = new FastPrintWriter(new LogWriter(android.util.Log.WARN, TAG));
pw.println("Histories differ!");
pw.println("Old history:");
(new HistoryPrinter()).printNextItem(pw, out, 0, false, true);
pw.println("New history:");
(new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, 0, false,
true);
pw.flush();
}
}
return true;
}
@Override
public void finishIteratingOldHistoryLocked() {
mIteratingHistory = false;
mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
mHistoryIterator = null;
}
public int getHistoryTotalSize() {
return MAX_HISTORY_BUFFER;
}
public int getHistoryUsedSize() {
return mHistoryBuffer.dataSize();
}
@Override
public boolean startIteratingHistoryLocked() {
if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
+ " pos=" + mHistoryBuffer.dataPosition());
if (mHistoryBuffer.dataSize() <= 0) {
return false;
}
mHistoryBuffer.setDataPosition(0);
mReadOverflow = false;
mIteratingHistory = true;
mReadHistoryStrings = new String[mHistoryTagPool.size()];
mReadHistoryUids = new int[mHistoryTagPool.size()];
mReadHistoryChars = 0;
for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
final HistoryTag tag = ent.getKey();
final int idx = ent.getValue();
mReadHistoryStrings[idx] = tag.string;
mReadHistoryUids[idx] = tag.uid;
mReadHistoryChars += tag.string.length() + 1;
}
return true;
}
@Override
public int getHistoryStringPoolSize() {
return mReadHistoryStrings.length;
}
@Override
public int getHistoryStringPoolBytes() {
// Each entry is a fixed 12 bytes: 4 for index, 4 for uid, 4 for string size
// Each string character is 2 bytes.
return (mReadHistoryStrings.length * 12) + (mReadHistoryChars * 2);
}
@Override
public String getHistoryTagPoolString(int index) {
return mReadHistoryStrings[index];
}
@Override
public int getHistoryTagPoolUid(int index) {
return mReadHistoryUids[index];
}
@Override
public boolean getNextHistoryLocked(HistoryItem out) {
final int pos = mHistoryBuffer.dataPosition();
if (pos == 0) {
out.clear();
}
boolean end = pos >= mHistoryBuffer.dataSize();
if (end) {
return false;
}
final long lastRealtime = out.time;
final long lastWalltime = out.currentTime;
readHistoryDelta(mHistoryBuffer, out);
if (out.cmd != HistoryItem.CMD_CURRENT_TIME
&& out.cmd != HistoryItem.CMD_RESET && lastWalltime != 0) {
out.currentTime = lastWalltime + (out.time - lastRealtime);
}
return true;
}
@Override
public void finishIteratingHistoryLocked() {
mIteratingHistory = false;
mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
mReadHistoryStrings = null;
}
@Override
public long getHistoryBaseTime() {
return mHistoryBaseTime;
}
@Override
public int getStartCount() {
return mStartCount;
}
public boolean isOnBattery() {
return mOnBattery;
}
public boolean isCharging() {
return mCharging;
}
public boolean isScreenOn() {
return mScreenState == Display.STATE_ON;
}
void initTimes(long uptime, long realtime) {
mStartClockTime = System.currentTimeMillis();
mOnBatteryTimeBase.init(uptime, realtime);
mOnBatteryScreenOffTimeBase.init(uptime, realtime);
mRealtime = 0;
mUptime = 0;
mRealtimeStart = realtime;
mUptimeStart = uptime;
}
void initDischarge() {
mLowDischargeAmountSinceCharge = 0;
mHighDischargeAmountSinceCharge = 0;
mDischargeAmountScreenOn = 0;
mDischargeAmountScreenOnSinceCharge = 0;
mDischargeAmountScreenOff = 0;
mDischargeAmountScreenOffSinceCharge = 0;
mDischargeStepTracker.init();
mChargeStepTracker.init();
}
public void resetAllStatsCmdLocked() {
resetAllStatsLocked();
final long mSecUptime = SystemClock.uptimeMillis();
long uptime = mSecUptime * 1000;
long mSecRealtime = SystemClock.elapsedRealtime();
long realtime = mSecRealtime * 1000;
mDischargeStartLevel = mHistoryCur.batteryLevel;
pullPendingStateUpdatesLocked();
addHistoryRecordLocked(mSecRealtime, mSecUptime);
mDischargeCurrentLevel = mDischargeUnplugLevel = mDischargePlugLevel
= mCurrentBatteryLevel = mHistoryCur.batteryLevel;
mOnBatteryTimeBase.reset(uptime, realtime);
mOnBatteryScreenOffTimeBase.reset(uptime, realtime);
if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) {
if (mScreenState == Display.STATE_ON) {
mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel;
mDischargeScreenOffUnplugLevel = 0;
} else {
mDischargeScreenOnUnplugLevel = 0;
mDischargeScreenOffUnplugLevel = mHistoryCur.batteryLevel;
}
mDischargeAmountScreenOn = 0;
mDischargeAmountScreenOff = 0;
}
initActiveHistoryEventsLocked(mSecRealtime, mSecUptime);
}
private void resetAllStatsLocked() {
mStartCount = 0;
initTimes(SystemClock.uptimeMillis() * 1000, SystemClock.elapsedRealtime() * 1000);
mScreenOnTimer.reset(false);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].reset(false);
}
mInteractiveTimer.reset(false);
mPowerSaveModeEnabledTimer.reset(false);
mDeviceIdleModeEnabledTimer.reset(false);
mDeviceIdlingTimer.reset(false);
mPhoneOnTimer.reset(false);
mAudioOnTimer.reset(false);
mVideoOnTimer.reset(false);
mFlashlightOnTimer.reset(false);
mCameraOnTimer.reset(false);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].reset(false);
}
mPhoneSignalScanningTimer.reset(false);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i].reset(false);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i].reset(false);
mNetworkPacketActivityCounters[i].reset(false);
}
mMobileRadioActiveTimer.reset(false);
mMobileRadioActivePerAppTimer.reset(false);
mMobileRadioActiveAdjustedTime.reset(false);
mMobileRadioActiveUnknownTime.reset(false);
mMobileRadioActiveUnknownCount.reset(false);
mWifiOnTimer.reset(false);
mGlobalWifiRunningTimer.reset(false);
for (int i=0; i<NUM_WIFI_STATES; i++) {
mWifiStateTimer[i].reset(false);
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
mWifiSupplStateTimer[i].reset(false);
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].reset(false);
}
for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mBluetoothActivityCounters[i].reset(false);
mWifiActivityCounters[i].reset(false);
}
mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0;
for (int i=0; i<mUidStats.size(); i++) {
if (mUidStats.valueAt(i).reset()) {
mUidStats.remove(mUidStats.keyAt(i));
i--;
}
}
if (mKernelWakelockStats.size() > 0) {
for (SamplingTimer timer : mKernelWakelockStats.values()) {
mOnBatteryScreenOffTimeBase.remove(timer);
}
mKernelWakelockStats.clear();
}
if (mWakeupReasonStats.size() > 0) {
for (SamplingTimer timer : mWakeupReasonStats.values()) {
mOnBatteryTimeBase.remove(timer);
}
mWakeupReasonStats.clear();
}
mLastHistoryStepDetails = null;
mLastStepCpuUserTime = mLastStepCpuSystemTime = 0;
mCurStepCpuUserTime = mCurStepCpuSystemTime = 0;
mLastStepCpuUserTime = mCurStepCpuUserTime = 0;
mLastStepCpuSystemTime = mCurStepCpuSystemTime = 0;
mLastStepStatUserTime = mCurStepStatUserTime = 0;
mLastStepStatSystemTime = mCurStepStatSystemTime = 0;
mLastStepStatIOWaitTime = mCurStepStatIOWaitTime = 0;
mLastStepStatIrqTime = mCurStepStatIrqTime = 0;
mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime = 0;
mLastStepStatIdleTime = mCurStepStatIdleTime = 0;
initDischarge();
clearHistoryLocked();
}
private void initActiveHistoryEventsLocked(long elapsedRealtimeMs, long uptimeMs) {
for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
if (!mRecordAllHistory && i == HistoryItem.EVENT_PROC) {
// Not recording process starts/stops.
continue;
}
HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(i);
if (active == null) {
continue;
}
for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
SparseIntArray uids = ent.getValue();
for (int j=0; j<uids.size(); j++) {
addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, i, ent.getKey(),
uids.keyAt(j));
}
}
}
}
void updateDischargeScreenLevelsLocked(boolean oldScreenOn, boolean newScreenOn) {
if (oldScreenOn) {
int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
if (diff > 0) {
mDischargeAmountScreenOn += diff;
mDischargeAmountScreenOnSinceCharge += diff;
}
} else {
int diff = mDischargeScreenOffUnplugLevel - mDischargeCurrentLevel;
if (diff > 0) {
mDischargeAmountScreenOff += diff;
mDischargeAmountScreenOffSinceCharge += diff;
}
}
if (newScreenOn) {
mDischargeScreenOnUnplugLevel = mDischargeCurrentLevel;
mDischargeScreenOffUnplugLevel = 0;
} else {
mDischargeScreenOnUnplugLevel = 0;
mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
}
}
public void pullPendingStateUpdatesLocked() {
if (mOnBatteryInternal) {
final boolean screenOn = mScreenState == Display.STATE_ON;
updateDischargeScreenLevelsLocked(screenOn, screenOn);
}
}
private String[] mMobileIfaces = EmptyArray.STRING;
private String[] mWifiIfaces = EmptyArray.STRING;
private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
private static final int NETWORK_STATS_LAST = 0;
private static final int NETWORK_STATS_NEXT = 1;
private static final int NETWORK_STATS_DELTA = 2;
private final NetworkStats[] mMobileNetworkStats = new NetworkStats[] {
new NetworkStats(SystemClock.elapsedRealtime(), 50),
new NetworkStats(SystemClock.elapsedRealtime(), 50),
new NetworkStats(SystemClock.elapsedRealtime(), 50)
};
private final NetworkStats[] mWifiNetworkStats = new NetworkStats[] {
new NetworkStats(SystemClock.elapsedRealtime(), 50),
new NetworkStats(SystemClock.elapsedRealtime(), 50),
new NetworkStats(SystemClock.elapsedRealtime(), 50)
};
/**
* Retrieves the delta of network stats for the given network ifaces. Uses networkStatsBuffer
* as a buffer of NetworkStats objects to cycle through when computing deltas.
*/
private NetworkStats getNetworkStatsDeltaLocked(String[] ifaces,
NetworkStats[] networkStatsBuffer)
throws IOException {
if (!SystemProperties.getBoolean(NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED,
false)) {
return null;
}
final NetworkStats stats = mNetworkStatsFactory.readNetworkStatsDetail(NetworkStats.UID_ALL,
ifaces, NetworkStats.TAG_NONE, networkStatsBuffer[NETWORK_STATS_NEXT]);
networkStatsBuffer[NETWORK_STATS_DELTA] = NetworkStats.subtract(stats,
networkStatsBuffer[NETWORK_STATS_LAST], null, null,
networkStatsBuffer[NETWORK_STATS_DELTA]);
networkStatsBuffer[NETWORK_STATS_NEXT] = networkStatsBuffer[NETWORK_STATS_LAST];
networkStatsBuffer[NETWORK_STATS_LAST] = stats;
return networkStatsBuffer[NETWORK_STATS_DELTA];
}
/**
* Distribute WiFi energy info and network traffic to apps.
* @param info The energy information from the WiFi controller.
*/
public void updateWifiStateLocked(@Nullable final WifiActivityEnergyInfo info) {
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating wifi stats");
}
final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
NetworkStats delta = null;
try {
if (!ArrayUtils.isEmpty(mWifiIfaces)) {
delta = getNetworkStatsDeltaLocked(mWifiIfaces, mWifiNetworkStats);
}
} catch (IOException e) {
Slog.wtf(TAG, "Failed to get wifi network stats", e);
return;
}
if (!mOnBatteryInternal) {
return;
}
SparseLongArray rxPackets = new SparseLongArray();
SparseLongArray txPackets = new SparseLongArray();
long totalTxPackets = 0;
long totalRxPackets = 0;
if (delta != null) {
final int size = delta.size();
for (int i = 0; i < size; i++) {
final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
if (DEBUG_ENERGY) {
Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes
+ " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets
+ " txPackets=" + entry.txPackets);
}
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);
rxPackets.put(u.getUid(), entry.rxPackets);
txPackets.put(u.getUid(), entry.txPackets);
// Sum the total number of packets so that the Rx Power and Tx Power can
// be evenly distributed amongst the apps.
totalRxPackets += entry.rxPackets;
totalTxPackets += 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);
}
}
if (info != null) {
mHasWifiEnergyReporting = true;
// Measured in mAms
final long txTimeMs = info.getControllerTxTimeMillis();
final long rxTimeMs = info.getControllerRxTimeMillis();
final long idleTimeMs = info.getControllerIdleTimeMillis();
final long totalTimeMs = txTimeMs + rxTimeMs + idleTimeMs;
long leftOverRxTimeMs = rxTimeMs;
long leftOverTxTimeMs = txTimeMs;
if (DEBUG_ENERGY) {
Slog.d(TAG, "------ BEGIN WiFi power blaming ------");
Slog.d(TAG, " Tx Time: " + txTimeMs + " ms");
Slog.d(TAG, " Rx Time: " + rxTimeMs + " ms");
Slog.d(TAG, " Idle Time: " + idleTimeMs + " ms");
Slog.d(TAG, " Total Time: " + totalTimeMs + " ms");
}
long totalWifiLockTimeMs = 0;
long totalScanTimeMs = 0;
// On the first pass, collect some totals so that we can normalize power
// calculations if we need to.
final int uidStatsSize = mUidStats.size();
for (int i = 0; i < uidStatsSize; i++) {
final Uid uid = mUidStats.valueAt(i);
// Sum the total scan power for all apps.
totalScanTimeMs += uid.mWifiScanTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
// Sum the total time holding wifi lock for all apps.
totalWifiLockTimeMs += uid.mFullWifiLockTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
}
if (DEBUG_ENERGY && totalScanTimeMs > rxTimeMs) {
Slog.d(TAG, " !Estimated scan time > Actual rx time (" + totalScanTimeMs + " ms > "
+ rxTimeMs + " ms). Normalizing scan time.");
}
if (DEBUG_ENERGY && totalScanTimeMs > txTimeMs) {
Slog.d(TAG, " !Estimated scan time > Actual tx time (" + totalScanTimeMs + " ms > "
+ txTimeMs + " ms). Normalizing scan time.");
}
// Actually assign and distribute power usage to apps.
for (int i = 0; i < uidStatsSize; i++) {
final Uid uid = mUidStats.valueAt(i);
long scanTimeSinceMarkMs = uid.mWifiScanTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
if (scanTimeSinceMarkMs > 0) {
// Set the new mark so that next time we get new data since this point.
uid.mWifiScanTimer.setMark(elapsedRealtimeMs);
long scanRxTimeSinceMarkMs = scanTimeSinceMarkMs;
long scanTxTimeSinceMarkMs = scanTimeSinceMarkMs;
// Our total scan time is more than the reported Tx/Rx time.
// This is possible because the cost of a scan is approximate.
// Let's normalize the result so that we evenly blame each app
// scanning.
//
// This means that we may have apps that transmitted/received packets not be
// blamed for this, but this is fine as scans are relatively more expensive.
if (totalScanTimeMs > rxTimeMs) {
scanRxTimeSinceMarkMs = (rxTimeMs * scanRxTimeSinceMarkMs) /
totalScanTimeMs;
}
if (totalScanTimeMs > txTimeMs) {
scanTxTimeSinceMarkMs = (txTimeMs * scanTxTimeSinceMarkMs) /
totalScanTimeMs;
}
if (DEBUG_ENERGY) {
Slog.d(TAG, " ScanTime for UID " + uid.getUid() + ": Rx:"
+ scanRxTimeSinceMarkMs + " ms Tx:"
+ scanTxTimeSinceMarkMs + " ms)");
}
uid.noteWifiControllerActivityLocked(CONTROLLER_RX_TIME, scanRxTimeSinceMarkMs);
uid.noteWifiControllerActivityLocked(CONTROLLER_TX_TIME, scanTxTimeSinceMarkMs);
leftOverRxTimeMs -= scanRxTimeSinceMarkMs;
leftOverTxTimeMs -= scanTxTimeSinceMarkMs;
}
// Distribute evenly the power consumed while Idle to each app holding a WiFi
// lock.
final long wifiLockTimeSinceMarkMs = uid.mFullWifiLockTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
if (wifiLockTimeSinceMarkMs > 0) {
// Set the new mark so that next time we get new data since this point.
uid.mFullWifiLockTimer.setMark(elapsedRealtimeMs);
final long myIdleTimeMs = (wifiLockTimeSinceMarkMs * idleTimeMs)
/ totalWifiLockTimeMs;
if (DEBUG_ENERGY) {
Slog.d(TAG, " IdleTime for UID " + uid.getUid() + ": "
+ myIdleTimeMs + " ms");
}
uid.noteWifiControllerActivityLocked(CONTROLLER_IDLE_TIME, myIdleTimeMs);
}
}
if (DEBUG_ENERGY) {
Slog.d(TAG, " New RxPower: " + leftOverRxTimeMs + " ms");
Slog.d(TAG, " New TxPower: " + leftOverTxTimeMs + " ms");
}
// Distribute the remaining Tx power appropriately between all apps that transmitted
// packets.
for (int i = 0; i < txPackets.size(); i++) {
final Uid uid = getUidStatsLocked(txPackets.keyAt(i));
final long myTxTimeMs = (txPackets.valueAt(i) * leftOverTxTimeMs) / totalTxPackets;
if (DEBUG_ENERGY) {
Slog.d(TAG, " TxTime for UID " + uid.getUid() + ": " + myTxTimeMs + " ms");
}
uid.noteWifiControllerActivityLocked(CONTROLLER_TX_TIME, myTxTimeMs);
}
// Distribute the remaining Rx power appropriately between all apps that received
// packets.
for (int i = 0; i < rxPackets.size(); i++) {
final Uid uid = getUidStatsLocked(rxPackets.keyAt(i));
final long myRxTimeMs = (rxPackets.valueAt(i) * leftOverRxTimeMs) / totalRxPackets;
if (DEBUG_ENERGY) {
Slog.d(TAG, " RxTime for UID " + uid.getUid() + ": " + myRxTimeMs + " ms");
}
uid.noteWifiControllerActivityLocked(CONTROLLER_RX_TIME, myRxTimeMs);
}
// Any left over power use will be picked up by the WiFi category in BatteryStatsHelper.
// Update WiFi controller stats.
mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
info.getControllerRxTimeMillis());
mWifiActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
info.getControllerTxTimeMillis());
mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
info.getControllerIdleTimeMillis());
// POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
final double opVolt = mPowerProfile.getAveragePower(
PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
if (opVolt != 0) {
// We store the power drain as mAms.
mWifiActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked(
(long)(info.getControllerEnergyUsed() / opVolt));
}
}
}
/**
* Distribute Cell radio energy info and network traffic to apps.
*/
public void updateMobileRadioStateLocked(final long elapsedRealtimeMs) {
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating mobile radio stats");
}
NetworkStats delta = null;
try {
if (!ArrayUtils.isEmpty(mMobileIfaces)) {
delta = getNetworkStatsDeltaLocked(mMobileIfaces, mMobileNetworkStats);
}
} catch (IOException e) {
Slog.wtf(TAG, "Failed to get mobile network stats", e);
return;
}
if (delta == null || !mOnBatteryInternal) {
return;
}
long radioTime = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000);
mMobileRadioActivePerAppTimer.setMark(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;
}
if (DEBUG_ENERGY) {
Slog.d(TAG, "Mobile uid " + entry.uid + ": delta rx=" + entry.rxBytes
+ " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets
+ " txPackets=" + entry.txPackets);
}
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);
}
}
/**
* Distribute Bluetooth energy info and network traffic to apps.
* @param info The energy information from the bluetooth controller.
*/
public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating bluetooth stats");
}
if (info != null && mOnBatteryInternal) {
mHasBluetoothEnergyReporting = true;
mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
info.getControllerRxTimeMillis());
mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
info.getControllerTxTimeMillis());
mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
info.getControllerIdleTimeMillis());
// POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
final double opVolt = mPowerProfile.getAveragePower(
PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
if (opVolt != 0) {
// We store the power drain as mAms.
mBluetoothActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked(
(long) (info.getControllerEnergyUsed() / opVolt));
}
}
}
/**
* Read and distribute kernel wake lock use across apps.
*/
public void updateKernelWakelocksLocked() {
final KernelWakelockStats wakelockStats = mKernelWakelockReader.readKernelWakelockStats(
mTmpWakelockStats);
if (wakelockStats == null) {
// Not crashing might make board bringup easier.
Slog.w(TAG, "Couldn't get kernel wake lock stats");
return;
}
// Record whether we've seen a non-zero time (for debugging b/22716723).
boolean seenNonZeroTime = false;
for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
String name = ent.getKey();
KernelWakelockStats.Entry 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(kws.mVersion);
if (kws.mVersion != wakelockStats.kernelWakelockVersion)
seenNonZeroTime |= kws.mTotalTime > 0;
}
int numWakelocksSetStale = 0;
if (wakelockStats.size() != mKernelWakelockStats.size()) {
// Set timers to stale if they didn't appear in /proc/wakelocks this time.
for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
SamplingTimer st = ent.getValue();
if (st.getUpdateVersion() != wakelockStats.kernelWakelockVersion) {
st.setStale();
numWakelocksSetStale++;
}
}
}
if (!seenNonZeroTime) {
Slog.wtf(TAG, "All kernel wakelocks had time of zero");
}
if (numWakelocksSetStale == mKernelWakelockStats.size()) {
Slog.wtf(TAG, "All kernel wakelocks were set stale. new version=" +
wakelockStats.kernelWakelockVersion);
}
}
// We use an anonymous class to access these variables,
// so they can't live on the stack or they'd have to be
// final MutableLong objects (more allocations).
// Used in updateCpuTimeLocked().
long mTempTotalCpuUserTimeUs;
long mTempTotalCpuSystemTimeUs;
/**
* Read and distribute CPU usage across apps. If their are partial wakelocks being held
* and we are on battery with screen off, we give more of the cpu time to those apps holding
* wakelocks. If the screen is on, we just assign the actual cpu time an app used.
*/
public void updateCpuTimeLocked() {
if (DEBUG_ENERGY_CPU) {
Slog.d(TAG, "!Cpu updating!");
}
// Holding a wakelock costs more than just using the cpu.
// Currently, we assign only half the cpu time to an app that is running but
// not holding a wakelock. The apps holding wakelocks get the rest of the blame.
// If no app is holding a wakelock, then the distribution is normal.
final int wakelockWeight = 50;
// Read the time spent at various cpu frequencies.
final int cpuSpeedSteps = getCpuSpeedSteps();
final long[] cpuSpeeds = mKernelCpuSpeedReader.readDelta();
int numWakelocks = 0;
// Calculate how many wakelocks we have to distribute amongst. The system is excluded.
// Only distribute cpu power to wakelocks if the screen is off and we're on battery.
final int numPartialTimers = mPartialTimers.size();
if (mOnBatteryScreenOffTimeBase.isRunning()) {
for (int i = 0; i < numPartialTimers; i++) {
final StopwatchTimer timer = mPartialTimers.get(i);
if (timer.mInList && timer.mUid != null && timer.mUid.mUid != Process.SYSTEM_UID) {
// Since the collection and blaming of wakelocks can be scheduled to run after
// some delay, the mPartialTimers list may have new entries. We can't blame
// the newly added timer for past cpu time, so we only consider timers that
// were present for one round of collection. Once a timer has gone through
// a round of collection, its mInList field is set to true.
numWakelocks++;
}
}
}
final int numWakelocksF = numWakelocks;
mTempTotalCpuUserTimeUs = 0;
mTempTotalCpuSystemTimeUs = 0;
// Read the CPU data for each UID. This will internally generate a snapshot so next time
// we read, we get a delta. If we are to distribute the cpu time, then do so. Otherwise
// we just ignore the data.
final long startTimeMs = SystemClock.elapsedRealtime();
mKernelUidCpuTimeReader.readDelta(!mOnBatteryInternal ? null :
new KernelUidCpuTimeReader.Callback() {
@Override
public void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs,
long powerMaUs) {
final Uid u = getUidStatsLocked(mapUid(uid));
// Accumulate the total system and user time.
mTempTotalCpuUserTimeUs += userTimeUs;
mTempTotalCpuSystemTimeUs += systemTimeUs;
StringBuilder sb = null;
if (DEBUG_ENERGY_CPU) {
sb = new StringBuilder();
sb.append(" got time for uid=").append(u.mUid).append(": u=");
TimeUtils.formatDuration(userTimeUs / 1000, sb);
sb.append(" s=");
TimeUtils.formatDuration(systemTimeUs / 1000, sb);
sb.append(" p=").append(powerMaUs / 1000).append("mAms\n");
}
if (numWakelocksF > 0) {
// We have wakelocks being held, so only give a portion of the
// time to the process. The rest will be distributed among wakelock
// holders.
userTimeUs = (userTimeUs * wakelockWeight) / 100;
systemTimeUs = (systemTimeUs * wakelockWeight) / 100;
}
if (sb != null) {
sb.append(" adding to uid=").append(u.mUid).append(": u=");
TimeUtils.formatDuration(userTimeUs / 1000, sb);
sb.append(" s=");
TimeUtils.formatDuration(systemTimeUs / 1000, sb);
sb.append(" p=").append(powerMaUs / 1000).append("mAms");
Slog.d(TAG, sb.toString());
}
u.mUserCpuTime.addCountLocked(userTimeUs);
u.mSystemCpuTime.addCountLocked(systemTimeUs);
u.mCpuPower.addCountLocked(powerMaUs);
// Add the cpu speeds to this UID. These are used as a ratio
// for computing the power this UID used.
for (int i = 0; i < cpuSpeedSteps; i++) {
if (u.mSpeedBins[i] == null) {
u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase);
}
u.mSpeedBins[i].addCountLocked(cpuSpeeds[i]);
}
}
});
if (DEBUG_ENERGY_CPU) {
Slog.d(TAG, "Reading cpu stats took " + (SystemClock.elapsedRealtime() - startTimeMs) +
" ms");
}
if (mOnBatteryInternal && numWakelocks > 0) {
// Distribute a portion of the total cpu time to wakelock holders.
mTempTotalCpuUserTimeUs = (mTempTotalCpuUserTimeUs * (100 - wakelockWeight)) / 100;
mTempTotalCpuSystemTimeUs =
(mTempTotalCpuSystemTimeUs * (100 - wakelockWeight)) / 100;
for (int i = 0; i < numPartialTimers; i++) {
final StopwatchTimer timer = mPartialTimers.get(i);
// The system does not share any blame, as it is usually holding the wakelock
// on behalf of an app.
if (timer.mInList && timer.mUid != null && timer.mUid.mUid != Process.SYSTEM_UID) {
int userTimeUs = (int) (mTempTotalCpuUserTimeUs / numWakelocks);
int systemTimeUs = (int) (mTempTotalCpuSystemTimeUs / numWakelocks);
if (DEBUG_ENERGY_CPU) {
StringBuilder sb = new StringBuilder();
sb.append(" Distributing wakelock uid=").append(timer.mUid.mUid)
.append(": u=");
TimeUtils.formatDuration(userTimeUs / 1000, sb);
sb.append(" s=");
TimeUtils.formatDuration(systemTimeUs / 1000, sb);
Slog.d(TAG, sb.toString());
}
timer.mUid.mUserCpuTime.addCountLocked(userTimeUs);
timer.mUid.mSystemCpuTime.addCountLocked(systemTimeUs);
final Uid.Proc proc = timer.mUid.getProcessStatsLocked("*wakelock*");
proc.addCpuTimeLocked(userTimeUs / 1000, systemTimeUs / 1000);
mTempTotalCpuUserTimeUs -= userTimeUs;
mTempTotalCpuSystemTimeUs -= systemTimeUs;
numWakelocks--;
}
}
if (mTempTotalCpuUserTimeUs > 0 || mTempTotalCpuSystemTimeUs > 0) {
// Anything left over is given to the system.
if (DEBUG_ENERGY_CPU) {
StringBuilder sb = new StringBuilder();
sb.append(" Distributing lost time to system: u=");
TimeUtils.formatDuration(mTempTotalCpuUserTimeUs / 1000, sb);
sb.append(" s=");
TimeUtils.formatDuration(mTempTotalCpuSystemTimeUs / 1000, sb);
Slog.d(TAG, sb.toString());
}
final Uid u = getUidStatsLocked(Process.SYSTEM_UID);
u.mUserCpuTime.addCountLocked(mTempTotalCpuUserTimeUs);
u.mSystemCpuTime.addCountLocked(mTempTotalCpuSystemTimeUs);
final Uid.Proc proc = u.getProcessStatsLocked("*lost*");
proc.addCpuTimeLocked((int) mTempTotalCpuUserTimeUs / 1000,
(int) mTempTotalCpuSystemTimeUs / 1000);
}
}
// See if there is a difference in wakelocks between this collection and the last
// collection.
if (ArrayUtils.referenceEquals(mPartialTimers, mLastPartialTimers)) {
// No difference, so each timer is now considered for the next collection.
for (int i = 0; i < numPartialTimers; i++) {
mPartialTimers.get(i).mInList = true;
}
} else {
// The lists are different, meaning we added (or removed a timer) since the last
// collection.
final int numLastPartialTimers = mLastPartialTimers.size();
for (int i = 0; i < numLastPartialTimers; i++) {
mLastPartialTimers.get(i).mInList = false;
}
mLastPartialTimers.clear();
// Mark the current timers as gone through a collection.
for (int i = 0; i < numPartialTimers; i++) {
final StopwatchTimer timer = mPartialTimers.get(i);
timer.mInList = true;
mLastPartialTimers.add(timer);
}
}
}
boolean setChargingLocked(boolean charging) {
if (mCharging != charging) {
mCharging = charging;
if (charging) {
mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
} else {
mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG;
}
mHandler.sendEmptyMessage(MSG_REPORT_CHARGING);
return true;
}
return false;
}
void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery,
final int oldStatus, final int level) {
boolean doWrite = false;
Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
m.arg1 = onBattery ? 1 : 0;
mHandler.sendMessage(m);
final long uptime = mSecUptime * 1000;
final long realtime = mSecRealtime * 1000;
final boolean screenOn = mScreenState == Display.STATE_ON;
if (onBattery) {
// We will reset our status if we are unplugging after the
// battery was last full, or the level is at 100, or
// we have gone through a significant charge (from a very low
// level to a now very high level).
boolean reset = false;
if (!mNoAutoReset && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
|| level >= 90
|| (mDischargeCurrentLevel < 20 && level >= 80)
|| (getHighDischargeAmountSinceCharge() >= 200
&& mHistoryBuffer.dataSize() >= MAX_HISTORY_BUFFER))) {
Slog.i(TAG, "Resetting battery stats: level=" + level + " status=" + oldStatus
+ " dischargeLevel=" + mDischargeCurrentLevel
+ " lowAmount=" + getLowDischargeAmountSinceCharge()
+ " highAmount=" + getHighDischargeAmountSinceCharge());
// Before we write, collect a snapshot of the final aggregated
// stats to be reported in the next checkin. Only do this if we have
// a sufficient amount of data to make it interesting.
if (getLowDischargeAmountSinceCharge() >= 20) {
final Parcel parcel = Parcel.obtain();
writeSummaryToParcel(parcel, true);
BackgroundThread.getHandler().post(new Runnable() {
@Override public void run() {
synchronized (mCheckinFile) {
FileOutputStream stream = null;
try {
stream = mCheckinFile.startWrite();
stream.write(parcel.marshall());
stream.flush();
FileUtils.sync(stream);
stream.close();
mCheckinFile.finishWrite(stream);
} catch (IOException e) {
Slog.w("BatteryStats",
"Error writing checkin battery statistics", e);
mCheckinFile.failWrite(stream);
} finally {
parcel.recycle();
}
}
}
});
}
doWrite = true;
resetAllStatsLocked();
mDischargeStartLevel = level;
reset = true;
mDischargeStepTracker.init();
}
if (mCharging) {
setChargingLocked(false);
}
mLastChargingStateLevel = level;
mOnBattery = mOnBatteryInternal = true;
mLastDischargeStepLevel = level;
mMinDischargeStepLevel = level;
mDischargeStepTracker.clearTime();
mDailyDischargeStepTracker.clearTime();
mInitStepMode = mCurStepMode;
mModStepMode = 0;
pullPendingStateUpdatesLocked();
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
+ Integer.toHexString(mHistoryCur.states));
if (reset) {
mRecordingHistory = true;
startRecordingHistory(mSecRealtime, mSecUptime, reset);
}
addHistoryRecordLocked(mSecRealtime, mSecUptime);
mDischargeCurrentLevel = mDischargeUnplugLevel = level;
if (screenOn) {
mDischargeScreenOnUnplugLevel = level;
mDischargeScreenOffUnplugLevel = 0;
} else {
mDischargeScreenOnUnplugLevel = 0;
mDischargeScreenOffUnplugLevel = level;
}
mDischargeAmountScreenOn = 0;
mDischargeAmountScreenOff = 0;
updateTimeBasesLocked(true, !screenOn, uptime, realtime);
} else {
mLastChargingStateLevel = level;
mOnBattery = mOnBatteryInternal = false;
pullPendingStateUpdatesLocked();
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(mSecRealtime, mSecUptime);
mDischargeCurrentLevel = mDischargePlugLevel = level;
if (level < mDischargeUnplugLevel) {
mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
}
updateDischargeScreenLevelsLocked(screenOn, screenOn);
updateTimeBasesLocked(false, !screenOn, uptime, realtime);
mChargeStepTracker.init();
mLastChargeStepLevel = level;
mMaxChargeStepLevel = level;
mInitStepMode = mCurStepMode;
mModStepMode = 0;
}
if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
if (mFile != null) {
writeAsyncLocked();
}
}
}
private void startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs,
boolean reset) {
mRecordingHistory = true;
mHistoryCur.currentTime = System.currentTimeMillis();
addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs,
reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME,
mHistoryCur);
mHistoryCur.currentTime = 0;
if (reset) {
initActiveHistoryEventsLocked(elapsedRealtimeMs, uptimeMs);
}
}
private void recordCurrentTimeChangeLocked(final long currentTime, final long elapsedRealtimeMs,
final long uptimeMs) {
if (mRecordingHistory) {
mHistoryCur.currentTime = currentTime;
addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_CURRENT_TIME,
mHistoryCur);
mHistoryCur.currentTime = 0;
}
}
private void recordShutdownLocked(final long elapsedRealtimeMs, final long uptimeMs) {
if (mRecordingHistory) {
mHistoryCur.currentTime = System.currentTimeMillis();
addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_SHUTDOWN,
mHistoryCur);
mHistoryCur.currentTime = 0;
}
}
private void scheduleSyncExternalStatsLocked(String reason) {
if (mExternalSync != null) {
mExternalSync.scheduleSync(reason);
}
}
private void scheduleSyncExternalWifiStatsLocked(String reason) {
if (mExternalSync != null) {
mExternalSync.scheduleWifiSync(reason);
}
}
// This should probably be exposed in the API, though it's not critical
public static final int BATTERY_PLUGGED_NONE = 0;
public void setBatteryStateLocked(int status, int health, int plugType, int level,
int temp, int volt) {
final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
final long uptime = SystemClock.uptimeMillis();
final long elapsedRealtime = SystemClock.elapsedRealtime();
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;
}
}
// Always start out assuming charging, that will be updated later.
mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
mHistoryCur.batteryStatus = (byte)status;
mHistoryCur.batteryLevel = (byte)level;
mMaxChargeStepLevel = mMinDischargeStepLevel =
mLastChargeStepLevel = mLastDischargeStepLevel = level;
mLastChargingStateLevel = level;
} else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) {
recordDailyStatsIfNeededLocked(level >= 100 && onBattery);
}
int oldStatus = mHistoryCur.batteryStatus;
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;
// TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record
// which will pull external stats.
scheduleSyncExternalStatsLocked("battery-level");
}
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;
}
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) {
changed |= setChargingLocked(false);
if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
modeBits, elapsedRealtime);
mDailyDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
modeBits, elapsedRealtime);
mLastDischargeStepLevel = level;
mMinDischargeStepLevel = level;
mInitStepMode = mCurStepMode;
mModStepMode = 0;
}
} else {
if (level >= 90) {
// If the battery level is at least 90%, always consider the device to be
// charging even if it happens to go down a level.
changed |= setChargingLocked(true);
mLastChargeStepLevel = level;
} if (!mCharging) {
if (mLastChargeStepLevel < level) {
// We have not reporting that we are charging, but the level has now
// gone up, so consider the state to be charging.
changed |= setChargingLocked(true);
mLastChargeStepLevel = level;
}
} else {
if (mLastChargeStepLevel > level) {
// We had reported that the device was charging, but here we are with
// power connected and the level going down. Looks like the current
// power supplied isn't enough, so consider the device to now be
// discharging.
changed |= setChargingLocked(false);
mLastChargeStepLevel = level;
}
}
if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
modeBits, elapsedRealtime);
mDailyChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
modeBits, elapsedRealtime);
mLastChargeStepLevel = level;
mMaxChargeStepLevel = level;
mInitStepMode = mCurStepMode;
mModStepMode = 0;
}
}
if (changed) {
addHistoryRecordLocked(elapsedRealtime, uptime);
}
}
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 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<numSteps; i++) {
total += steps[i] & STEP_LEVEL_TIME_MASK;
}
return total / numSteps;
/*
long[] buckets = new long[numSteps];
int numBuckets = 0;
int numToAverage = 4;
int i = 0;
while (i < numSteps) {
long totalTime = 0;
int num = 0;
for (int j=0; j<numToAverage && (i+j)<numSteps; j++) {
totalTime += steps[i+j] & STEP_LEVEL_TIME_MASK;
num++;
}
buckets[numBuckets] = totalTime / num;
numBuckets++;
numToAverage *= 2;
i += num;
}
if (numBuckets < 1) {
return -1;
}
long averageTime = buckets[numBuckets-1];
for (i=numBuckets-2; 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 (mDischargeStepTracker.mNumStepDurations < 1) {
return -1;
}
long msPerLevel = mDischargeStepTracker.computeTimePerLevel();
if (msPerLevel <= 0) {
return -1;
}
return (msPerLevel * mCurrentBatteryLevel) * 1000;
}
@Override
public LevelStepTracker getDischargeLevelStepTracker() {
return mDischargeStepTracker;
}
@Override
public LevelStepTracker getDailyDischargeLevelStepTracker() {
return mDailyDischargeStepTracker;
}
@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 (mChargeStepTracker.mNumStepDurations < 1) {
return -1;
}
long msPerLevel = mChargeStepTracker.computeTimePerLevel();
if (msPerLevel <= 0) {
return -1;
}
return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000;
}
@Override
public LevelStepTracker getChargeLevelStepTracker() {
return mChargeStepTracker;
}
@Override
public LevelStepTracker getDailyChargeLevelStepTracker() {
return mDailyChargeStepTracker;
}
@Override
public ArrayList<PackageChange> getDailyPackageChanges() {
return mDailyPackageChanges;
}
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) {
mKernelUidCpuTimeReader.removeUid(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);
}
public void shutdownLocked() {
recordShutdownLocked(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
writeSyncLocked();
mShuttingDown = true;
}
Parcel mPendingWrite = null;
final ReentrantLock mWriteLock = new ReentrantLock();
public void writeAsyncLocked() {
writeLocked(false);
}
public void writeSyncLocked() {
writeLocked(true);
}
void writeLocked(boolean sync) {
if (mFile == null) {
Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
return;
}
if (mShuttingDown) {
return;
}
Parcel out = Parcel.obtain();
writeSummaryToParcel(out, true);
mLastWriteTime = SystemClock.elapsedRealtime();
if (mPendingWrite != null) {
mPendingWrite.recycle();
}
mPendingWrite = out;
if (sync) {
commitPendingDataToDisk();
} else {
BackgroundThread.getHandler().post(new Runnable() {
@Override public void run() {
commitPendingDataToDisk();
}
});
}
}
public void commitPendingDataToDisk() {
final Parcel next;
synchronized (this) {
next = mPendingWrite;
mPendingWrite = null;
if (next == null) {
return;
}
mWriteLock.lock();
}
try {
FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
stream.write(next.marshall());
stream.flush();
FileUtils.sync(stream);
stream.close();
mFile.commit();
} catch (IOException e) {
Slog.w("BatteryStats", "Error writing battery statistics", e);
mFile.rollback();
} finally {
next.recycle();
mWriteLock.unlock();
}
}
public void readLocked() {
if (mDailyFile != null) {
readDailyStatsLocked();
}
if (mFile == null) {
Slog.w("BatteryStats", "readLocked: no file associated with this instance");
return;
}
mUidStats.clear();
try {
File file = mFile.chooseForRead();
if (!file.exists()) {
return;
}
FileInputStream stream = new FileInputStream(file);
byte[] raw = BatteryStatsHelper.readFully(stream);
Parcel in = Parcel.obtain();
in.unmarshall(raw, 0, raw.length);
in.setDataPosition(0);
stream.close();
readSummaryFromParcel(in);
} catch(Exception e) {
Slog.e("BatteryStats", "Error reading battery statistics", e);
resetAllStatsLocked();
}
mEndPlatformVersion = Build.ID;
if (mHistoryBuffer.dataPosition() > 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);
}
recordDailyStatsIfNeededLocked(false);
}
public int describeContents() {
return 0;
}
void readHistory(Parcel in, boolean andOldHistory) throws ParcelFormatException {
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<numTags; i++) {
int idx = in.readInt();
String str = in.readString();
if (str == null) {
throw new ParcelFormatException("null history tag string");
}
int uid = in.readInt();
HistoryTag tag = new HistoryTag();
tag.string = str;
tag.uid = uid;
tag.poolIdx = idx;
mHistoryTagPool.put(tag, idx);
if (idx >= mNextHistoryTagIdx) {
mNextHistoryTagIdx = idx+1;
}
mNumHistoryTagChars += tag.string.length() + 1;
}
int bufSize = in.readInt();
int curPos = in.dataPosition();
if (bufSize >= (MAX_MAX_HISTORY_BUFFER*3)) {
throw new ParcelFormatException("File corrupt: history data buffer too large " +
bufSize);
} else if ((bufSize&~3) != bufSize) {
throw new ParcelFormatException("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<HistoryTag, Integer> 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) throws ParcelFormatException {
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();
mDischargeStepTracker.readFromParcel(in);
mChargeStepTracker.readFromParcel(in);
mDailyDischargeStepTracker.readFromParcel(in);
mDailyChargeStepTracker.readFromParcel(in);
int NPKG = in.readInt();
if (NPKG > 0) {
mDailyPackageChanges = new ArrayList<>(NPKG);
while (NPKG > 0) {
NPKG--;
PackageChange pc = new PackageChange();
pc.mPackageName = in.readString();
pc.mUpdate = in.readInt() != 0;
pc.mVersionCode = in.readInt();
mDailyPackageChanges.add(pc);
}
} else {
mDailyPackageChanges = null;
}
mDailyStartTime = in.readLong();
mNextMinDailyDeadline = in.readLong();
mNextMaxDailyDeadline = in.readLong();
mStartCount++;
mScreenState = Display.STATE_UNKNOWN;
mScreenOnTimer.readSummaryFromParcelLocked(in);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
}
mInteractive = false;
mInteractiveTimer.readSummaryFromParcelLocked(in);
mPhoneOn = false;
mPowerSaveModeEnabledTimer.readSummaryFromParcelLocked(in);
mDeviceIdleModeEnabledTimer.readSummaryFromParcelLocked(in);
mDeviceIdlingTimer.readSummaryFromParcelLocked(in);
mPhoneOnTimer.readSummaryFromParcelLocked(in);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
}
mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
}
mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mMobileRadioActiveTimer.readSummaryFromParcelLocked(in);
mMobileRadioActivePerAppTimer.readSummaryFromParcelLocked(in);
mMobileRadioActiveAdjustedTime.readSummaryFromParcelLocked(in);
mMobileRadioActiveUnknownTime.readSummaryFromParcelLocked(in);
mMobileRadioActiveUnknownCount.readSummaryFromParcelLocked(in);
mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mWifiOn = false;
mWifiOnTimer.readSummaryFromParcelLocked(in);
mGlobalWifiRunning = false;
mGlobalWifiRunningTimer.readSummaryFromParcelLocked(in);
for (int i=0; i<NUM_WIFI_STATES; i++) {
mWifiStateTimer[i].readSummaryFromParcelLocked(in);
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
mWifiSupplStateTimer[i].readSummaryFromParcelLocked(in);
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
}
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mBluetoothActivityCounters[i].readSummaryFromParcelLocked(in);
}
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mWifiActivityCounters[i].readSummaryFromParcelLocked(in);
}
mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt();
mFlashlightOnNesting = 0;
mFlashlightOnTimer.readSummaryFromParcelLocked(in);
mCameraOnNesting = 0;
mCameraOnTimer.readSummaryFromParcelLocked(in);
int NKW = in.readInt();
if (NKW > 10000) {
throw new ParcelFormatException("File corrupt: too many kernel wake locks " + NKW);
}
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) {
throw new ParcelFormatException("File corrupt: too many wakeup reasons " + NWR);
}
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 ParcelFormatException("Bad speed steps in data: " + sNumSpeedSteps);
}
final int NU = in.readInt();
if (NU > 10000) {
throw new ParcelFormatException("File corrupt: too many uids " + NU);
}
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.createFlashlightTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
u.createCameraTurnedOnTimerLocked().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<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
}
}
if (in.readInt() != 0) {
if (u.mNetworkByteActivityCounters == null) {
u.initNetworkActivityLocked();
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
u.mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
u.mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
}
u.mMobileRadioActiveTime.readSummaryFromParcelLocked(in);
u.mMobileRadioActiveCount.readSummaryFromParcelLocked(in);
}
u.mUserCpuTime.readSummaryFromParcelLocked(in);
u.mSystemCpuTime.readSummaryFromParcelLocked(in);
u.mCpuPower.readSummaryFromParcelLocked(in);
int NSB = in.readInt();
if (NSB > 100) {
throw new ParcelFormatException("File corrupt: too many speed bins " + NSB);
}
u.mSpeedBins = new LongSamplingCounter[NSB];
for (int i=0; i<NSB; i++) {
if (in.readInt() != 0) {
u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase);
u.mSpeedBins[i].readSummaryFromParcelLocked(in);
}
}
int NW = in.readInt();
if (NW > 100) {
throw new ParcelFormatException("File corrupt: too many wake locks " + NW);
}
for (int iw = 0; iw < NW; iw++) {
String wlName = in.readString();
u.readWakeSummaryFromParcelLocked(wlName, in);
}
int NS = in.readInt();
if (NS > 100) {
throw new ParcelFormatException("File corrupt: too many syncs " + NS);
}
for (int is = 0; is < NS; is++) {
String name = in.readString();
u.readSyncSummaryFromParcelLocked(name, in);
}
int NJ = in.readInt();
if (NJ > 100) {
throw new ParcelFormatException("File corrupt: too many job timers " + NJ);
}
for (int ij = 0; ij < NJ; ij++) {
String name = in.readString();
u.readJobSummaryFromParcelLocked(name, in);
}
int NP = in.readInt();
if (NP > 1000) {
throw new ParcelFormatException("File corrupt: too many sensors " + NP);
}
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) {
throw new ParcelFormatException("File corrupt: too many processes " + NP);
}
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();
p.mNumCrashes = p.mLoadedNumCrashes = in.readInt();
p.mNumAnrs = p.mLoadedNumAnrs = in.readInt();
p.readExcessivePowerFromParcelLocked(in);
}
NP = in.readInt();
if (NP > 10000) {
throw new ParcelFormatException("File corrupt: too many packages " + NP);
}
for (int ip = 0; ip < NP; ip++) {
String pkgName = in.readString();
Uid.Pkg p = u.getPackageStatsLocked(pkgName);
final int NWA = in.readInt();
if (NWA > 1000) {
throw new ParcelFormatException("File corrupt: too many wakeup alarms " + NWA);
}
p.mWakeupAlarms.clear();
for (int iwa=0; iwa<NWA; iwa++) {
String tag = in.readString();
Counter c = new Counter(mOnBatteryTimeBase);
c.readSummaryFromParcelLocked(in);
p.mWakeupAlarms.put(tag, c);
}
NS = in.readInt();
if (NS > 1000) {
throw new ParcelFormatException("File corrupt: too many services " + NS);
}
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());
mDischargeStepTracker.writeToParcel(out);
mChargeStepTracker.writeToParcel(out);
mDailyDischargeStepTracker.writeToParcel(out);
mDailyChargeStepTracker.writeToParcel(out);
if (mDailyPackageChanges != null) {
final int NPKG = mDailyPackageChanges.size();
out.writeInt(NPKG);
for (int i=0; i<NPKG; i++) {
PackageChange pc = mDailyPackageChanges.get(i);
out.writeString(pc.mPackageName);
out.writeInt(pc.mUpdate ? 1 : 0);
out.writeInt(pc.mVersionCode);
}
} else {
out.writeInt(0);
}
out.writeLong(mDailyStartTime);
out.writeLong(mNextMinDailyDeadline);
out.writeLong(mNextMaxDailyDeadline);
mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
mInteractiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mPowerSaveModeEnabledTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mDeviceIdleModeEnabledTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mDeviceIdlingTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
}
mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mMobileRadioActivePerAppTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mMobileRadioActiveAdjustedTime.writeSummaryFromParcelLocked(out);
mMobileRadioActiveUnknownTime.writeSummaryFromParcelLocked(out);
mMobileRadioActiveUnknownCount.writeSummaryFromParcelLocked(out);
mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
for (int i=0; i<NUM_WIFI_STATES; i++) {
mWifiStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
mWifiSupplStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mBluetoothActivityCounters[i].writeSummaryFromParcelLocked(out);
}
for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mWifiActivityCounters[i].writeSummaryFromParcelLocked(out);
}
out.writeInt(mNumConnectivityChange);
mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mCameraOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
out.writeInt(mKernelWakelockStats.size());
for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
Timer kwlt = ent.getValue();
if (kwlt != null) {
out.writeInt(1);
out.writeString(ent.getKey());
kwlt.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
}
out.writeInt(mWakeupReasonStats.size());
for (Map.Entry<String, SamplingTimer> 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.mFlashlightTurnedOnTimer != null) {
out.writeInt(1);
u.mFlashlightTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
if (u.mCameraTurnedOnTimer != null) {
out.writeInt(1);
u.mCameraTurnedOnTimer.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<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
}
}
if (u.mNetworkByteActivityCounters == null) {
out.writeInt(0);
} else {
out.writeInt(1);
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
u.mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
u.mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
}
u.mMobileRadioActiveTime.writeSummaryFromParcelLocked(out);
u.mMobileRadioActiveCount.writeSummaryFromParcelLocked(out);
}
u.mUserCpuTime.writeSummaryFromParcelLocked(out);
u.mSystemCpuTime.writeSummaryFromParcelLocked(out);
u.mCpuPower.writeSummaryFromParcelLocked(out);
out.writeInt(u.mSpeedBins.length);
for (int i = 0; i < u.mSpeedBins.length; i++) {
LongSamplingCounter speedBin = u.mSpeedBins[i];
if (speedBin != null) {
out.writeInt(1);
speedBin.writeSummaryFromParcelLocked(out);
} else {
out.writeInt(0);
}
}
final ArrayMap<String, Uid.Wakelock> wakeStats = u.mWakelockStats.getMap();
int NW = wakeStats.size();
out.writeInt(NW);
for (int iw=0; iw<NW; iw++) {
out.writeString(wakeStats.keyAt(iw));
Uid.Wakelock wl = wakeStats.valueAt(iw);
if (wl.mTimerFull != null) {
out.writeInt(1);
wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
if (wl.mTimerPartial != null) {
out.writeInt(1);
wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
if (wl.mTimerWindow != null) {
out.writeInt(1);
wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
if (wl.mTimerDraw != null) {
out.writeInt(1);
wl.mTimerDraw.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
}
final ArrayMap<String, StopwatchTimer> syncStats = u.mSyncStats.getMap();
int NS = syncStats.size();
out.writeInt(NS);
for (int is=0; is<NS; is++) {
out.writeString(syncStats.keyAt(is));
syncStats.valueAt(is).writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
final ArrayMap<String, StopwatchTimer> jobStats = u.mJobStats.getMap();
int NJ = jobStats.size();
out.writeInt(NJ);
for (int ij=0; ij<NJ; ij++) {
out.writeString(jobStats.keyAt(ij));
jobStats.valueAt(ij).writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
int NSE = u.mSensorStats.size();
out.writeInt(NSE);
for (int ise=0; ise<NSE; ise++) {
out.writeInt(u.mSensorStats.keyAt(ise));
Uid.Sensor se = u.mSensorStats.valueAt(ise);
if (se.mTimer != null) {
out.writeInt(1);
se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
} else {
out.writeInt(0);
}
}
int NP = u.mProcessStats.size();
out.writeInt(NP);
for (int ip=0; ip<NP; ip++) {
out.writeString(u.mProcessStats.keyAt(ip));
Uid.Proc ps = u.mProcessStats.valueAt(ip);
out.writeLong(ps.mUserTime);
out.writeLong(ps.mSystemTime);
out.writeLong(ps.mForegroundTime);
out.writeInt(ps.mStarts);
out.writeInt(ps.mNumCrashes);
out.writeInt(ps.mNumAnrs);
ps.writeExcessivePowerToParcelLocked(out);
}
NP = u.mPackageStats.size();
out.writeInt(NP);
if (NP > 0) {
for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
: u.mPackageStats.entrySet()) {
out.writeString(ent.getKey());
Uid.Pkg ps = ent.getValue();
final int NWA = ps.mWakeupAlarms.size();
out.writeInt(NWA);
for (int iwa=0; iwa<NWA; iwa++) {
out.writeString(ps.mWakeupAlarms.keyAt(iwa));
ps.mWakeupAlarms.valueAt(iwa).writeSummaryFromParcelLocked(out);
}
NS = ps.mServiceStats.size();
out.writeInt(NS);
for (int is=0; is<NS; is++) {
out.writeString(ps.mServiceStats.keyAt(is));
BatteryStatsImpl.Uid.Pkg.Serv ss = ps.mServiceStats.valueAt(is);
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<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase,
in);
}
mInteractive = false;
mInteractiveTimer = new StopwatchTimer(null, -10, null, mOnBatteryTimeBase, in);
mPhoneOn = false;
mPowerSaveModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
mDeviceIdleModeEnabledTimer = new StopwatchTimer(null, -11, null, mOnBatteryTimeBase, in);
mDeviceIdlingTimer = new StopwatchTimer(null, -12, null, mOnBatteryTimeBase, in);
mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase, in);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
null, mOnBatteryTimeBase, in);
}
mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mOnBatteryTimeBase, in);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
null, mOnBatteryTimeBase, in);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
}
mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase, in);
mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase,
in);
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mWifiOn = false;
mWifiOnTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase, in);
mGlobalWifiRunning = false;
mGlobalWifiRunningTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase, in);
for (int i=0; i<NUM_WIFI_STATES; i++) {
mWifiStateTimer[i] = new StopwatchTimer(null, -600-i,
null, mOnBatteryTimeBase, in);
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
mWifiSupplStateTimer[i] = new StopwatchTimer(null, -700-i,
null, mOnBatteryTimeBase, in);
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i,
null, mOnBatteryTimeBase, in);
}
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
}
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
}
mHasWifiEnergyReporting = in.readInt() != 0;
mHasBluetoothEnergyReporting = in.readInt() != 0;
mNumConnectivityChange = in.readInt();
mLoadedNumConnectivityChange = in.readInt();
mUnpluggedNumConnectivityChange = in.readInt();
mAudioOnNesting = 0;
mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
mVideoOnNesting = 0;
mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
mFlashlightOnNesting = 0;
mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in);
mCameraOnNesting = 0;
mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase, in);
mDischargeUnplugLevel = in.readInt();
mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
mCurrentBatteryLevel = in.readInt();
mLowDischargeAmountSinceCharge = in.readInt();
mHighDischargeAmountSinceCharge = in.readInt();
mDischargeAmountScreenOn = in.readInt();
mDischargeAmountScreenOnSinceCharge = in.readInt();
mDischargeAmountScreenOff = in.readInt();
mDischargeAmountScreenOffSinceCharge = in.readInt();
mDischargeStepTracker.readFromParcel(in);
mChargeStepTracker.readFromParcel(in);
mLastWriteTime = in.readLong();
mKernelWakelockStats.clear();
int NKW = in.readInt();
for (int ikw = 0; ikw < NKW; ikw++) {
if (in.readInt() != 0) {
String wakelockName = in.readString();
SamplingTimer kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase, in);
mKernelWakelockStats.put(wakelockName, kwlt);
}
}
mWakeupReasonStats.clear();
int NWR = in.readInt();
for (int iwr = 0; iwr < NWR; iwr++) {
if (in.readInt() != 0) {
String reasonName = in.readString();
SamplingTimer timer = new SamplingTimer(mOnBatteryTimeBase, in);
mWakeupReasonStats.put(reasonName, timer);
}
}
mPartialTimers.clear();
mFullTimers.clear();
mWindowTimers.clear();
mWifiRunningTimers.clear();
mFullWifiLockTimers.clear();
mWifiScanTimers.clear();
mWifiBatchedScanTimers.clear();
mWifiMulticastTimers.clear();
mAudioTurnedOnTimers.clear();
mVideoTurnedOnTimers.clear();
mFlashlightTurnedOnTimers.clear();
mCameraTurnedOnTimers.clear();
sNumSpeedSteps = in.readInt();
int numUids = in.readInt();
mUidStats.clear();
for (int i = 0; i < numUids; i++) {
int uid = in.readInt();
Uid u = new Uid(uid);
u.readFromParcelLocked(mOnBatteryTimeBase, mOnBatteryScreenOffTimeBase, in);
mUidStats.append(uid, u);
}
}
public void writeToParcel(Parcel out, int flags) {
writeToParcelLocked(out, true, flags);
}
public void writeToParcelWithoutUids(Parcel out, int flags) {
writeToParcelLocked(out, false, flags);
}
@SuppressWarnings("unused")
void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
// Need to update with current kernel wake lock counts.
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 uSecUptime = SystemClock.uptimeMillis() * 1000;
final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
final long batteryRealtime = mOnBatteryTimeBase.getRealtime(uSecRealtime);
final long batteryScreenOffRealtime = mOnBatteryScreenOffTimeBase.getRealtime(uSecRealtime);
out.writeInt(MAGIC);
writeHistory(out, true, false);
out.writeInt(mStartCount);
out.writeLong(startClockTime);
out.writeString(mStartPlatformVersion);
out.writeString(mEndPlatformVersion);
out.writeLong(mUptime);
out.writeLong(mUptimeStart);
out.writeLong(mRealtime);
out.writeLong(mRealtimeStart);
out.writeInt(mOnBattery ? 1 : 0);
mOnBatteryTimeBase.writeToParcel(out, uSecUptime, uSecRealtime);
mOnBatteryScreenOffTimeBase.writeToParcel(out, uSecUptime, uSecRealtime);
mScreenOnTimer.writeToParcel(out, uSecRealtime);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].writeToParcel(out, uSecRealtime);
}
mInteractiveTimer.writeToParcel(out, uSecRealtime);
mPowerSaveModeEnabledTimer.writeToParcel(out, uSecRealtime);
mDeviceIdleModeEnabledTimer.writeToParcel(out, uSecRealtime);
mDeviceIdlingTimer.writeToParcel(out, uSecRealtime);
mPhoneOnTimer.writeToParcel(out, uSecRealtime);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
}
mPhoneSignalScanningTimer.writeToParcel(out, uSecRealtime);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i].writeToParcel(out, uSecRealtime);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i].writeToParcel(out);
mNetworkPacketActivityCounters[i].writeToParcel(out);
}
mMobileRadioActiveTimer.writeToParcel(out, uSecRealtime);
mMobileRadioActivePerAppTimer.writeToParcel(out, uSecRealtime);
mMobileRadioActiveAdjustedTime.writeToParcel(out);
mMobileRadioActiveUnknownTime.writeToParcel(out);
mMobileRadioActiveUnknownCount.writeToParcel(out);
mWifiOnTimer.writeToParcel(out, uSecRealtime);
mGlobalWifiRunningTimer.writeToParcel(out, uSecRealtime);
for (int i=0; i<NUM_WIFI_STATES; i++) {
mWifiStateTimer[i].writeToParcel(out, uSecRealtime);
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
mWifiSupplStateTimer[i].writeToParcel(out, uSecRealtime);
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
}
for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mBluetoothActivityCounters[i].writeToParcel(out);
}
for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mWifiActivityCounters[i].writeToParcel(out);
}
out.writeInt(mHasWifiEnergyReporting ? 1 : 0);
out.writeInt(mHasBluetoothEnergyReporting ? 1 : 0);
out.writeInt(mNumConnectivityChange);
out.writeInt(mLoadedNumConnectivityChange);
out.writeInt(mUnpluggedNumConnectivityChange);
mFlashlightOnTimer.writeToParcel(out, uSecRealtime);
mCameraOnTimer.writeToParcel(out, uSecRealtime);
out.writeInt(mDischargeUnplugLevel);
out.writeInt(mDischargePlugLevel);
out.writeInt(mDischargeCurrentLevel);
out.writeInt(mCurrentBatteryLevel);
out.writeInt(mLowDischargeAmountSinceCharge);
out.writeInt(mHighDischargeAmountSinceCharge);
out.writeInt(mDischargeAmountScreenOn);
out.writeInt(mDischargeAmountScreenOnSinceCharge);
out.writeInt(mDischargeAmountScreenOff);
out.writeInt(mDischargeAmountScreenOffSinceCharge);
mDischargeStepTracker.writeToParcel(out);
mChargeStepTracker.writeToParcel(out);
out.writeLong(mLastWriteTime);
if (inclUids) {
out.writeInt(mKernelWakelockStats.size());
for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
SamplingTimer kwlt = ent.getValue();
if (kwlt != null) {
out.writeInt(1);
out.writeString(ent.getKey());
kwlt.writeToParcel(out, uSecRealtime);
} else {
out.writeInt(0);
}
}
out.writeInt(mWakeupReasonStats.size());
for (Map.Entry<String, SamplingTimer> 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<BatteryStatsImpl> CREATOR =
new Parcelable.Creator<BatteryStatsImpl>() {
public BatteryStatsImpl createFromParcel(Parcel in) {
return new BatteryStatsImpl(in);
}
public BatteryStatsImpl[] newArray(int size) {
return new BatteryStatsImpl[size];
}
};
public void 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<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
pr.println("*** Screen brightness #" + i + ":");
mScreenBrightnessTimer[i].logState(pr, " ");
}
pr.println("*** Interactive timer:");
mInteractiveTimer.logState(pr, " ");
pr.println("*** Power save mode timer:");
mPowerSaveModeEnabledTimer.logState(pr, " ");
pr.println("*** Device idle mode timer:");
mDeviceIdleModeEnabledTimer.logState(pr, " ");
pr.println("*** Device idling timer:");
mDeviceIdlingTimer.logState(pr, " ");
pr.println("*** Phone timer:");
mPhoneOnTimer.logState(pr, " ");
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
pr.println("*** Phone signal strength #" + i + ":");
mPhoneSignalStrengthsTimer[i].logState(pr, " ");
}
pr.println("*** Signal scanning :");
mPhoneSignalScanningTimer.logState(pr, " ");
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
pr.println("*** Data connection type #" + i + ":");
mPhoneDataConnectionsTimer[i].logState(pr, " ");
}
pr.println("*** mMobileRadioPowerState=" + mMobileRadioPowerState);
pr.println("*** Mobile network active timer:");
mMobileRadioActiveTimer.logState(pr, " ");
pr.println("*** Mobile network active adjusted timer:");
mMobileRadioActiveAdjustedTime.logState(pr, " ");
pr.println("*** mWifiRadioPowerState=" + mWifiRadioPowerState);
pr.println("*** Wifi timer:");
mWifiOnTimer.logState(pr, " ");
pr.println("*** WifiRunning timer:");
mGlobalWifiRunningTimer.logState(pr, " ");
for (int i=0; i<NUM_WIFI_STATES; i++) {
pr.println("*** Wifi state #" + i + ":");
mWifiStateTimer[i].logState(pr, " ");
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
pr.println("*** Wifi suppl state #" + i + ":");
mWifiSupplStateTimer[i].logState(pr, " ");
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
pr.println("*** Wifi signal strength #" + i + ":");
mWifiSignalStrengthsTimer[i].logState(pr, " ");
}
pr.println("*** Flashlight timer:");
mFlashlightOnTimer.logState(pr, " ");
pr.println("*** Camera timer:");
mCameraOnTimer.logState(pr, " ");
}
super.dumpLocked(context, pw, flags, reqUid, histStart);
}
}