public long time;
- // The command codes 0-3 can be written with delta updates; all others require
- // that a full entry be written.
- public static final byte CMD_UPDATE = 0;
- public static final byte CMD_EVENT = 1;
+ public static final byte CMD_UPDATE = 0; // These can be written as deltas
public static final byte CMD_NULL = -1;
public static final byte CMD_START = 4;
public static final byte CMD_OVERFLOW = 5;
/**
* Return whether the command code is a delta data update.
*/
- public static boolean isDeltaData(byte cmd) {
- return cmd >= 0 && cmd <= 3;
- }
-
- /**
- * Return whether the command code is a delta data update.
- */
public boolean isDeltaData() {
- return cmd >= 0 && cmd <= 3;
+ return cmd == CMD_UPDATE;
}
public byte batteryLevel;
// These states always appear directly in the first int token
// of a delta change; they should be ones that change relatively
// frequently.
- public static final int STATE_WAKE_LOCK_FLAG = 1<<30;
- public static final int STATE_SENSOR_ON_FLAG = 1<<29;
- public static final int STATE_GPS_ON_FLAG = 1<<28;
- public static final int STATE_PHONE_SCANNING_FLAG = 1<<27;
- public static final int STATE_WIFI_RUNNING_FLAG = 1<<26;
- public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<25;
- public static final int STATE_WIFI_SCAN_FLAG = 1<<24;
- public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<23;
+ public static final int STATE_WAKE_LOCK_FLAG = 1<<31;
+ public static final int STATE_SENSOR_ON_FLAG = 1<<30;
+ public static final int STATE_GPS_ON_FLAG = 1<<29;
+ public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<28;
+ public static final int STATE_WIFI_SCAN_FLAG = 1<<29;
+ public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<26;
// These are on the lower bits used for the command; if they change
// we need to write another int of data.
+ public static final int STATE_WIFI_RUNNING_FLAG = 1<<24;
+ public static final int STATE_PHONE_SCANNING_FLAG = 1<<23;
public static final int STATE_AUDIO_ON_FLAG = 1<<22;
public static final int STATE_VIDEO_ON_FLAG = 1<<21;
public static final int STATE_SCREEN_ON_FLAG = 1<<20;
} else {
dest.writeInt(0);
}
- if (cmd == CMD_EVENT) {
+ dest.writeInt(eventCode);
+ if (eventCode != EVENT_NONE) {
dest.writeInt(eventCode);
eventTag.writeToParcel(dest, flags);
}
} else {
wakelockTag = null;
}
- if (cmd == CMD_EVENT) {
- eventCode = src.readInt();
+ eventCode = src.readInt();
+ if (eventCode != EVENT_NONE) {
eventTag = localEventTag;
eventTag.readFromParcel(src);
- } else {
- eventCode = EVENT_NONE;
- eventTag = null;
}
numReadInts += (src.dataPosition()-start)/4;
}
public void setTo(HistoryItem o) {
time = o.time;
cmd = o.cmd;
+ setToCommon(o);
+ }
+
+ public void setTo(long time, byte cmd, HistoryItem o) {
+ this.time = time;
+ this.cmd = cmd;
+ setToCommon(o);
+ }
+
+ private void setToCommon(HistoryItem o) {
batteryLevel = o.batteryLevel;
batteryStatus = o.batteryStatus;
batteryHealth = o.batteryHealth;
}
}
- public void setTo(long time, byte cmd, int eventCode, int eventUid, String eventName,
- HistoryItem o) {
- this.time = time;
- this.cmd = cmd;
- this.eventCode = eventCode;
- if (eventCode != EVENT_NONE) {
- eventTag = localEventTag;
- eventTag.setTo(eventName, eventUid);
- } else {
- eventTag = null;
- }
- batteryLevel = o.batteryLevel;
- batteryStatus = o.batteryStatus;
- batteryHealth = o.batteryHealth;
- batteryPlugType = o.batteryPlugType;
- batteryTemperature = o.batteryTemperature;
- batteryVoltage = o.batteryVoltage;
- states = o.states;
- if (o.wakelockTag != null) {
- wakelockTag = localWakelockTag;
- wakelockTag.setTo(o.wakelockTag);
- } else {
- wakelockTag = null;
- }
- }
-
public boolean sameNonEvent(HistoryItem o) {
return batteryLevel == o.batteryLevel
&& batteryStatus == o.batteryStatus
public static final BitDescription[] HISTORY_STATE_DESCRIPTIONS
= new BitDescription[] {
- new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged", "BP"),
- new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen", "S"),
+ new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock", "w"),
+ new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor", "s"),
new BitDescription(HistoryItem.STATE_GPS_ON_FLAG, "gps", "g"),
- new BitDescription(HistoryItem.STATE_PHONE_IN_CALL_FLAG, "phone_in_call", "Pcl"),
- new BitDescription(HistoryItem.STATE_PHONE_SCANNING_FLAG, "phone_scanning", "Psc"),
- new BitDescription(HistoryItem.STATE_WIFI_ON_FLAG, "wifi", "W"),
- new BitDescription(HistoryItem.STATE_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
new BitDescription(HistoryItem.STATE_WIFI_FULL_LOCK_FLAG, "wifi_full_lock", "Wl"),
new BitDescription(HistoryItem.STATE_WIFI_SCAN_FLAG, "wifi_scan", "Ws"),
new BitDescription(HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG, "wifi_multicast", "Wm"),
- new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth", "b"),
+ new BitDescription(HistoryItem.STATE_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
+ new BitDescription(HistoryItem.STATE_PHONE_SCANNING_FLAG, "phone_scanning", "Psc"),
new BitDescription(HistoryItem.STATE_AUDIO_ON_FLAG, "audio", "a"),
new BitDescription(HistoryItem.STATE_VIDEO_ON_FLAG, "video", "v"),
- new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock", "w"),
- new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor", "s"),
- new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK,
- HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness", "Sb",
- SCREEN_BRIGHTNESS_NAMES, SCREEN_BRIGHTNESS_SHORT_NAMES),
+ new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen", "S"),
+ new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged", "BP"),
+ new BitDescription(HistoryItem.STATE_PHONE_IN_CALL_FLAG, "phone_in_call", "Pcl"),
+ new BitDescription(HistoryItem.STATE_WIFI_ON_FLAG, "wifi", "W"),
+ new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth", "b"),
+ new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK,
+ HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", "Pcn",
+ DATA_CONNECTION_NAMES, DATA_CONNECTION_NAMES),
+ new BitDescription(HistoryItem.STATE_PHONE_STATE_MASK,
+ HistoryItem.STATE_PHONE_STATE_SHIFT, "phone_state", "Pst",
+ new String[] {"in", "out", "emergency", "off"},
+ new String[] {"in", "out", "em", "off"}),
new BitDescription(HistoryItem.STATE_SIGNAL_STRENGTH_MASK,
HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT, "signal_strength", "Pss",
SignalStrength.SIGNAL_STRENGTH_NAMES, new String[] {
"0", "1", "2", "3", "4"
}),
- new BitDescription(HistoryItem.STATE_PHONE_STATE_MASK,
- HistoryItem.STATE_PHONE_STATE_SHIFT, "phone_state", "Pst",
- new String[] {"in", "out", "emergency", "off"},
- new String[] {"in", "out", "em", "off"}),
- new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK,
- HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", "Pcn",
- DATA_CONNECTION_NAMES, DATA_CONNECTION_NAMES),
+ new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK,
+ HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness", "Sb",
+ SCREEN_BRIGHTNESS_NAMES, SCREEN_BRIGHTNESS_SHORT_NAMES),
};
/**
else if (rec.batteryLevel < 100) pw.print("0");
pw.print(rec.batteryLevel);
pw.print(" ");
- if (rec.states < 0x10) pw.print("0000000");
+ if (rec.states < 0) ;
+ else if (rec.states < 0x10) pw.print("0000000");
else if (rec.states < 0x100) pw.print("000000");
else if (rec.states < 0x1000) pw.print("00000");
else if (rec.states < 0x10000) pw.print("0000");
public static final int ON_AFTER_RELEASE = 0x20000000;
/**
+ * Wake lock flag: This wake lock is not important for logging events. If a later
+ * wake lock is acquired that is important, it will be considered the one to log.
+ * @hide
+ */
+ public static final int UNIMPORTANT_FOR_LOGGING = 0x40000000;
+
+ /**
* Flag for {@link WakeLock#release release(int)} to defer releasing a
* {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK} wake lock until the proximity sensor returns
* a negative value.
* </p>
*/
public final class WakeLock {
- private final int mFlags;
- private final String mTag;
+ private int mFlags;
+ private String mTag;
private final String mPackageName;
private final IBinder mToken;
private int mCount;
}
}
+ /** @hide */
+ public void setTag(String tag) {
+ mTag = tag;
+ }
+
+ /** @hide */
+ public void setUnimportantForLogging(boolean state) {
+ if (state) mFlags |= UNIMPORTANT_FOR_LOGGING;
+ else mFlags &= ~UNIMPORTANT_FOR_LOGGING;
+ }
+
@Override
public String toString() {
synchronized (mToken) {
void noteEvent(int code, String name, int uid);
- void noteStartWakelock(int uid, int pid, String name, int type);
+ void noteStartWakelock(int uid, int pid, String name, int type, boolean unimportantForLogging);
void noteStopWakelock(int uid, int pid, String name, int type);
- void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, int type);
+ void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, int type,
+ boolean unimportantForLogging);
void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, int type);
void noteVibratorOn(int uid, long durationMillis);
*/
public final class BatteryStatsImpl extends BatteryStats {
private static final String TAG = "BatteryStatsImpl";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
private static final boolean DEBUG_HISTORY = false;
private static final boolean USE_OLD_HISTORY = false; // for debugging.
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 75 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 77 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
long mRealtimeStart;
long mLastRealtime;
+ int mWakeLockNesting;
+ boolean mWakeLockImportant;
+
boolean mScreenOn;
StopwatchTimer mScreenOnTimer;
}
// Part of initial delta int that specifies the time delta.
- static final int DELTA_TIME_MASK = 0x1ffff;
- static final int DELTA_TIME_LONG = 0x1ffff; // The delta is a following long
- static final int DELTA_TIME_INT = 0x1fffe; // The delta is a following int
- static final int DELTA_TIME_ABS = 0x1fffd; // Following is an entire abs update.
- // Part of initial delta int holding the command code.
- static final int DELTA_CMD_MASK = 0x3;
- static final int DELTA_CMD_SHIFT = 17;
+ static final int DELTA_TIME_MASK = 0xfffff;
+ static final int DELTA_TIME_LONG = 0xfffff; // The delta is a following long
+ static final int DELTA_TIME_INT = 0xffffe; // The delta is a following int
+ static final int DELTA_TIME_ABS = 0xffffd; // Following is an entire abs update.
// Flag in delta int: a new battery level int follows.
- static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000;
+ static final int DELTA_BATTERY_LEVEL_FLAG = 0x00400000;
// Flag in delta int: a new full state and battery status int follows.
- static final int DELTA_STATE_FLAG = 0x00100000;
+ static final int DELTA_STATE_FLAG = 0x00800000;
// Flag in delta int: contains a wakelock tag.
- static final int DELTA_WAKELOCK_FLAG = 0x00200000;
- static final int DELTA_STATE_MASK = 0xffc00000;
+ static final int DELTA_WAKELOCK_FLAG = 0x01000000;
+ // Flag in delta int: contains an event description.
+ static final int DELTA_EVENT_FLAG = 0x02000000;
+ // These upper bits are the frequently changing state bits.
+ static final int DELTA_STATE_MASK = 0xfc000000;
public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
- if (last == null || !last.isDeltaData() || !cur.isDeltaData()) {
+ if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
dest.writeInt(DELTA_TIME_ABS);
cur.writeToParcel(dest, 0);
return;
} else {
deltaTimeToken = (int)deltaTime;
}
- int firstToken = deltaTimeToken
- | (cur.cmd<<DELTA_CMD_SHIFT)
- | (cur.states&DELTA_STATE_MASK);
+ int firstToken = deltaTimeToken | (cur.states&DELTA_STATE_MASK);
final int batteryLevelInt = buildBatteryLevelInt(cur);
final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt;
if (batteryLevelIntChanged) {
if (cur.wakelockTag != 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 (DEBUG) Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
+ " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
}
- if (cur.cmd == HistoryItem.CMD_EVENT) {
+ if (cur.eventCode != HistoryItem.EVENT_NONE) {
int index = writeHistoryTag(cur.eventTag);
int codeAndIndex = (cur.eventCode&0xffff) | (index<<16);
dest.writeInt(codeAndIndex);
public void readHistoryDelta(Parcel src, HistoryItem cur) {
int firstToken = src.readInt();
int deltaTimeToken = firstToken&DELTA_TIME_MASK;
- cur.cmd = (byte)((firstToken>>DELTA_CMD_SHIFT)&DELTA_CMD_MASK);
+ cur.cmd = HistoryItem.CMD_UPDATE;
cur.numReadInts = 1;
if (DEBUG) Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)
+ " deltaTimeToken=" + deltaTimeToken);
cur.wakelockTag = null;
}
- if (cur.cmd == HistoryItem.CMD_EVENT) {
+ if ((firstToken&DELTA_EVENT_FLAG) != 0) {
cur.eventTag = cur.localEventTag;
final int codeAndIndex = src.readInt();
cur.eventCode = (codeAndIndex&0xffff);
if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
&& timeDiff < 1000 && (diffStates&lastDiffStates) == 0
&& (mHistoryLastWritten.wakelockTag == null || mHistoryCur.wakelockTag == null)
+ && (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE
+ || mHistoryCur.eventCode == HistoryItem.EVENT_NONE)
&& mHistoryLastWritten.batteryLevel == mHistoryCur.batteryLevel
&& mHistoryLastWritten.batteryStatus == mHistoryCur.batteryStatus
&& mHistoryLastWritten.batteryHealth == mHistoryCur.batteryHealth
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
mHistoryCur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag);
}
+ // 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) {
+ mHistoryCur.eventCode = mHistoryLastWritten.eventCode;
+ mHistoryCur.eventTag = mHistoryCur.localEventTag;
+ mHistoryCur.eventTag.setTo(mHistoryLastWritten.eventTag);
+ }
mHistoryLastWritten.setTo(mHistoryLastLastWritten);
}
addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
}
- void addHistoryBufferLocked(long curTime, byte cmd) {
- addHistoryBufferLocked(curTime, cmd, HistoryItem.EVENT_NONE, null, 0);
- }
-
- void addHistoryBufferEventLocked(long curTime, int eventCode, String eventName, int eventUid) {
- addHistoryBufferLocked(curTime, HistoryItem.CMD_EVENT, eventCode, eventName, eventUid);
- }
-
- private void addHistoryBufferLocked(long curTime, byte cmd,
- int eventCode, String eventName, int eventUid) {
+ private void addHistoryBufferLocked(long curTime, byte cmd) {
if (mIteratingHistory) {
throw new IllegalStateException("Can't do this while iterating history!");
}
mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
mHistoryLastLastWritten.setTo(mHistoryLastWritten);
- mHistoryLastWritten.setTo(mHistoryBaseTime + curTime, cmd,
- eventCode, eventUid, eventName, mHistoryCur);
+ mHistoryLastWritten.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
mLastHistoryTime = curTime;
mHistoryCur.wakelockTag = null;
+ mHistoryCur.eventCode = HistoryItem.EVENT_NONE;
+ mHistoryCur.eventTag = null;
if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
+ " now " + mHistoryBuffer.dataPosition()
+ " size is now " + mHistoryBuffer.dataSize());
mHistoryLastEnd = null;
} else {
mChangedStates |= mHistoryEnd.states^mHistoryCur.states;
- mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE,
- HistoryItem.EVENT_NONE, 0, null, mHistoryCur);
+ mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, mHistoryCur);
}
return;
}
}
void addHistoryEventLocked(long curTime, int code, String name, int uid) {
- addHistoryBufferEventLocked(curTime, code, name, uid);
+ mHistoryCur.eventCode = code;
+ mHistoryCur.eventTag = mHistoryCur.localEventTag;
+ mHistoryCur.eventTag.string = name;
+ mHistoryCur.eventTag.uid = uid;
+ addHistoryBufferLocked(curTime);
}
void addHistoryRecordLocked(long curTime, byte cmd) {
} else {
rec = new HistoryItem();
}
- rec.setTo(mHistoryBaseTime + curTime, cmd,
- HistoryItem.EVENT_NONE, 0, null, mHistoryCur);
+ rec.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
addHistoryRecordLocked(rec);
}
mHistoryBuffer.setDataSize(0);
mHistoryBuffer.setDataPosition(0);
mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER / 2);
- mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
- mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
+ mHistoryLastLastWritten.clear();
+ mHistoryLastWritten.clear();
mHistoryTagPool.clear();
mNextHistoryTagIdx = 0;
mNumHistoryTagChars = 0;
mBluetoothPingStart = -1;
}
- int mWakeLockNesting;
-
public void addIsolatedUidLocked(int isolatedUid, int appUid) {
mIsolatedUids.put(isolatedUid, appUid);
}
addHistoryEventLocked(SystemClock.elapsedRealtime(), code, name, uid);
}
- public void noteStartWakeLocked(int uid, int pid, String name, int type) {
+ public void noteStartWakeLocked(int uid, int pid, String name, int type,
+ boolean unimportantForLogging) {
uid = mapUid(uid);
if (type == WAKE_TYPE_PARTIAL) {
// Only care about partial wake locks, since full wake locks
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
mHistoryCur.wakelockTag.string = name;
mHistoryCur.wakelockTag.uid = uid;
+ mWakeLockImportant = !unimportantForLogging;
addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ } else if (!mWakeLockImportant && !unimportantForLogging) {
+ if (mHistoryLastWritten.wakelockTag != null) {
+ // We'll try to update the last tag.
+ mHistoryLastWritten.wakelockTag = null;
+ mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+ mHistoryCur.wakelockTag.string = name;
+ mHistoryCur.wakelockTag.uid = uid;
+ addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ }
+ mWakeLockImportant = true;
}
mWakeLockNesting++;
}
}
}
- public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
+ public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type,
+ boolean unimportantForLogging) {
int N = ws.size();
for (int i=0; i<N; i++) {
- noteStartWakeLocked(ws.get(i), pid, name, type);
+ noteStartWakeLocked(ws.get(i), pid, name, type, unimportantForLogging);
}
}
// Fake a wake lock, so we consider the device waked as long
// as the screen is on.
- noteStartWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL);
+ noteStartWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL, false);
// Update discharge amounts.
if (mOnBatteryInternal) {
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;
mReadHistoryUids[idx] = tag.uid;
mReadHistoryChars += tag.string.length() + 1;
}
- return mHistoryBuffer.dataSize() > 0;
+ return true;
}
@Override
mDischargeAmountScreenOff = 0;
mDischargeAmountScreenOffSinceCharge = 0;
}
-
- public void resetAllStatsLocked() {
+
+ public void resetAllStatsCmdLocked() {
+ resetAllStatsLocked();
+ long uptime = SystemClock.uptimeMillis() * 1000;
+ long mSecRealtime = SystemClock.elapsedRealtime();
+ long realtime = mSecRealtime * 1000;
+ mDischargeStartLevel = mHistoryCur.batteryLevel;
+ pullPendingStateUpdatesLocked();
+ addHistoryRecordLocked(mSecRealtime);
+ mDischargeCurrentLevel = mDischargeUnplugLevel = mHistoryCur.batteryLevel;
+ if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0) {
+ mTrackBatteryPastUptime = 0;
+ mTrackBatteryPastRealtime = 0;
+ } else {
+ mTrackBatteryUptimeStart = uptime;
+ mTrackBatteryRealtimeStart = realtime;
+ mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
+ mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
+ if (mScreenOn) {
+ mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel;
+ mDischargeScreenOffUnplugLevel = 0;
+ } else {
+ mDischargeScreenOnUnplugLevel = 0;
+ mDischargeScreenOffUnplugLevel = mHistoryCur.batteryLevel;
+ }
+ mDischargeAmountScreenOn = 0;
+ mDischargeAmountScreenOff = 0;
+ }
+ }
+
+ private void resetAllStatsLocked() {
mStartCount = 0;
initTimes();
mScreenOnTimer.reset(this, false);
if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
// We don't record history while we are plugged in and fully charged.
// The next time we are unplugged, history will be cleared.
- mRecordingHistory = false;
+ mRecordingHistory = DEBUG;
}
}
}
import android.os.UserHandle;
import android.os.WorkSource;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.TimeUtils;
import java.io.ByteArrayOutputStream;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
-import java.util.HashMap;
import java.util.LinkedList;
-import java.util.Map;
import java.util.TimeZone;
import static android.app.AlarmManager.RTC_WAKEUP;
return 0;
}
}
-
+
+ final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() {
+ @Override
+ public int compare(Alarm lhs, Alarm rhs) {
+ if (lhs.wakeup != rhs.wakeup) {
+ return lhs.wakeup ? -1 : 1;
+ }
+ if (lhs.whenElapsed < rhs.whenElapsed) {
+ return -1;
+ } else if (lhs.whenElapsed > rhs.whenElapsed) {
+ return 1;
+ }
+ return 0;
+ }
+ };
+
// minimum recurrence period or alarm futurity for us to be able to fuzz it
static final long MIN_FUZZABLE_INTERVAL = 10000;
static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
}
static final class BroadcastStats {
+ final int mUid;
final String mPackageName;
long aggregateTime;
int numWakeup;
long startTime;
int nesting;
- final HashMap<Pair<String, ComponentName>, FilterStats> filterStats
- = new HashMap<Pair<String, ComponentName>, FilterStats>();
+ final ArrayMap<Pair<String, ComponentName>, FilterStats> filterStats
+ = new ArrayMap<Pair<String, ComponentName>, FilterStats>();
- BroadcastStats(String packageName) {
+ BroadcastStats(int uid, String packageName) {
+ mUid = uid;
mPackageName = packageName;
}
}
- final HashMap<String, BroadcastStats> mBroadcastStats
- = new HashMap<String, BroadcastStats>();
+ final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats
+ = new SparseArray<ArrayMap<String, BroadcastStats>>();
@Override
public void onStart() {
setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
new Intent(Intent.ACTION_TIME_TICK).addFlags(
}
};
int len = 0;
- for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
- BroadcastStats bs = be.getValue();
- for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
- : bs.filterStats.entrySet()) {
- FilterStats fs = fe.getValue();
- int pos = len > 0
- ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
- if (pos < 0) {
- pos = -pos - 1;
- }
- if (pos < topFilters.length) {
- int copylen = topFilters.length - pos - 1;
- if (copylen > 0) {
- System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
+ for (int iu=0; iu<mBroadcastStats.size(); iu++) {
+ ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
+ for (int ip=0; ip<uidStats.size(); ip++) {
+ BroadcastStats bs = uidStats.valueAt(ip);
+ for (int is=0; is<bs.filterStats.size(); is++) {
+ FilterStats fs = bs.filterStats.valueAt(is);
+ int pos = len > 0
+ ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
+ if (pos < 0) {
+ pos = -pos - 1;
}
- topFilters[pos] = fs;
- if (len < topFilters.length) {
- len++;
+ if (pos < topFilters.length) {
+ int copylen = topFilters.length - pos - 1;
+ if (copylen > 0) {
+ System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
+ }
+ topFilters[pos] = fs;
+ if (len < topFilters.length) {
+ len++;
+ }
}
}
}
TimeUtils.formatDuration(fs.aggregateTime, pw);
pw.print(" running, "); pw.print(fs.numWakeup);
pw.print(" wakeups, "); pw.print(fs.count);
- pw.print(" alarms: "); pw.print(fs.mBroadcastStats.mPackageName);
+ pw.print(" alarms: "); UserHandle.formatUid(pw, fs.mBroadcastStats.mUid);
+ pw.print(":"); pw.print(fs.mBroadcastStats.mPackageName);
pw.println();
pw.print(" ");
if (fs.mTarget.first != null) {
pw.println(" ");
pw.println(" Alarm Stats:");
final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
- for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
- BroadcastStats bs = be.getValue();
- pw.print(" ");
- if (bs.nesting > 0) pw.print("*ACTIVE* ");
- pw.print(be.getKey());
- pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
- pw.print(" running, "); pw.print(bs.numWakeup);
- pw.println(" wakeups:");
- tmpFilters.clear();
- for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
- : bs.filterStats.entrySet()) {
- tmpFilters.add(fe.getValue());
- }
- Collections.sort(tmpFilters, comparator);
- for (int i=0; i<tmpFilters.size(); i++) {
- FilterStats fs = tmpFilters.get(i);
- pw.print(" ");
- if (fs.nesting > 0) pw.print("*ACTIVE* ");
- TimeUtils.formatDuration(fs.aggregateTime, pw);
- pw.print(" "); pw.print(fs.numWakeup);
- pw.print(" wakes " ); pw.print(fs.count);
- pw.print(" alarms:");
- if (fs.mTarget.first != null) {
- pw.print(" act="); pw.print(fs.mTarget.first);
- }
- if (fs.mTarget.second != null) {
- pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
- }
- pw.println();
+ for (int iu=0; iu<mBroadcastStats.size(); iu++) {
+ ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
+ for (int ip=0; ip<uidStats.size(); ip++) {
+ BroadcastStats bs = uidStats.valueAt(ip);
+ pw.print(" ");
+ if (bs.nesting > 0) pw.print("*ACTIVE* ");
+ UserHandle.formatUid(pw, bs.mUid);
+ pw.print(":");
+ pw.print(bs.mPackageName);
+ pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
+ pw.print(" running, "); pw.print(bs.numWakeup);
+ pw.println(" wakeups:");
+ tmpFilters.clear();
+ for (int is=0; is<bs.filterStats.size(); is++) {
+ tmpFilters.add(bs.filterStats.valueAt(is));
+ }
+ Collections.sort(tmpFilters, comparator);
+ for (int i=0; i<tmpFilters.size(); i++) {
+ FilterStats fs = tmpFilters.get(i);
+ pw.print(" ");
+ if (fs.nesting > 0) pw.print("*ACTIVE* ");
+ TimeUtils.formatDuration(fs.aggregateTime, pw);
+ pw.print(" "); pw.print(fs.numWakeup);
+ pw.print(" wakes " ); pw.print(fs.count);
+ pw.print(" alarms:");
+ if (fs.mTarget.first != null) {
+ pw.print(" act="); pw.print(fs.mTarget.first);
+ }
+ if (fs.mTarget.second != null) {
+ pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
+ }
+ pw.println();
+ }
}
}
private native int waitForAlarm(long nativeData);
private native int setKernelTimezone(long nativeData, int minuteswest);
- void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
+ void triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
+ final long nowRTC) {
// batches are temporally sorted, so we need only pull from the
// start of the list until we either empty it or hit a batch
// that is not yet deliverable
}
}
+
+ Collections.sort(triggerList, mAlarmDispatchComparator);
+
+ if (localLOGV) {
+ for (int i=0; i<triggerList.size(); i++) {
+ Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i));
+ }
+ }
}
/**
}
private static class Alarm {
- public int type;
+ public final int type;
+ public final boolean wakeup;
public int count;
public long when;
public long windowLength;
public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
long _interval, PendingIntent _op, WorkSource _ws) {
type = _type;
+ wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
+ || _type == AlarmManager.RTC_WAKEUP;
when = _when;
whenElapsed = _whenElapsed;
windowLength = _windowLength;
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(" type ");
sb.append(type);
+ sb.append(" when ");
+ sb.append(when);
sb.append(" ");
sb.append(operation.getTargetPackage());
sb.append('}');
// we have an active broadcast so stay awake.
if (mBroadcastRefCount == 0) {
setWakelockWorkSource(alarm.operation, alarm.workSource);
+ mWakeLock.setUnimportantForLogging(
+ alarm.operation == mTimeTickSender);
+ // XXX debugging
+ /*
+ Intent intent = alarm.operation.getIntent();
+ mWakeLock.setTag(intent.getAction() != null ? intent.getAction()
+ : (intent.getComponent() != null
+ ? intent.getComponent().toShortString() : TAG));
+ */
mWakeLock.acquire();
}
final InFlight inflight = new InFlight(AlarmManagerService.this,
if (pkgList != null && (pkgList.length > 0)) {
for (String pkg : pkgList) {
removeLocked(pkg);
- mBroadcastStats.remove(pkg);
+ for (int i=mBroadcastStats.size()-1; i>=0; i--) {
+ ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
+ if (uidStats.remove(pkg) != null) {
+ if (uidStats.size() <= 0) {
+ mBroadcastStats.removeAt(i);
+ }
+ }
+ }
}
}
}
}
private final BroadcastStats getStatsLocked(PendingIntent pi) {
- String pkg = pi.getTargetPackage();
- BroadcastStats bs = mBroadcastStats.get(pkg);
+ String pkg = pi.getCreatorPackage();
+ int uid = pi.getCreatorUid();
+ ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.get(uid);
+ if (uidStats == null) {
+ uidStats = new ArrayMap<String, BroadcastStats>();
+ mBroadcastStats.put(uid, uidStats);
+ }
+ BroadcastStats bs = uidStats.get(pkg);
if (bs == null) {
- bs = new BroadcastStats(pkg);
- mBroadcastStats.put(pkg, bs);
+ bs = new BroadcastStats(uid, pkg);
+ uidStats.put(pkg, bs);
}
return bs;
}
}
}
- public void noteStartWakelock(int uid, int pid, String name, int type) {
+ public void noteStartWakelock(int uid, int pid, String name, int type,
+ boolean unimportantForLogging) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteStartWakeLocked(uid, pid, name, type);
+ mStats.noteStartWakeLocked(uid, pid, name, type, unimportantForLogging);
}
}
}
}
- public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, int type) {
+ public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, int type,
+ boolean unimportantForLogging) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteStartWakeFromSourceLocked(ws, pid, name, type);
+ mStats.noteStartWakeFromSourceLocked(ws, pid, name, type, unimportantForLogging);
}
}
isUnpluggedOnly = true;
} else if ("--reset".equals(arg)) {
synchronized (mStats) {
- mStats.resetAllStatsLocked();
+ mStats.resetAllStatsCmdLocked();
pw.println("Battery stats reset.");
noOutput = true;
}
mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
+
+ // Initialize screen on state.
+ if (mPowerState.isScreenOn()) {
+ mNotifier.onScreenOn();
+ } else {
+ mNotifier.onScreenOff();
+ }
+ mNotifier.onScreenBrightness(mPowerState.getScreenBrightness());
}
private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
try {
final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+ boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
+ && ownerUid == Process.SYSTEM_UID;
if (workSource != null) {
- mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType);
+ mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType,
+ unimportantForLogging);
} else {
- mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType);
+ mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType,
+ unimportantForLogging);
// XXX need to deal with disabled operations.
mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);