Merge "Various battery info things:" into gingerbread

This commit is contained in:
Dianne Hackborn
2010-08-13 15:56:29 -07:00
committed by Android (Google) Code Review
13 changed files with 494 additions and 71 deletions

View File

@@ -365,7 +365,8 @@ public class ActivityManager {
/**
* The time when the service was first made active, either by someone
* starting or binding to it.
* starting or binding to it. This
* is in units of {@link android.os.SystemClock#elapsedRealtime()}.
*/
public long activeSince;
@@ -387,7 +388,8 @@ public class ActivityManager {
/**
* The time when there was last activity in the service (either
* explicit requests to start it or clients binding to it).
* explicit requests to start it or clients binding to it). This
* is in units of {@link android.os.SystemClock#uptimeMillis()}.
*/
public long lastActivityTime;

View File

@@ -290,6 +290,11 @@ public abstract class BatteryStats implements Parcelable {
*/
public static abstract class Proc {
public static class ExcessiveWake {
public long overTime;
public long usedTime;
}
/**
* Returns the total time (in 1/100 sec) spent executing in user code.
*
@@ -326,6 +331,10 @@ public abstract class BatteryStats implements Parcelable {
* @see BatteryStats#getCpuSpeedSteps()
*/
public abstract long getTimeAtCpuSpeedStep(int speedStep, int which);
public abstract int countExcessiveWakes();
public abstract ExcessiveWake getExcessiveWake(int i);
}
/**
@@ -421,6 +430,8 @@ public abstract class BatteryStats implements Parcelable {
public static final int STATE_BLUETOOTH_ON_FLAG = 1<<20;
public static final int STATE_AUDIO_ON_FLAG = 1<<19;
public static final int STATE_VIDEO_ON_FLAG = 1<<18;
public static final int STATE_WAKE_LOCK_FLAG = 1<<17;
public static final int STATE_SENSOR_ON_FLAG = 1<<16;
public int states;
@@ -470,6 +481,16 @@ public abstract class BatteryStats implements Parcelable {
batteryVoltage = o.batteryVoltage;
states = o.states;
}
public boolean same(HistoryItem o) {
return batteryLevel == o.batteryLevel
&& batteryStatus == o.batteryStatus
&& batteryHealth == o.batteryHealth
&& batteryPlugType == o.batteryPlugType
&& batteryTemperature == o.batteryTemperature
&& batteryVoltage == o.batteryVoltage
&& states == o.states;
}
}
public static final class BitDescription {
@@ -633,6 +654,8 @@ public abstract class BatteryStats implements Parcelable {
new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth"),
new BitDescription(HistoryItem.STATE_AUDIO_ON_FLAG, "audio"),
new BitDescription(HistoryItem.STATE_VIDEO_ON_FLAG, "video"),
new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock"),
new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor"),
new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK,
HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness",
SCREEN_BRIGHTNESS_NAMES),
@@ -1376,7 +1399,6 @@ public abstract class BatteryStats implements Parcelable {
pw.println(getDischargeStartLevel());
pw.print(prefix); pw.print(" Discharge cycle current level: ");
pw.println(getDischargeCurrentLevel());
} else {
pw.print(prefix); pw.println(" Device is currently plugged into power");
pw.print(prefix); pw.print(" Last discharge cycle start level: ");
pw.println(getDischargeStartLevel());
@@ -1384,6 +1406,13 @@ public abstract class BatteryStats implements Parcelable {
pw.println(getDischargeCurrentLevel());
}
pw.println(" ");
} else {
pw.print(prefix); pw.println(" Device battery use since last full charge");
pw.print(prefix); pw.print(" Amount discharged (lower bound): ");
pw.println(getLowDischargeAmountSinceCharge());
pw.print(prefix); pw.print(" Amount discharged (upper bound): ");
pw.println(getHighDischargeAmountSinceCharge());
pw.println(" ");
}
@@ -1524,12 +1553,16 @@ public abstract class BatteryStats implements Parcelable {
long userTime;
long systemTime;
int starts;
int numExcessive;
userTime = ps.getUserTime(which);
systemTime = ps.getSystemTime(which);
starts = ps.getStarts(which);
numExcessive = which == STATS_SINCE_CHARGED
? ps.countExcessiveWakes() : 0;
if (userTime != 0 || systemTime != 0 || starts != 0) {
if (userTime != 0 || systemTime != 0 || starts != 0
|| numExcessive != 0) {
sb.setLength(0);
sb.append(prefix); sb.append(" Proc ");
sb.append(ent.getKey()); sb.append(":\n");
@@ -1539,6 +1572,16 @@ public abstract class BatteryStats implements Parcelable {
sb.append(prefix); sb.append(" "); sb.append(starts);
sb.append(" proc starts");
pw.println(sb.toString());
for (int e=0; e<numExcessive; e++) {
Uid.Proc.ExcessiveWake ew = ps.getExcessiveWake(e);
if (ew != null) {
pw.print(prefix); pw.print(" * Killed for wake lock use: ");
pw.print(ew.usedTime); pw.print("ms over ");
pw.print(ew.overTime); pw.print("ms (");
pw.print((ew.usedTime*100)/ew.overTime);
pw.println("%)");
}
}
uidActivity = true;
}
}

View File

@@ -22,8 +22,8 @@ import android.telephony.SignalStrength;
interface IBatteryStats {
byte[] getStatistics();
void noteStartWakelock(int uid, String name, int type);
void noteStopWakelock(int uid, String name, int type);
void noteStartWakelock(int uid, int pid, String name, int type);
void noteStopWakelock(int uid, int pid, String name, int type);
/* DO NOT CHANGE the position of noteStartSensor without updating
SensorService.cpp */

View File

@@ -27,6 +27,7 @@ import android.os.ParcelFormatException;
import android.os.Parcelable;
import android.os.Process;
import android.os.SystemClock;
import android.os.BatteryStats.Uid.Proc.ExcessiveWake;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
@@ -63,7 +64,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
private static final int VERSION = 49;
private static final int VERSION = 50;
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 1000;
@@ -107,6 +108,7 @@ public final class BatteryStatsImpl extends BatteryStats {
int mNumHistoryItems;
HistoryItem mHistory;
HistoryItem mHistoryEnd;
HistoryItem mHistoryLastEnd;
HistoryItem mHistoryCache;
final HistoryItem mHistoryCur = new HistoryItem();
@@ -451,7 +453,7 @@ public final class BatteryStatsImpl extends BatteryStats {
* Clear state of this timer. Returns true if the timer is inactive
* so can be completely dropped.
*/
boolean reset(boolean detachIfReset) {
boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
mTotalTime = mLoadedTime = mLastTime = 0;
mCount = mLoadedCount = mLastCount = 0;
if (detachIfReset) {
@@ -713,8 +715,8 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(mTrackingReportedValues ? 1 : 0);
}
boolean reset(boolean detachIfReset) {
super.reset(detachIfReset);
boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
super.reset(stats, detachIfReset);
setStale();
return true;
}
@@ -749,7 +751,7 @@ public final class BatteryStatsImpl extends BatteryStats {
long mUpdateTime;
/**
* The total time at which the timer was acquired, to determine if
* The total time at which the timer was acquired, to determine if it
* was actually held for an interesting duration.
*/
long mAcquireTime;
@@ -890,9 +892,14 @@ public final class BatteryStatsImpl extends BatteryStats {
return mCount;
}
boolean reset(boolean detachIfReset) {
boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
boolean canDetach = mNesting <= 0;
super.reset(canDetach && detachIfReset);
super.reset(stats, canDetach && detachIfReset);
if (mNesting > 0) {
mUpdateTime = stats.getBatteryRealtimeLocked(
SystemClock.elapsedRealtime() * 1000);
}
mAcquireTime = mTotalTime;
return canDetach;
}
@@ -1113,6 +1120,26 @@ public final class BatteryStatsImpl extends BatteryStats {
if (!mHaveBatteryLevel || !mRecordingHistory) {
return;
}
// If the current time is basically the same as the last time,
// just collapse into one record.
if (mHistoryEnd != null && mHistoryEnd.cmd == HistoryItem.CMD_UPDATE
&& (mHistoryBaseTime+curTime) < (mHistoryEnd.time+100)) {
// If the current is the same as the one before, then we no
// longer need the entry.
if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE
&& mHistoryLastEnd.same(mHistoryCur)) {
mHistoryLastEnd.next = null;
mHistoryEnd.next = mHistoryCache;
mHistoryCache = mHistoryEnd;
mHistoryEnd = mHistoryLastEnd;
mHistoryLastEnd = null;
} else {
mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, mHistoryCur);
}
return;
}
if (mNumHistoryItems >= MAX_HISTORY_ITEMS) {
// Once we've reached the maximum number of items, we only
// record changes to the battery level.
@@ -1121,6 +1148,7 @@ public final class BatteryStatsImpl extends BatteryStats {
return;
}
}
addHistoryRecordLocked(curTime, HistoryItem.CMD_UPDATE);
}
@@ -1139,6 +1167,7 @@ public final class BatteryStatsImpl extends BatteryStats {
void addHistoryRecordLocked(HistoryItem rec) {
mNumHistoryItems++;
rec.next = null;
mHistoryLastEnd = mHistoryEnd;
if (mHistoryEnd != null) {
mHistoryEnd.next = rec;
mHistoryEnd = rec;
@@ -1151,7 +1180,7 @@ public final class BatteryStatsImpl extends BatteryStats {
if (mHistory != null) {
mHistoryEnd.next = mHistoryCache;
mHistoryCache = mHistory;
mHistory = mHistoryEnd = null;
mHistory = mHistoryLastEnd = mHistoryEnd = null;
}
mNumHistoryItems = 0;
mHistoryBaseTime = 0;
@@ -1209,6 +1238,83 @@ public final class BatteryStatsImpl extends BatteryStats {
mBluetoothPingStart = -1;
}
int mWakeLockNesting;
public void noteStartWakeLocked(int uid, int pid, String name, int type) {
if (mWakeLockNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
mWakeLockNesting++;
if (uid >= 0) {
getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type);
}
}
public void noteStopWakeLocked(int uid, int pid, String name, int type) {
mWakeLockNesting--;
if (mWakeLockNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
if (uid >= 0) {
getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type);
}
}
public void noteProcessDiedLocked(int uid, int pid) {
Uid u = mUidStats.get(uid);
if (u != null) {
u.mPids.remove(pid);
}
}
public long getProcessWakeTime(int uid, int pid, long realtime) {
Uid u = mUidStats.get(uid);
if (u != null) {
Uid.Pid p = u.mPids.get(pid);
if (p != null) {
return p.mWakeSum + (p.mWakeStart != 0 ? (realtime - p.mWakeStart) : 0);
}
}
return 0;
}
public void reportExcessiveWakeLocked(int uid, String proc, long overTime, long usedTime) {
Uid u = mUidStats.get(uid);
if (u != null) {
u.reportExcessiveWakeLocked(proc, overTime, usedTime);
}
}
int mSensorNesting;
public void noteStartSensorLocked(int uid, int sensor) {
if (mSensorNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
mSensorNesting++;
getUidStatsLocked(uid).noteStartSensor(sensor);
}
public void noteStopSensorLocked(int uid, int sensor) {
mSensorNesting--;
if (mSensorNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Stop sensor to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
getUidStatsLocked(uid).noteStopSensor(sensor);
}
int mGpsNesting;
public void noteStartGpsLocked(int uid) {
@@ -1244,6 +1350,10 @@ public final class BatteryStatsImpl extends BatteryStats {
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
}
// Fake a wake lock, so we consider the device waked as long
// as the screen is on.
noteStartWakeLocked(-1, -1, "dummy", 0);
}
}
@@ -1258,6 +1368,8 @@ public final class BatteryStatsImpl extends BatteryStats {
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
}
noteStopWakeLocked(-1, -1, "dummy", 0);
}
}
@@ -1798,6 +1910,11 @@ public final class BatteryStatsImpl extends BatteryStats {
*/
final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
/**
* The transient wake stats we have collected for this uid's pids.
*/
final SparseArray<Pid> mPids = new SparseArray<Pid>();
public Uid(int uid) {
mUid = uid;
mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables);
@@ -2081,27 +2198,27 @@ public final class BatteryStatsImpl extends BatteryStats {
boolean active = false;
if (mWifiTurnedOnTimer != null) {
active |= !mWifiTurnedOnTimer.reset(false);
active |= !mWifiTurnedOnTimer.reset(BatteryStatsImpl.this, false);
active |= mWifiTurnedOn;
}
if (mFullWifiLockTimer != null) {
active |= !mFullWifiLockTimer.reset(false);
active |= !mFullWifiLockTimer.reset(BatteryStatsImpl.this, false);
active |= mFullWifiLockOut;
}
if (mScanWifiLockTimer != null) {
active |= !mScanWifiLockTimer.reset(false);
active |= !mScanWifiLockTimer.reset(BatteryStatsImpl.this, false);
active |= mScanWifiLockOut;
}
if (mWifiMulticastTimer != null) {
active |= !mWifiMulticastTimer.reset(false);
active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
active |= mWifiMulticastEnabled;
}
if (mAudioTurnedOnTimer != null) {
active |= !mAudioTurnedOnTimer.reset(false);
active |= !mAudioTurnedOnTimer.reset(BatteryStatsImpl.this, false);
active |= mAudioTurnedOn;
}
if (mVideoTurnedOnTimer != null) {
active |= !mVideoTurnedOnTimer.reset(false);
active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
active |= mVideoTurnedOn;
}
@@ -2146,6 +2263,14 @@ public final class BatteryStatsImpl extends BatteryStats {
}
mProcessStats.clear();
}
if (mPids.size() > 0) {
for (int i=0; !active && i<mPids.size(); i++) {
Pid pid = mPids.valueAt(i);
if (pid.mWakeStart != 0) {
active = true;
}
}
}
if (mPackageStats.size() > 0) {
Iterator<Map.Entry<String, Pkg>> it = mPackageStats.entrySet().iterator();
while (it.hasNext()) {
@@ -2164,6 +2289,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mPackageStats.clear();
}
mPids.clear();
if (!active) {
if (mWifiTurnedOnTimer != null) {
mWifiTurnedOnTimer.detach();
@@ -2412,13 +2539,13 @@ public final class BatteryStatsImpl extends BatteryStats {
boolean reset() {
boolean wlactive = false;
if (mTimerFull != null) {
wlactive |= !mTimerFull.reset(false);
wlactive |= !mTimerFull.reset(BatteryStatsImpl.this, false);
}
if (mTimerPartial != null) {
wlactive |= !mTimerPartial.reset(false);
wlactive |= !mTimerPartial.reset(BatteryStatsImpl.this, false);
}
if (mTimerWindow != null) {
wlactive |= !mTimerWindow.reset(false);
wlactive |= !mTimerWindow.reset(BatteryStatsImpl.this, false);
}
if (!wlactive) {
if (mTimerFull != null) {
@@ -2486,7 +2613,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
boolean reset() {
if (mTimer.reset(true)) {
if (mTimer.reset(BatteryStatsImpl.this, true)) {
mTimer = null;
return true;
}
@@ -2598,6 +2725,8 @@ public final class BatteryStatsImpl extends BatteryStats {
SamplingCounter[] mSpeedBins;
ArrayList<ExcessiveWake> mExcessiveWake;
Proc() {
mUnpluggables.add(this);
mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
@@ -2624,6 +2753,58 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
public int countExcessiveWakes() {
return mExcessiveWake != null ? mExcessiveWake.size() : 0;
}
public ExcessiveWake getExcessiveWake(int i) {
if (mExcessiveWake != null) {
return mExcessiveWake.get(i);
}
return null;
}
public void addExcessiveWake(long overTime, long usedTime) {
if (mExcessiveWake == null) {
mExcessiveWake = new ArrayList<ExcessiveWake>();
}
ExcessiveWake ew = new ExcessiveWake();
ew.overTime = overTime;
ew.usedTime = usedTime;
mExcessiveWake.add(ew);
}
void writeExcessiveWakeToParcelLocked(Parcel out) {
if (mExcessiveWake == null) {
out.writeInt(0);
return;
}
final int N = mExcessiveWake.size();
out.writeInt(N);
for (int i=0; i<N; i++) {
ExcessiveWake ew = mExcessiveWake.get(i);
out.writeLong(ew.overTime);
out.writeLong(ew.usedTime);
}
}
void readExcessiveWakeFromParcelLocked(Parcel in) {
final int N = in.readInt();
if (N == 0) {
mExcessiveWake = null;
return;
}
mExcessiveWake = new ArrayList<ExcessiveWake>();
for (int i=0; i<N; i++) {
ExcessiveWake ew = new ExcessiveWake();
ew.overTime = in.readLong();
ew.usedTime = in.readLong();
mExcessiveWake.add(ew);
}
}
void writeToParcelLocked(Parcel out) {
out.writeLong(mUserTime);
out.writeLong(mSystemTime);
@@ -2648,6 +2829,8 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(0);
}
}
writeExcessiveWakeToParcelLocked(out);
}
void readFromParcelLocked(Parcel in) {
@@ -2676,6 +2859,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
}
}
readExcessiveWakeFromParcelLocked(in);
}
public BatteryStatsImpl getBatteryStats() {
@@ -3153,6 +3338,11 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
public class Pid {
long mWakeSum;
long mWakeStart;
}
/**
* Retrieve the statistics object for a particular process, creating
* if needed.
@@ -3167,6 +3357,15 @@ public final class BatteryStatsImpl extends BatteryStats {
return ps;
}
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.
@@ -3259,18 +3458,36 @@ public final class BatteryStatsImpl extends BatteryStats {
return t;
}
public void noteStartWakeLocked(String name, int type) {
public void noteStartWakeLocked(int pid, String name, int type) {
StopwatchTimer t = getWakeTimerLocked(name, type);
if (t != null) {
t.startRunningLocked(BatteryStatsImpl.this);
}
if (pid >= 0) {
Pid p = getPidStatsLocked(pid);
p.mWakeStart = SystemClock.elapsedRealtime();
}
}
public void noteStopWakeLocked(String name, int type) {
public void noteStopWakeLocked(int pid, String name, int type) {
StopwatchTimer t = getWakeTimerLocked(name, type);
if (t != null) {
t.stopRunningLocked(BatteryStatsImpl.this);
}
if (pid >= 0) {
Pid p = mPids.get(pid);
if (p != null) {
p.mWakeSum += SystemClock.elapsedRealtime() - p.mWakeStart;
p.mWakeStart = 0;
}
}
}
public void reportExcessiveWakeLocked(String proc, long overTime, long usedTime) {
Proc p = getProcessStatsLocked(proc);
if (p != null) {
p.addExcessiveWake(overTime, usedTime);
}
}
public void noteStartSensor(int sensor) {
@@ -3372,6 +3589,10 @@ public final class BatteryStatsImpl extends BatteryStats {
return mOnBattery;
}
public boolean isScreenOn() {
return mScreenOn;
}
void initTimes() {
mBatteryRealtime = mTrackBatteryPastUptime = 0;
mBatteryUptime = mTrackBatteryPastRealtime = 0;
@@ -3384,24 +3605,24 @@ public final class BatteryStatsImpl extends BatteryStats {
public void resetAllStatsLocked() {
mStartCount = 0;
initTimes();
mScreenOnTimer.reset(false);
mScreenOnTimer.reset(this, false);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].reset(false);
mScreenBrightnessTimer[i].reset(this, false);
}
mInputEventCounter.reset(false);
mPhoneOnTimer.reset(false);
mAudioOnTimer.reset(false);
mVideoOnTimer.reset(false);
mPhoneOnTimer.reset(this, false);
mAudioOnTimer.reset(this, false);
mVideoOnTimer.reset(this, false);
for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].reset(false);
mPhoneSignalStrengthsTimer[i].reset(this, false);
}
mPhoneSignalScanningTimer.reset(false);
mPhoneSignalScanningTimer.reset(this, false);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i].reset(false);
mPhoneDataConnectionsTimer[i].reset(this, false);
}
mWifiOnTimer.reset(false);
mWifiRunningTimer.reset(false);
mBluetoothOnTimer.reset(false);
mWifiOnTimer.reset(this, false);
mWifiRunningTimer.reset(this, false);
mBluetoothOnTimer.reset(this, false);
for (int i=0; i<mUidStats.size(); i++) {
if (mUidStats.valueAt(i).reset()) {
@@ -4083,6 +4304,7 @@ public final class BatteryStatsImpl extends BatteryStats {
p.mUserTime = p.mLoadedUserTime = in.readLong();
p.mSystemTime = p.mLoadedSystemTime = in.readLong();
p.mStarts = p.mLoadedStarts = in.readInt();
p.readExcessiveWakeFromParcelLocked(in);
}
NP = in.readInt();
@@ -4271,6 +4493,7 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeLong(ps.mUserTime);
out.writeLong(ps.mSystemTime);
out.writeInt(ps.mStarts);
ps.writeExcessiveWakeToParcelLocked(out);
}
}

View File

@@ -151,6 +151,7 @@ class PowerManagerService extends IPowerManager.Stub
static final int INITIAL_KEYBOARD_BRIGHTNESS = Power.BRIGHTNESS_OFF;
private final int MY_UID;
private final int MY_PID;
private boolean mDoneBooting = false;
private boolean mBootCompleted = false;
@@ -309,7 +310,7 @@ class PowerManagerService extends IPowerManager.Stub
long ident = Binder.clearCallingIdentity();
try {
PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken,
MY_UID, mTag);
MY_UID, MY_PID, mTag);
mHeld = true;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -434,11 +435,11 @@ class PowerManagerService extends IPowerManager.Stub
}
}
PowerManagerService()
{
PowerManagerService() {
// Hack to get our uid... should have a func for this.
long token = Binder.clearCallingIdentity();
MY_UID = Binder.getCallingUid();
MY_UID = Process.myUid();
MY_PID = Process.myPid();
Binder.restoreCallingIdentity(token);
// XXX remove this when the kernel doesn't timeout wake locks
@@ -573,13 +574,13 @@ class PowerManagerService extends IPowerManager.Stub
private class WakeLock implements IBinder.DeathRecipient
{
WakeLock(int f, IBinder b, String t, int u) {
WakeLock(int f, IBinder b, String t, int u, int p) {
super();
flags = f;
binder = b;
tag = t;
uid = u == MY_UID ? Process.SYSTEM_UID : u;
pid = Binder.getCallingPid();
pid = p;
if (u != MY_UID || (
!"KEEP_SCREEN_ON_FLAG".equals(tag)
&& !"KeyInputQueue".equals(tag))) {
@@ -631,21 +632,23 @@ class PowerManagerService extends IPowerManager.Stub
public void acquireWakeLock(int flags, IBinder lock, String tag) {
int uid = Binder.getCallingUid();
int pid = Binder.getCallingPid();
if (uid != Process.myUid()) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
}
long ident = Binder.clearCallingIdentity();
try {
synchronized (mLocks) {
acquireWakeLockLocked(flags, lock, uid, tag);
acquireWakeLockLocked(flags, lock, uid, pid, tag);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
public void acquireWakeLockLocked(int flags, IBinder lock, int uid, String tag) {
public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag) {
int acquireUid = -1;
int acquirePid = -1;
String acquireName = null;
int acquireType = -1;
@@ -657,7 +660,7 @@ class PowerManagerService extends IPowerManager.Stub
WakeLock wl;
boolean newlock;
if (index < 0) {
wl = new WakeLock(flags, lock, tag, uid);
wl = new WakeLock(flags, lock, tag, uid, pid);
switch (wl.flags & LOCK_MASK)
{
case PowerManager.FULL_WAKE_LOCK:
@@ -730,13 +733,14 @@ class PowerManagerService extends IPowerManager.Stub
}
if (newlock) {
acquireUid = wl.uid;
acquirePid = wl.pid;
acquireName = wl.tag;
acquireType = wl.monitorType;
}
if (acquireType >= 0) {
try {
mBatteryStats.noteStartWakelock(acquireUid, acquireName, acquireType);
mBatteryStats.noteStartWakelock(acquireUid, acquirePid, acquireName, acquireType);
} catch (RemoteException e) {
// Ignore
}
@@ -756,6 +760,7 @@ class PowerManagerService extends IPowerManager.Stub
private void releaseWakeLockLocked(IBinder lock, int flags, boolean death) {
int releaseUid;
int releasePid;
String releaseName;
int releaseType;
@@ -800,13 +805,14 @@ class PowerManagerService extends IPowerManager.Stub
// Unlink the lock from the binder.
wl.binder.unlinkToDeath(wl, 0);
releaseUid = wl.uid;
releasePid = wl.pid;
releaseName = wl.tag;
releaseType = wl.monitorType;
if (releaseType >= 0) {
long origId = Binder.clearCallingIdentity();
try {
mBatteryStats.noteStopWakelock(releaseUid, releaseName, releaseType);
mBatteryStats.noteStopWakelock(releaseUid, releasePid, releaseName, releaseType);
} catch (RemoteException e) {
// Ignore
} finally {

View File

@@ -8081,12 +8081,12 @@ public class WindowManagerService extends IWindowManager.Stub
if (oldHold != newHold) {
try {
if (oldHold != null) {
mBatteryStats.noteStopWakelock(oldHold.mUid,
mBatteryStats.noteStopWakelock(oldHold.mUid, -1,
"window",
BatteryStats.WAKE_TYPE_WINDOW);
}
if (newHold != null) {
mBatteryStats.noteStartWakelock(newHold.mUid,
mBatteryStats.noteStartWakelock(newHold.mUid, -1,
"window",
BatteryStats.WAKE_TYPE_WINDOW);
}

View File

@@ -199,6 +199,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// The minimum amount of time between successive GC requests for a process.
static final int GC_MIN_INTERVAL = 60*1000;
// The rate at which we check for apps using excessive wake locks -- 15 mins.
static final int WAKE_LOCK_CHECK_DELAY = 15*60*1000;
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_TIMEOUT = 10*1000;
@@ -769,6 +772,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
*/
boolean mDidAppSwitch;
/**
* Last time (in realtime) at which we checked for wake lock usage.
*/
long mLastWakeLockCheckTime;
/**
* Set while we are wanting to sleep, to prevent any
* activities from being started/resumed.
@@ -914,6 +922,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
static final int POST_HEAVY_NOTIFICATION_MSG = 24;
static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;
static final int SHOW_STRICT_MODE_VIOLATION_MSG = 26;
static final int CHECK_EXCESSIVE_WAKE_LOCKS_MSG = 27;
AlertDialog mUidAlert;
@@ -1173,6 +1182,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} catch (RemoteException e) {
}
} break;
case CHECK_EXCESSIVE_WAKE_LOCKS_MSG: {
synchronized (ActivityManagerService.this) {
checkExcessiveWakeLocksLocked(true);
mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
if (mSleeping) {
Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY);
}
}
} break;
}
}
};
@@ -2555,6 +2574,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mProcDeaths[0]++;
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
stats.noteProcessDiedLocked(app.info.uid, pid);
}
// Clean up already done if the process has been re-started.
if (app.pid == pid && app.thread != null &&
app.thread.asBinder() == thread.asBinder()) {
@@ -3570,6 +3594,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
// Start looking for apps that are abusing wake locks.
Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY);
// Tell anyone interested that we are done booting!
SystemProperties.set("sys.boot_completed", "1");
broadcastIntentLocked(null, null,
@@ -5375,6 +5402,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} else {
Slog.w(TAG, "goingToSleep with no resumed activity!");
}
// Initialize the wake times of all processes.
checkExcessiveWakeLocksLocked(false);
mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY);
}
}
@@ -5424,6 +5457,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mWindowManager.setEventDispatching(true);
mSleeping = false;
mMainStack.resumeTopActivityLocked(null);
mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
}
}
@@ -11259,6 +11293,52 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
final void checkExcessiveWakeLocksLocked(boolean doKills) {
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
if (mLastWakeLockCheckTime == 0) {
doKills = false;
}
if (stats.isScreenOn()) {
doKills = false;
}
final long curRealtime = SystemClock.elapsedRealtime();
final long timeSince = curRealtime - mLastWakeLockCheckTime;
mLastWakeLockCheckTime = curRealtime;
if (timeSince < 5*60*1000) {
doKills = false;
}
int i = mLruProcesses.size();
while (i > 0) {
i--;
ProcessRecord app = mLruProcesses.get(i);
if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
long wtime;
synchronized (stats) {
wtime = stats.getProcessWakeTime(app.info.uid,
app.pid, curRealtime);
}
long timeUsed = wtime - app.lastWakeTime;
Slog.i(TAG, "Wake for " + app + ": over "
+ timeSince + " used " + timeUsed
+ " (" + ((timeUsed*100)/timeSince) + "%)");
// If a process has held a wake lock for more
// than 50% of the time during this period,
// that sounds pad. Kill!
if (doKills && timeSince > 0
&& ((timeUsed*100)/timeSince) >= 50) {
Slog.i(TAG, "Excessive wake lock in " + app.processName
+ " (pid " + app.pid + "): held " + timeUsed
+ " during " + timeSince);
EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
app.processName, app.setAdj, "excessive wake lock");
Process.killProcessQuiet(app.pid);
} else {
app.lastWakeTime = wtime;
}
}
}
}
private final boolean updateOomAdjLocked(
ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
app.hiddenAdj = hiddenAdj;
@@ -11281,6 +11361,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Likewise do a gc when an app is moving in to the
// background (such as a service stopping).
scheduleAppGcLocked(app);
// And note its current wake lock time.
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
app.pid, SystemClock.elapsedRealtime());
}
}
app.setRawAdj = app.curRawAdj;
}

View File

@@ -93,31 +93,31 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
return data;
}
public void noteStartWakelock(int uid, String name, int type) {
public void noteStartWakelock(int uid, int pid, String name, int type) {
enforceCallingPermission();
synchronized (mStats) {
mStats.getUidStatsLocked(uid).noteStartWakeLocked(name, type);
mStats.noteStartWakeLocked(uid, pid, name, type);
}
}
public void noteStopWakelock(int uid, String name, int type) {
public void noteStopWakelock(int uid, int pid, String name, int type) {
enforceCallingPermission();
synchronized (mStats) {
mStats.getUidStatsLocked(uid).noteStopWakeLocked(name, type);
mStats.noteStopWakeLocked(uid, pid, name, type);
}
}
public void noteStartSensor(int uid, int sensor) {
enforceCallingPermission();
synchronized (mStats) {
mStats.getUidStatsLocked(uid).noteStartSensor(sensor);
mStats.noteStartSensorLocked(uid, sensor);
}
}
public void noteStopSensor(int uid, int sensor) {
enforceCallingPermission();
synchronized (mStats) {
mStats.getUidStatsLocked(uid).noteStopSensor(sensor);
mStats.noteStopSensorLocked(uid, sensor);
}
}

View File

@@ -74,6 +74,7 @@ class ProcessRecord {
Bundle instrumentationArguments;// as given to us
ComponentName instrumentationResultClass;// copy of instrumentationClass
BroadcastRecord curReceiver;// receiver currently running in the app
long lastWakeTime; // How long proc held wake lock at last check
long lastRequestedGc; // When we last asked the app to do a gc
long lastLowMemory; // When we last told the app that memory is low
boolean reportLowMemory; // Set to true when waiting to report low mem
@@ -158,7 +159,7 @@ class ProcessRecord {
pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting=");
pw.print(starting); pw.print(" lastPss="); pw.println(lastPss);
pw.print(prefix); pw.print("lastActivityTime="); pw.print(lastActivityTime);
pw.print(" lruWeight="); pw.println(lruWeight);
pw.print(" lruWeight="); pw.print(lruWeight);
pw.print(" hidden="); pw.print(hidden);
pw.print(" empty="); pw.println(empty);
pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
@@ -177,6 +178,10 @@ class ProcessRecord {
pw.print(" persistentActivities="); pw.println(persistentActivities);
pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
pw.print(" lruSeq="); pw.println(lruSeq);
pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime);
pw.print(" lastRequestedGc="); pw.print(lastRequestedGc);
pw.print(" lastLowMemory="); pw.print(lastLowMemory);
pw.print(" reportLowMemory="); pw.println(reportLowMemory);
if (killedBackground) {
pw.print(prefix); pw.print("killedBackground="); pw.println(killedBackground);
}

View File

@@ -149,7 +149,9 @@ class ServiceRecord extends Binder {
pw.print(" foregroundId="); pw.print(foregroundId);
pw.print(" foregroundNoti="); pw.println(foregroundNoti);
}
pw.print(prefix); pw.print("lastActivity="); pw.print(lastActivity-now);
pw.print(prefix); pw.print("createTime=");
pw.print(createTime-SystemClock.elapsedRealtime());
pw.print(" lastActivity="); pw.print(lastActivity-now);
pw.print(" executingStart="); pw.print(executingStart-now);
pw.print(" restartTime="); pw.println(restartTime);
if (startRequested || lastStartId != 0) {
@@ -213,7 +215,8 @@ class ServiceRecord extends Binder {
dataDir = sInfo.applicationInfo.dataDir;
exported = sInfo.exported;
this.restarter = restarter;
createTime = lastActivity = SystemClock.uptimeMillis();
createTime = SystemClock.elapsedRealtime();
lastActivity = SystemClock.uptimeMillis();
}
public AppBindRecord retrieveAppBindingLocked(Intent intent,

View File

@@ -30,6 +30,16 @@
android:text="@string/waste_away"
/>
<CheckBox android:id="@+id/checkbox_wake"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginTop="25dp"
android:textSize="18sp"
android:textColor="#ffffffff"
android:text="@string/wake_away"
/>
<ScrollView android:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="0px"

View File

@@ -18,5 +18,7 @@
<string name="waste_away">Discharge my battery!</string>
<string name="wake_away">Keep my device awake!</string>
</resources>

View File

@@ -41,6 +41,8 @@ public class BatteryWaster extends Activity {
PowerManager.WakeLock mWakeLock;
SpinThread mThread;
boolean mWasting, mWaking;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -50,6 +52,7 @@ public class BatteryWaster extends Activity {
setContentView(R.layout.battery_waster);
findViewById(R.id.checkbox).setOnClickListener(mClickListener);
findViewById(R.id.checkbox_wake).setOnClickListener(mWakeClickListener);
mLog = (TextView)findViewById(R.id.log);
mDateFormat = DateFormat.getInstance();
@@ -67,9 +70,18 @@ public class BatteryWaster extends Activity {
@Override
public void onPause() {
super.onPause();
stopRunning();
}
@Override
public void onDestroy() {
super.onDestroy();
if (mWakeLock.isHeld()) {
mWakeLock.release();
}
}
View.OnClickListener mClickListener = new View.OnClickListener() {
public void onClick(View v) {
CheckBox checkbox = (CheckBox)v;
@@ -81,23 +93,54 @@ public class BatteryWaster extends Activity {
}
};
View.OnClickListener mWakeClickListener = new View.OnClickListener() {
public void onClick(View v) {
CheckBox checkbox = (CheckBox)v;
if (checkbox.isChecked()) {
mWaking = true;
updateWakeLock();
} else {
mWaking = false;
updateWakeLock();
}
}
};
void startRunning() {
log("Start");
registerReceiver(mReceiver, mFilter);
mWakeLock.acquire();
if (mThread == null) {
mThread = new SpinThread();
mThread.start();
if (!mWasting) {
log("Start");
registerReceiver(mReceiver, mFilter);
mWasting = true;
updateWakeLock();
if (mThread == null) {
mThread = new SpinThread();
mThread.start();
}
}
}
void stopRunning() {
log("Stop");
unregisterReceiver(mReceiver);
mWakeLock.release();
if (mThread != null) {
mThread.quit();
mThread = null;
if (mWasting) {
log("Stop");
unregisterReceiver(mReceiver);
mWasting = false;
updateWakeLock();
if (mThread != null) {
mThread.quit();
mThread = null;
}
}
}
void updateWakeLock() {
if (mWasting || mWaking) {
if (!mWakeLock.isHeld()) {
mWakeLock.acquire();
}
} else {
if (mWakeLock.isHeld()) {
mWakeLock.release();
}
}
}