Adjust activity manager process OOM adj.
Modify OOM adj classes a bit, to take into account the new
heavy weight app type, and give "foreground services" their
own category to have a bettery chance to manager them when
things go wrong.
Also add some new code to battery stats to keep a history
of changes to the battery level.
Change-Id: I29f5ab6938777e1a7eafd7d8c38b5e564cc9f96a
diff --git a/api/current.xml b/api/current.xml
index 8dd57f0..41b0423 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -21763,7 +21763,18 @@
type="int"
transient="false"
volatile="false"
- value="150"
+ value="170"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IMPORTANCE_PERCEPTIBLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="130"
static="true"
final="true"
deprecated="not deprecated"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 793b9d2..7f95bf5 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -726,16 +726,24 @@
public static final int IMPORTANCE_FOREGROUND = 100;
/**
- * Constant for {@link #importance}: this process is running a
- * heavy-weight application and thus should not be killed.
+ * Constant for {@link #importance}: this process is running something
+ * that is actively visible to the user, though not in the immediate
+ * foreground.
*/
- public static final int IMPORTANCE_HEAVY_WEIGHT = 150;
+ public static final int IMPORTANCE_VISIBLE = 200;
/**
* Constant for {@link #importance}: this process is running something
- * that is considered to be actively visible to the user.
+ * that is considered to be actively perceptible to the user. An
+ * example would be an application performing background music playback.
*/
- public static final int IMPORTANCE_VISIBLE = 200;
+ public static final int IMPORTANCE_PERCEPTIBLE = 130;
+
+ /**
+ * Constant for {@link #importance}: this process is running a
+ * heavy-weight application and thus should not be killed.
+ */
+ public static final int IMPORTANCE_HEAVY_WEIGHT = 170;
/**
* Constant for {@link #importance}: this process is contains services
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index d114bff..4adeaeb 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -51,50 +51,36 @@
/**
* A constant indicating a sensor timer.
- *
- * {@hide}
*/
public static final int SENSOR = 3;
/**
* A constant indicating a a wifi turn on timer
- *
- * {@hide}
*/
public static final int WIFI_TURNED_ON = 4;
/**
* A constant indicating a full wifi lock timer
- *
- * {@hide}
*/
public static final int FULL_WIFI_LOCK = 5;
/**
* A constant indicating a scan wifi lock timer
- *
- * {@hide}
*/
public static final int SCAN_WIFI_LOCK = 6;
/**
* A constant indicating a wifi multicast timer
- *
- * {@hide}
*/
public static final int WIFI_MULTICAST_ENABLED = 7;
/**
* A constant indicating an audio turn on timer
- *
- * {@hide}
*/
public static final int AUDIO_TURNED_ON = 7;
/**
* A constant indicating a video turn on timer
- *
- * {@hide}
*/
public static final int VIDEO_TURNED_ON = 8;
@@ -391,6 +377,61 @@
}
}
+ public final class BatteryHistoryRecord implements Parcelable {
+ public BatteryHistoryRecord next;
+
+ public long time;
+ public byte batteryLevel;
+
+ public static final int STATE_SCREEN_MASK = 0x000000f;
+ public static final int STATE_SCREEN_SHIFT = 0;
+ public static final int STATE_SIGNAL_STRENGTH_MASK = 0x00000f0;
+ public static final int STATE_SIGNAL_STRENGTH_SHIFT = 4;
+ public static final int STATE_PHONE_STATE_MASK = 0x0000f00;
+ public static final int STATE_PHONE_STATE_SHIFT = 8;
+ public static final int STATE_DATA_CONNECTION_MASK = 0x000f000;
+ public static final int STATE_DATA_CONNECTION_SHIFT = 12;
+
+ public static final int STATE_BATTERY_PLUGGED_FLAG = 1<<30;
+ public static final int STATE_SCREEN_ON_FLAG = 1<<29;
+ public static final int STATE_GPS_ON_FLAG = 1<<28;
+ public static final int STATE_PHONE_ON_FLAG = 1<<27;
+ public static final int STATE_WIFI_ON_FLAG = 1<<26;
+ public static final int STATE_WIFI_RUNNING_FLAG = 1<<25;
+ public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<24;
+ public static final int STATE_WIFI_SCAN_LOCK_FLAG = 1<<23;
+ public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<22;
+ public static final int STATE_BLUETOOTH_ON_FLAG = 1<<21;
+ public static final int STATE_AUDIO_ON_FLAG = 1<<20;
+ public static final int STATE_VIDEO_ON_FLAG = 1<<19;
+
+ public int states;
+
+ public BatteryHistoryRecord() {
+ }
+
+ public BatteryHistoryRecord(long time, Parcel src) {
+ this.time = time;
+ batteryLevel = (byte)src.readInt();
+ states = src.readInt();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(time);
+ dest.writeInt(batteryLevel);
+ dest.writeInt(states);
+ }
+ }
+
+ /**
+ * Return the current history of battery state changes.
+ */
+ public abstract BatteryHistoryRecord getHistory();
+
/**
* Returns the number of times the device has been started.
*/
@@ -1443,6 +1484,20 @@
*/
@SuppressWarnings("unused")
public void dumpLocked(PrintWriter pw) {
+ BatteryHistoryRecord rec = getHistory();
+ if (rec != null) {
+ pw.println("Battery History:");
+ while (rec != null) {
+ pw.print(" ");
+ pw.print(rec.time);
+ pw.print(" ");
+ pw.print(rec.batteryLevel);
+ pw.print(" ");
+ pw.println(Integer.toHexString(rec.states));
+ rec = rec.next;
+ }
+ }
+
pw.println("Total Statistics (Current and Historic):");
pw.println(" System starts: " + getStartCount()
+ ", currently on battery: " + getIsOnBattery());
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index aadb576..3833725 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -56,12 +56,13 @@
public final class BatteryStatsImpl extends BatteryStats {
private static final String TAG = "BatteryStatsImpl";
private static final boolean DEBUG = false;
-
+ private static final boolean DEBUG_HISTORY = false;
+
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 43;
+ private static final int VERSION = 44;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -94,6 +95,11 @@
// is unplugged from power.
final ArrayList<Unpluggable> mUnpluggables = new ArrayList<Unpluggable>();
+ BatteryHistoryRecord mHistory;
+ BatteryHistoryRecord mHistoryEnd;
+ BatteryHistoryRecord mHistoryCache;
+ final BatteryHistoryRecord mHistoryCur = new BatteryHistoryRecord();
+
int mStartCount;
long mBatteryUptime;
@@ -1042,6 +1048,37 @@
mBtHeadset = headset;
}
+ void addHistoryRecord(long curTime) {
+ BatteryHistoryRecord rec = mHistoryCache;
+ if (rec != null) {
+ mHistoryCache = rec.next;
+ } else {
+ rec = new BatteryHistoryRecord();
+ }
+ rec.time = curTime;
+ rec.batteryLevel = mHistoryCur.batteryLevel;
+ rec.states = mHistoryCur.states;
+ addHistoryRecord(rec);
+ }
+
+ void addHistoryRecord(BatteryHistoryRecord rec) {
+ rec.next = null;
+ if (mHistoryEnd != null) {
+ mHistoryEnd.next = rec;
+ mHistoryEnd = rec;
+ } else {
+ mHistory = mHistoryEnd = rec;
+ }
+ }
+
+ void clearHistory() {
+ if (mHistory != null) {
+ mHistoryEnd.next = mHistoryCache;
+ mHistoryCache = mHistory;
+ mHistory = mHistoryEnd = null;
+ }
+ }
+
public void doUnplug(long batteryUptime, long batteryRealtime) {
for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
Uid u = mUidStats.valueAt(iu);
@@ -1094,16 +1131,37 @@
mBluetoothPingStart = -1;
}
+ int mGpsNesting;
+
public void noteStartGps(int uid) {
+ if (mGpsNesting == 0) {
+ mHistoryCur.states |= BatteryHistoryRecord.STATE_GPS_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
+ }
+ mGpsNesting++;
getUidStatsLocked(uid).noteStartGps();
}
public void noteStopGps(int uid) {
+ mGpsNesting--;
+ if (mGpsNesting == 0) {
+ mHistoryCur.states &= ~BatteryHistoryRecord.STATE_GPS_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Stop GPS to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
+ }
getUidStatsLocked(uid).noteStopGps();
}
public void noteScreenOnLocked() {
if (!mScreenOn) {
+ mHistoryCur.states |= BatteryHistoryRecord.STATE_SCREEN_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
+ mGpsNesting++;
mScreenOn = true;
mScreenOnTimer.startRunningLocked(this);
if (mScreenBrightnessBin >= 0) {
@@ -1114,6 +1172,10 @@
public void noteScreenOffLocked() {
if (mScreenOn) {
+ mHistoryCur.states &= ~BatteryHistoryRecord.STATE_SCREEN_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
mScreenOn = false;
mScreenOnTimer.stopRunningLocked(this);
if (mScreenBrightnessBin >= 0) {
@@ -1128,6 +1190,11 @@
if (bin < 0) bin = 0;
else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
if (mScreenBrightnessBin != bin) {
+ mHistoryCur.states = (mHistoryCur.states&~BatteryHistoryRecord.STATE_SCREEN_MASK)
+ | (bin << BatteryHistoryRecord.STATE_SCREEN_SHIFT);
+ if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
if (mScreenOn) {
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
@@ -1148,6 +1215,10 @@
public void notePhoneOnLocked() {
if (!mPhoneOn) {
+ mHistoryCur.states |= BatteryHistoryRecord.STATE_PHONE_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
mPhoneOn = true;
mPhoneOnTimer.startRunningLocked(this);
}
@@ -1155,6 +1226,10 @@
public void notePhoneOffLocked() {
if (mPhoneOn) {
+ mHistoryCur.states &= ~BatteryHistoryRecord.STATE_PHONE_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
mPhoneOn = false;
mPhoneOnTimer.stopRunningLocked(this);
}
@@ -1195,7 +1270,15 @@
mPhoneSignalScanningTimer.startRunningLocked(this);
}
}
- mPhoneServiceState = state;
+
+ if (mPhoneServiceState != state) {
+ mHistoryCur.states = (mHistoryCur.states&~BatteryHistoryRecord.STATE_PHONE_STATE_MASK)
+ | (state << BatteryHistoryRecord.STATE_PHONE_STATE_SHIFT);
+ if (DEBUG_HISTORY) Slog.v(TAG, "Phone state " + bin + " to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
+ mPhoneServiceState = state;
+ }
}
public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
@@ -1222,6 +1305,11 @@
else bin = SIGNAL_STRENGTH_POOR;
}
if (mPhoneSignalStrengthBin != bin) {
+ mHistoryCur.states = (mHistoryCur.states&~BatteryHistoryRecord.STATE_SIGNAL_STRENGTH_MASK)
+ | (bin << BatteryHistoryRecord.STATE_SIGNAL_STRENGTH_SHIFT);
+ if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + bin + " to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
if (mPhoneSignalStrengthBin >= 0) {
mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this);
}
@@ -1250,6 +1338,11 @@
}
if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
if (mPhoneDataConnectionType != bin) {
+ mHistoryCur.states = (mHistoryCur.states&~BatteryHistoryRecord.STATE_DATA_CONNECTION_MASK)
+ | (bin << BatteryHistoryRecord.STATE_DATA_CONNECTION_SHIFT);
+ if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
if (mPhoneDataConnectionType >= 0) {
mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this);
}
@@ -1260,6 +1353,10 @@
public void noteWifiOnLocked(int uid) {
if (!mWifiOn) {
+ mHistoryCur.states |= BatteryHistoryRecord.STATE_WIFI_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
mWifiOn = true;
mWifiOnTimer.startRunningLocked(this);
}
@@ -1274,6 +1371,10 @@
public void noteWifiOffLocked(int uid) {
if (mWifiOn) {
+ mHistoryCur.states &= ~BatteryHistoryRecord.STATE_WIFI_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
mWifiOn = false;
mWifiOnTimer.stopRunningLocked(this);
}
@@ -1285,6 +1386,10 @@
public void noteAudioOnLocked(int uid) {
if (!mAudioOn) {
+ mHistoryCur.states |= BatteryHistoryRecord.STATE_AUDIO_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
mAudioOn = true;
mAudioOnTimer.startRunningLocked(this);
}
@@ -1293,6 +1398,10 @@
public void noteAudioOffLocked(int uid) {
if (mAudioOn) {
+ mHistoryCur.states &= ~BatteryHistoryRecord.STATE_AUDIO_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
mAudioOn = false;
mAudioOnTimer.stopRunningLocked(this);
}
@@ -1301,6 +1410,10 @@
public void noteVideoOnLocked(int uid) {
if (!mVideoOn) {
+ mHistoryCur.states |= BatteryHistoryRecord.STATE_VIDEO_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
mVideoOn = true;
mVideoOnTimer.startRunningLocked(this);
}
@@ -1309,6 +1422,10 @@
public void noteVideoOffLocked(int uid) {
if (mVideoOn) {
+ mHistoryCur.states &= ~BatteryHistoryRecord.STATE_VIDEO_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
mVideoOn = false;
mVideoOnTimer.stopRunningLocked(this);
}
@@ -1317,6 +1434,10 @@
public void noteWifiRunningLocked() {
if (!mWifiRunning) {
+ mHistoryCur.states |= BatteryHistoryRecord.STATE_WIFI_RUNNING_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
mWifiRunning = true;
mWifiRunningTimer.startRunningLocked(this);
}
@@ -1324,6 +1445,10 @@
public void noteWifiStoppedLocked() {
if (mWifiRunning) {
+ mHistoryCur.states &= ~BatteryHistoryRecord.STATE_WIFI_RUNNING_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
mWifiRunning = false;
mWifiRunningTimer.stopRunningLocked(this);
}
@@ -1331,6 +1456,10 @@
public void noteBluetoothOnLocked() {
if (!mBluetoothOn) {
+ mHistoryCur.states |= BatteryHistoryRecord.STATE_BLUETOOTH_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth on to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
mBluetoothOn = true;
mBluetoothOnTimer.startRunningLocked(this);
}
@@ -1338,32 +1467,84 @@
public void noteBluetoothOffLocked() {
if (mBluetoothOn) {
+ mHistoryCur.states &= ~BatteryHistoryRecord.STATE_BLUETOOTH_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth off to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
mBluetoothOn = false;
mBluetoothOnTimer.stopRunningLocked(this);
}
}
+ int mWifiFullLockNesting = 0;
+
public void noteFullWifiLockAcquiredLocked(int uid) {
+ if (mWifiFullLockNesting == 0) {
+ mHistoryCur.states |= BatteryHistoryRecord.STATE_WIFI_FULL_LOCK_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
+ }
+ mWifiFullLockNesting++;
getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
}
public void noteFullWifiLockReleasedLocked(int uid) {
+ mWifiFullLockNesting--;
+ if (mWifiFullLockNesting == 0) {
+ mHistoryCur.states &= ~BatteryHistoryRecord.STATE_WIFI_FULL_LOCK_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
+ }
getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
}
+ int mWifiScanLockNesting = 0;
+
public void noteScanWifiLockAcquiredLocked(int uid) {
+ if (mWifiScanLockNesting == 0) {
+ mHistoryCur.states |= BatteryHistoryRecord.STATE_WIFI_SCAN_LOCK_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock on to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
+ }
+ mWifiScanLockNesting++;
getUidStatsLocked(uid).noteScanWifiLockAcquiredLocked();
}
public void noteScanWifiLockReleasedLocked(int uid) {
+ mWifiScanLockNesting--;
+ if (mWifiScanLockNesting == 0) {
+ mHistoryCur.states &= ~BatteryHistoryRecord.STATE_WIFI_SCAN_LOCK_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan lock off to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
+ }
getUidStatsLocked(uid).noteScanWifiLockReleasedLocked();
}
+ int mWifiMulticastNesting = 0;
+
public void noteWifiMulticastEnabledLocked(int uid) {
+ if (mWifiMulticastNesting == 0) {
+ mHistoryCur.states |= BatteryHistoryRecord.STATE_WIFI_MULTICAST_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
+ }
+ mWifiMulticastNesting++;
getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
}
public void noteWifiMulticastDisabledLocked(int uid) {
+ mWifiMulticastNesting--;
+ if (mWifiMulticastNesting == 0) {
+ mHistoryCur.states &= ~BatteryHistoryRecord.STATE_WIFI_MULTICAST_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(SystemClock.elapsedRealtime());
+ }
getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
}
@@ -2766,6 +2947,11 @@
}
@Override
+ public BatteryHistoryRecord getHistory() {
+ return mHistory;
+ }
+
+ @Override
public int getStartCount() {
return mStartCount;
}
@@ -2784,6 +2970,12 @@
long mSecRealtime = SystemClock.elapsedRealtime();
long realtime = mSecRealtime * 1000;
if (onBattery) {
+ clearHistory();
+ mHistoryCur.batteryLevel = (byte)level;
+ mHistoryCur.states &= ~BatteryHistoryRecord.STATE_BATTERY_PLUGGED_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(mSecRealtime);
mTrackBatteryUptimeStart = uptime;
mTrackBatteryRealtimeStart = realtime;
mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
@@ -2791,6 +2983,11 @@
mDischargeCurrentLevel = mDischargeStartLevel = level;
doUnplug(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
} else {
+ mHistoryCur.batteryLevel = (byte)level;
+ mHistoryCur.states |= BatteryHistoryRecord.STATE_BATTERY_PLUGGED_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecord(mSecRealtime);
mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
mDischargeCurrentLevel = level;
@@ -2806,7 +3003,11 @@
}
public void recordCurrentLevel(int level) {
- mDischargeCurrentLevel = level;
+ if (mDischargeCurrentLevel != level) {
+ mDischargeCurrentLevel = level;
+ mHistoryCur.batteryLevel = (byte)level;
+ addHistoryRecord(SystemClock.elapsedRealtime());
+ }
}
public void updateKernelWakelocksLocked() {
@@ -3146,6 +3347,24 @@
return 0;
}
+ void readHistory(Parcel in) {
+ mHistory = mHistoryEnd = mHistoryCache = null;
+ long time;
+ while ((time=in.readLong()) >= 0) {
+ BatteryHistoryRecord rec = new BatteryHistoryRecord(time, in);
+ addHistoryRecord(rec);
+ }
+ }
+
+ void writeHistory(Parcel out) {
+ BatteryHistoryRecord rec = mHistory;
+ while (rec != null) {
+ if (rec.time >= 0) rec.writeToParcel(out, 0);
+ rec = rec.next;
+ }
+ out.writeLong(-1);
+ }
+
private void readSummaryFromParcel(Parcel in) {
final int version = in.readInt();
if (version != VERSION) {
@@ -3154,6 +3373,8 @@
return;
}
+ readHistory(in);
+
mStartCount = in.readInt();
mBatteryUptime = in.readLong();
mBatteryLastUptime = in.readLong();
@@ -3325,6 +3546,8 @@
out.writeInt(VERSION);
+ writeHistory(out);
+
out.writeInt(mStartCount);
out.writeLong(computeBatteryUptime(NOW_SYS, STATS_TOTAL));
out.writeLong(computeBatteryUptime(NOW_SYS, STATS_CURRENT));
@@ -3493,6 +3716,8 @@
throw new ParcelFormatException("Bad magic number");
}
+ readHistory(in);
+
mStartCount = in.readInt();
mBatteryUptime = in.readLong();
mBatteryLastUptime = in.readLong();
@@ -3591,6 +3816,9 @@
final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
out.writeInt(MAGIC);
+
+ writeHistory(out);
+
out.writeInt(mStartCount);
out.writeLong(mBatteryUptime);
out.writeLong(mBatteryLastUptime);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index cfcac86..0946ba2 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -288,6 +288,17 @@
// system/rootdir/init.rc on startup.
static final int SECONDARY_SERVER_ADJ;
+ // This is a process with a heavy-weight application. It is in the
+ // background, but we want to try to avoid killing it. Value set in
+ // system/rootdir/init.rc on startup.
+ static final int HEAVY_WEIGHT_APP_ADJ;
+
+ // This is a process only hosting components that are perceptible to the
+ // user, and we really want to avoid killing them, but they are not
+ // immediately visible. An example is background music playback. Value set in
+ // system/rootdir/init.rc on startup.
+ static final int PERCEPTIBLE_APP_ADJ;
+
// This is a process only hosting activities that are visible to the
// user, so we'd prefer they don't disappear. Value set in
// system/rootdir/init.rc on startup.
@@ -313,6 +324,8 @@
static final int HOME_APP_MEM;
static final int BACKUP_APP_MEM;
static final int SECONDARY_SERVER_MEM;
+ static final int HEAVY_WEIGHT_APP_MEM;
+ static final int PERCEPTIBLE_APP_MEM;
static final int VISIBLE_APP_MEM;
static final int FOREGROUND_APP_MEM;
@@ -333,37 +346,40 @@
// been idle for less than 120 seconds.
static final long EMPTY_APP_IDLE_OFFSET = 120*1000;
+ static int getIntProp(String name, boolean allowZero) {
+ String str = SystemProperties.get(name);
+ if (str == null) {
+ throw new IllegalArgumentException("Property not defined: " + name);
+ }
+ int val = Integer.valueOf(str);
+ if (val == 0 && !allowZero) {
+ throw new IllegalArgumentException("Property must not be zero: " + name);
+ }
+ return val;
+ }
+
static {
// These values are set in system/rootdir/init.rc on startup.
- FOREGROUND_APP_ADJ =
- Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
- VISIBLE_APP_ADJ =
- Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
- SECONDARY_SERVER_ADJ =
- Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
- BACKUP_APP_ADJ =
- Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
- HOME_APP_ADJ =
- Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
- HIDDEN_APP_MIN_ADJ =
- Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
- EMPTY_APP_ADJ =
- Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
- HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ-1;
- FOREGROUND_APP_MEM =
- Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
- VISIBLE_APP_MEM =
- Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
- SECONDARY_SERVER_MEM =
- Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
- BACKUP_APP_MEM =
- Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
- HOME_APP_MEM =
- Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
- HIDDEN_APP_MEM =
- Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
- EMPTY_APP_MEM =
- Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
+ FOREGROUND_APP_ADJ = getIntProp("ro.FOREGROUND_APP_ADJ", true);
+ VISIBLE_APP_ADJ = getIntProp("ro.VISIBLE_APP_ADJ", true);
+ PERCEPTIBLE_APP_ADJ = getIntProp("ro.PERCEPTIBLE_APP_ADJ", true);
+ HEAVY_WEIGHT_APP_ADJ = getIntProp("ro.HEAVY_WEIGHT_APP_ADJ", true);
+ SECONDARY_SERVER_ADJ = getIntProp("ro.SECONDARY_SERVER_ADJ", true);
+ BACKUP_APP_ADJ = getIntProp("ro.BACKUP_APP_ADJ", true);
+ HOME_APP_ADJ = getIntProp("ro.HOME_APP_ADJ", true);
+ HIDDEN_APP_MIN_ADJ = getIntProp("ro.HIDDEN_APP_MIN_ADJ", true);
+ EMPTY_APP_ADJ = getIntProp("ro.EMPTY_APP_ADJ", true);
+ // These days we use the last empty slot for hidden apps as well.
+ HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ;
+ FOREGROUND_APP_MEM = getIntProp("ro.FOREGROUND_APP_MEM", false)*PAGE_SIZE;
+ VISIBLE_APP_MEM = getIntProp("ro.VISIBLE_APP_MEM", false)*PAGE_SIZE;
+ PERCEPTIBLE_APP_MEM = getIntProp("ro.PERCEPTIBLE_APP_MEM", false)*PAGE_SIZE;
+ HEAVY_WEIGHT_APP_MEM = getIntProp("ro.HEAVY_WEIGHT_APP_MEM", false)*PAGE_SIZE;
+ SECONDARY_SERVER_MEM = getIntProp("ro.SECONDARY_SERVER_MEM", false)*PAGE_SIZE;
+ BACKUP_APP_MEM = getIntProp("ro.BACKUP_APP_MEM", false)*PAGE_SIZE;
+ HOME_APP_MEM = getIntProp("ro.HOME_APP_MEM", false)*PAGE_SIZE;
+ HIDDEN_APP_MEM = getIntProp("ro.HIDDEN_APP_MEM", false)*PAGE_SIZE;
+ EMPTY_APP_MEM = getIntProp("ro.EMPTY_APP_MEM", false)*PAGE_SIZE;
}
static final int MY_PID = Process.myPid();
@@ -4974,8 +4990,8 @@
(rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
// The low memory report is overriding any current
// state for a GC request. Make sure to do
- // visible/foreground processes first.
- if (rec.setAdj <= VISIBLE_APP_ADJ) {
+ // heavy/important/visible/foreground processes first.
+ if (rec.setAdj <= HEAVY_WEIGHT_APP_ADJ) {
rec.lastRequestedGc = 0;
} else {
rec.lastRequestedGc = rec.lastLowMemory;
@@ -8102,8 +8118,8 @@
r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
}
cpr.clients.add(r);
- if (cpr.app != null && r.setAdj >= VISIBLE_APP_ADJ) {
- // If this is a visible app accessing the provider,
+ if (cpr.app != null && r.setAdj <= PERCEPTIBLE_APP_ADJ) {
+ // If this is a perceptible app accessing the provider,
// make sure to count it as being accessed and thus
// back up on the LRU list. This is good because
// content providers are often expensive to start.
@@ -9741,10 +9757,12 @@
currApp.lru = 0;
} else if (adj >= SECONDARY_SERVER_ADJ) {
currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
+ } else if (adj >= HEAVY_WEIGHT_APP_ADJ) {
+ currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_HEAVY_WEIGHT;
+ } else if (adj >= PERCEPTIBLE_APP_ADJ) {
+ currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE;
} else if (adj >= VISIBLE_APP_ADJ) {
currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
- } else if (app == mHeavyWeightProcess) {
- currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_HEAVY_WEIGHT;
} else {
currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
}
@@ -10006,7 +10024,7 @@
needSep = true;
pw.println(" Running processes (most recent first):");
dumpProcessList(pw, this, mLruProcesses, " ",
- "App ", "PERS", true);
+ "Proc", "PERS", true);
needSep = true;
}
@@ -10502,7 +10520,8 @@
String prefix, String normalLabel, String persistentLabel,
boolean inclOomAdj) {
int numPers = 0;
- for (int i=list.size()-1; i>=0; i--) {
+ final int N = list.size()-1;
+ for (int i=N; i>=0; i--) {
ProcessRecord r = (ProcessRecord)list.get(i);
if (false) {
pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
@@ -10520,6 +10539,10 @@
oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
} else if (r.setAdj >= BACKUP_APP_ADJ) {
oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
+ } else if (r.setAdj >= HEAVY_WEIGHT_APP_ADJ) {
+ oomAdj = buildOomTag("hvy ", null, r.setAdj, HEAVY_WEIGHT_APP_ADJ);
+ } else if (r.setAdj >= PERCEPTIBLE_APP_ADJ) {
+ oomAdj = buildOomTag("prcp ", null, r.setAdj, PERCEPTIBLE_APP_ADJ);
} else if (r.setAdj >= VISIBLE_APP_ADJ) {
oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
} else if (r.setAdj >= FOREGROUND_APP_ADJ) {
@@ -10545,10 +10568,27 @@
}
pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
prefix, (r.persistent ? persistentLabel : normalLabel),
- i, oomAdj, schedGroup, r.toShortString(), r.adjType));
+ N-i, oomAdj, schedGroup, r.toShortString(), r.adjType));
if (r.adjSource != null || r.adjTarget != null) {
- pw.println(prefix + " " + r.adjTarget
- + "<=" + r.adjSource);
+ pw.print(prefix);
+ pw.print(" ");
+ if (r.adjTarget instanceof ComponentName) {
+ pw.print(((ComponentName)r.adjTarget).flattenToShortString());
+ } else if (r.adjTarget != null) {
+ pw.print(r.adjTarget.toString());
+ } else {
+ pw.print("{null}");
+ }
+ pw.print("<=");
+ if (r.adjSource instanceof ProcessRecord) {
+ pw.print("Proc{");
+ pw.print(((ProcessRecord)r.adjSource).toShortString());
+ pw.println("}");
+ } else if (r.adjSource != null) {
+ pw.println(r.adjSource.toString());
+ } else {
+ pw.println("{null}");
+ }
}
} else {
pw.println(String.format("%s%s #%2d: %s",
@@ -14092,11 +14132,6 @@
adj = FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "instrumentation";
- } else if (app == mHeavyWeightProcess) {
- // We don't want to kill the current heavy-weight process.
- adj = FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- app.adjType = "heavy";
} else if (app.persistentActivities > 0) {
// Special persistent activities... shouldn't be used these days.
adj = FOREGROUND_APP_ADJ;
@@ -14117,15 +14152,20 @@
app.adjType = "exec-service";
} else if (app.foregroundServices) {
// The user is aware of this app, so make it visible.
- adj = VISIBLE_APP_ADJ;
+ adj = PERCEPTIBLE_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "foreground-service";
} else if (app.forcingToForeground != null) {
// The user is aware of this app, so make it visible.
- adj = VISIBLE_APP_ADJ;
+ adj = PERCEPTIBLE_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "force-foreground";
app.adjSource = app.forcingToForeground;
+ } else if (app == mHeavyWeightProcess) {
+ // We don't want to kill the current heavy-weight process.
+ adj = HEAVY_WEIGHT_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ app.adjType = "heavy";
} else if (app == mHomeProcess) {
// This process is hosting what we currently consider to be the
// home app, so we don't want to let it go into the background.
@@ -14220,7 +14260,7 @@
ProcessRecord client = cr.binding.client;
int myHiddenAdj = hiddenAdj;
if (myHiddenAdj > client.hiddenAdj) {
- if (client.hiddenAdj > VISIBLE_APP_ADJ) {
+ if (client.hiddenAdj >= VISIBLE_APP_ADJ) {
myHiddenAdj = client.hiddenAdj;
} else {
myHiddenAdj = VISIBLE_APP_ADJ;
@@ -14229,7 +14269,7 @@
int clientAdj = computeOomAdjLocked(
client, myHiddenAdj, TOP_APP, true);
if (adj > clientAdj) {
- adj = clientAdj > VISIBLE_APP_ADJ
+ adj = clientAdj >= VISIBLE_APP_ADJ
? clientAdj : VISIBLE_APP_ADJ;
if (!client.hidden) {
app.hidden = false;
@@ -14340,7 +14380,7 @@
// " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
if (adj > app.maxAdj) {
adj = app.maxAdj;
- if (app.maxAdj <= VISIBLE_APP_ADJ) {
+ if (app.maxAdj <= PERCEPTIBLE_APP_ADJ) {
schedGroup = Process.THREAD_GROUP_DEFAULT;
}
}
@@ -14392,7 +14432,7 @@
if (canGcNowLocked()) {
while (mProcessesToGc.size() > 0) {
ProcessRecord proc = mProcessesToGc.remove(0);
- if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
+ if (proc.curRawAdj > PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) {
if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
<= SystemClock.uptimeMillis()) {
// To avoid spamming the system, we will GC processes one
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 33bbc13..ba13c51 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -96,6 +96,7 @@
public void noteStartWakelock(int uid, String name, int type) {
enforceCallingPermission();
synchronized (mStats) {
+ Slog.i("battery", "Start wake lock: " + uid + " " + name);
mStats.getUidStatsLocked(uid).noteStartWakeLocked(name, type);
}
}
@@ -103,6 +104,7 @@
public void noteStopWakelock(int uid, String name, int type) {
enforceCallingPermission();
synchronized (mStats) {
+ Slog.i("battery", "Stop wake lock: " + uid + " " + name);
mStats.getUidStatsLocked(uid).noteStopWakeLocked(name, type);
}
}