Merge "Apply correct memory trim levels for processes in LRU list"
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 50c992c..112814c69 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -340,6 +340,7 @@
import com.android.server.ThreadPriorityBooster;
import com.android.server.UserspaceRebootLogger;
import com.android.server.Watchdog;
+import com.android.server.am.LowMemDetector.MemFactor;
import com.android.server.appop.AppOpsService;
import com.android.server.compat.PlatformCompat;
import com.android.server.contentcapture.ContentCaptureManagerInternal;
@@ -8224,13 +8225,25 @@
}
@Override
- public int getMemoryTrimLevel() {
+ public @MemFactor int getMemoryTrimLevel() {
enforceNotIsolatedCaller("getMyMemoryState");
synchronized (this) {
return mAppProfiler.getLastMemoryLevelLocked();
}
}
+ void setMemFactorOverride(@MemFactor int level) {
+ synchronized (this) {
+ if (level == mAppProfiler.getLastMemoryLevelLocked()) {
+ return;
+ }
+
+ mAppProfiler.setMemFactorOverrideLocked(level);
+ // Kick off an oom adj update since we forced a mem factor update.
+ updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+ }
+ }
+
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 31e7106..e3c071f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -25,6 +25,12 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.INVALID_DISPLAY;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+import static com.android.server.am.LowMemDetector.ADJ_MEM_FACTOR_NOTHING;
+
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
@@ -92,6 +98,7 @@
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.util.HexDump;
import com.android.internal.util.MemInfoReader;
+import com.android.server.am.LowMemDetector.MemFactor;
import com.android.server.compat.PlatformCompat;
import java.io.BufferedReader;
@@ -309,6 +316,8 @@
return runCompat(pw);
case "refresh-settings-cache":
return runRefreshSettingsCache();
+ case "memory-factor":
+ return runMemoryFactor(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -3014,6 +3023,81 @@
return -1;
}
+ private int runSetMemoryFactor(PrintWriter pw) throws RemoteException {
+ final String levelArg = getNextArgRequired();
+ @MemFactor int level = ADJ_MEM_FACTOR_NOTHING;
+ switch (levelArg) {
+ case "NORMAL":
+ level = ADJ_MEM_FACTOR_NORMAL;
+ break;
+ case "MODERATE":
+ level = ADJ_MEM_FACTOR_MODERATE;
+ break;
+ case "LOW":
+ level = ADJ_MEM_FACTOR_LOW;
+ break;
+ case "CRITICAL":
+ level = ADJ_MEM_FACTOR_CRITICAL;
+ break;
+ default:
+ try {
+ level = Integer.parseInt(levelArg);
+ } catch (NumberFormatException e) {
+ }
+ if (level < ADJ_MEM_FACTOR_NORMAL || level > ADJ_MEM_FACTOR_CRITICAL) {
+ getErrPrintWriter().println("Error: Unknown level option: " + levelArg);
+ return -1;
+ }
+ }
+ mInternal.setMemFactorOverride(level);
+ return 0;
+ }
+
+ private int runShowMemoryFactor(PrintWriter pw) throws RemoteException {
+ final @MemFactor int level = mInternal.getMemoryTrimLevel();
+ switch (level) {
+ case ADJ_MEM_FACTOR_NOTHING:
+ pw.println("<UNKNOWN>");
+ break;
+ case ADJ_MEM_FACTOR_NORMAL:
+ pw.println("NORMAL");
+ break;
+ case ADJ_MEM_FACTOR_MODERATE:
+ pw.println("MODERATE");
+ break;
+ case ADJ_MEM_FACTOR_LOW:
+ pw.println("LOW");
+ break;
+ case ADJ_MEM_FACTOR_CRITICAL:
+ pw.println("CRITICAL");
+ break;
+ }
+ pw.flush();
+ return 0;
+ }
+
+ private int runResetMemoryFactor(PrintWriter pw) throws RemoteException {
+ mInternal.setMemFactorOverride(ADJ_MEM_FACTOR_NOTHING);
+ return 0;
+ }
+
+ private int runMemoryFactor(PrintWriter pw) throws RemoteException {
+ mInternal.enforceCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
+ "runMemoryFactor()");
+
+ final String op = getNextArgRequired();
+ switch (op) {
+ case "set":
+ return runSetMemoryFactor(pw);
+ case "show":
+ return runShowMemoryFactor(pw);
+ case "reset":
+ return runResetMemoryFactor(pw);
+ default:
+ getErrPrintWriter().println("Error: unknown command '" + op + "'");
+ return -1;
+ }
+ }
private Resources getResources(PrintWriter pw) throws RemoteException {
// system resources does not contain all the device configuration, construct it manually.
@@ -3334,6 +3418,13 @@
pw.println(" Removes all existing overrides for all changes for ");
pw.println(" <PACKAGE_NAME> (back to default behaviour).");
pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
+ pw.println(" memory-factor [command] [...]: sub-commands for overriding memory pressure factor");
+ pw.println(" set <NORMAL|MODERATE|LOW|CRITICAL>");
+ pw.println(" Overrides memory pressure factor. May also supply a raw int level");
+ pw.println(" show");
+ pw.println(" Shows the existing memory pressure factor");
+ pw.println(" reset");
+ pw.println(" Removes existing override for memory pressure factor");
pw.println();
Intent.printIntentArgsHelp(pw, "");
}
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 31ffb35..5e59a35 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -20,11 +20,16 @@
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.Process.FIRST_APPLICATION_UID;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.LowMemDetector.ADJ_MEM_FACTOR_NOTHING;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import android.annotation.BroadcastBehavior;
@@ -72,6 +77,7 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.MemInfoReader;
+import com.android.server.am.LowMemDetector.MemFactor;
import com.android.server.am.ProcessList.ProcStateMemTracker;
import com.android.server.utils.PriorityDump;
@@ -202,7 +208,10 @@
* processes are going away for other reasons.
*/
@GuardedBy("mService")
- private int mLastMemoryLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+ private @MemFactor int mLastMemoryLevel = ADJ_MEM_FACTOR_NORMAL;
+
+ @GuardedBy("mService")
+ private @MemFactor int mMemFactorOverride = ADJ_MEM_FACTOR_NOTHING;
/**
* The last total number of process we have, to determine if changes actually look
@@ -851,7 +860,7 @@
@GuardedBy("mService")
boolean isLastMemoryLevelNormal() {
- return mLastMemoryLevel <= ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+ return mLastMemoryLevel <= ADJ_MEM_FACTOR_NORMAL;
}
@GuardedBy("mService")
@@ -868,6 +877,11 @@
}
@GuardedBy("mService")
+ void setMemFactorOverrideLocked(@MemFactor int factor) {
+ mMemFactorOverride = factor;
+ }
+
+ @GuardedBy("mService")
boolean updateLowMemStateLocked(int numCached, int numEmpty, int numTrimming) {
final int numOfLru = mService.mProcessList.getLruSizeLocked();
final long now = SystemClock.uptimeMillis();
@@ -885,28 +899,32 @@
&& numEmpty <= mService.mConstants.CUR_TRIM_EMPTY_PROCESSES) {
final int numCachedAndEmpty = numCached + numEmpty;
if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
- memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
+ memFactor = ADJ_MEM_FACTOR_CRITICAL;
} else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
- memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;
+ memFactor = ADJ_MEM_FACTOR_LOW;
} else {
- memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
+ memFactor = ADJ_MEM_FACTOR_MODERATE;
}
} else {
- memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+ memFactor = ADJ_MEM_FACTOR_NORMAL;
}
}
// We always allow the memory level to go up (better). We only allow it to go
// down if we are in a state where that is allowed, *and* the total number of processes
// has gone down since last time.
if (DEBUG_OOM_ADJ) {
- Slog.d(TAG_OOM_ADJ, "oom: memFactor=" + memFactor
+ Slog.d(TAG_OOM_ADJ, "oom: memFactor=" + memFactor + " override=" + mMemFactorOverride
+ " last=" + mLastMemoryLevel + " allowLow=" + mAllowLowerMemLevel
+ " numProcs=" + mService.mProcessList.getLruSizeLocked()
+ " last=" + mLastNumProcesses);
}
+ boolean override;
+ if (override = (mMemFactorOverride != ADJ_MEM_FACTOR_NOTHING)) {
+ memFactor = mMemFactorOverride;
+ }
if (memFactor > mLastMemoryLevel) {
- if (!mAllowLowerMemLevel
- || mService.mProcessList.getLruSizeLocked() >= mLastNumProcesses) {
+ if (!override && (!mAllowLowerMemLevel
+ || mService.mProcessList.getLruSizeLocked() >= mLastNumProcesses)) {
memFactor = mLastMemoryLevel;
if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "Keeping last mem factor!");
}
@@ -924,17 +942,17 @@
mService.mAtmInternal == null || !mService.mAtmInternal.isSleeping(), now);
trackerMemFactor = mService.mProcessStats.getMemFactorLocked();
}
- if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
+ if (memFactor != ADJ_MEM_FACTOR_NORMAL) {
if (mLowRamStartTime == 0) {
mLowRamStartTime = now;
}
int step = 0;
int fgTrimLevel;
switch (memFactor) {
- case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+ case ADJ_MEM_FACTOR_CRITICAL:
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
break;
- case ProcessStats.ADJ_MEM_FACTOR_LOW:
+ case ADJ_MEM_FACTOR_LOW:
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
break;
default:
@@ -947,7 +965,7 @@
if (mService.mAtmInternal.getPreviousProcess() != null) minFactor++;
if (factor < minFactor) factor = minFactor;
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
- for (int i = numOfLru - 1; i >= 0; i--) {
+ for (int i = 0; i < numOfLru; i++) {
ProcessRecord app = mService.mProcessList.mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
mService.setProcessTrackerStateLocked(app, trackerMemFactor, now);
@@ -1032,7 +1050,7 @@
mLowRamTimeSinceLastIdle += now - mLowRamStartTime;
mLowRamStartTime = 0;
}
- for (int i = numOfLru - 1; i >= 0; i--) {
+ for (int i = 0; i < numOfLru; i++) {
ProcessRecord app = mService.mProcessList.mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
mService.setProcessTrackerStateLocked(app, trackerMemFactor, now);
@@ -1622,16 +1640,16 @@
@GuardedBy("mService")
void dumpLastMemoryLevelLocked(PrintWriter pw) {
switch (mLastMemoryLevel) {
- case ProcessStats.ADJ_MEM_FACTOR_NORMAL:
+ case ADJ_MEM_FACTOR_NORMAL:
pw.println("normal)");
break;
- case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
+ case ADJ_MEM_FACTOR_MODERATE:
pw.println("moderate)");
break;
- case ProcessStats.ADJ_MEM_FACTOR_LOW:
+ case ADJ_MEM_FACTOR_LOW:
pw.println("low)");
break;
- case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+ case ADJ_MEM_FACTOR_CRITICAL:
pw.println("critical)");
break;
default:
diff --git a/services/core/java/com/android/server/am/LowMemDetector.java b/services/core/java/com/android/server/am/LowMemDetector.java
index e82a207..8f79133 100644
--- a/services/core/java/com/android/server/am/LowMemDetector.java
+++ b/services/core/java/com/android/server/am/LowMemDetector.java
@@ -16,8 +16,19 @@
package com.android.server.am;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_NOTHING;
+
+import android.annotation.IntDef;
+
import com.android.internal.annotations.GuardedBy;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Detects low memory using PSI.
*
@@ -32,13 +43,20 @@
private final Object mPressureStateLock = new Object();
@GuardedBy("mPressureStateLock")
- private int mPressureState = MEM_PRESSURE_NONE;
+ private int mPressureState = ADJ_MEM_FACTOR_NORMAL;
+
+ public static final int ADJ_MEM_FACTOR_NOTHING = ADJ_NOTHING;
/* getPressureState return values */
- public static final int MEM_PRESSURE_NONE = 0;
- public static final int MEM_PRESSURE_LOW = 1;
- public static final int MEM_PRESSURE_MEDIUM = 2;
- public static final int MEM_PRESSURE_HIGH = 3;
+ @IntDef(prefix = { "ADJ_MEM_FACTOR_" }, value = {
+ ADJ_MEM_FACTOR_NOTHING,
+ ADJ_MEM_FACTOR_NORMAL,
+ ADJ_MEM_FACTOR_MODERATE,
+ ADJ_MEM_FACTOR_LOW,
+ ADJ_MEM_FACTOR_CRITICAL,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MemFactor{}
LowMemDetector(ActivityManagerService am) {
mAm = am;
@@ -62,7 +80,7 @@
* there should be conversion performed here to translate pressure state
* into memFactor.
*/
- public int getMemFactor() {
+ public @MemFactor int getMemFactor() {
synchronized (mPressureStateLock) {
return mPressureState;
}