Merge "Various battery info things:" into gingerbread
This commit is contained in:
committed by
Android (Google) Code Review
commit
a8d9291d7f
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -18,5 +18,7 @@
|
||||
|
||||
<string name="waste_away">Discharge my battery!</string>
|
||||
|
||||
<string name="wake_away">Keep my device awake!</string>
|
||||
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user