diff options
3 files changed, 72 insertions, 1 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index c3720965e7f6..30162288d92c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -246,6 +246,18 @@ final class ActivityManagerConstants extends ContentObserver { private static final String KEY_MAX_PHANTOM_PROCESSES = "max_phantom_processes"; /** + * Enables proactive killing of cached apps + */ + private static final String KEY_PROACTIVE_KILLS_ENABLED = "proactive_kills_enabled"; + + /** + * Trim LRU cached app when swap falls below this minimum percentage. + * + * Depends on KEY_PROACTIVE_KILLS_ENABLED + */ + private static final String KEY_LOW_SWAP_THRESHOLD_PERCENT = "low_swap_threshold_percent"; + + /** * Default value for mFlagBackgroundActivityStartsEnabled if not explicitly set in * Settings.Global. This allows it to be set experimentally unless it has been * enabled/disabled in developer options. Defaults to false. @@ -833,6 +845,10 @@ final class ActivityManagerConstants extends ContentObserver { */ private static final long DEFAULT_MIN_ASSOC_LOG_DURATION = 5 * 60 * 1000; // 5 mins + private static final boolean DEFAULT_PROACTIVE_KILLS_ENABLED = false; + + private static final float DEFAULT_LOW_SWAP_THRESHOLD_PERCENT = 0.10f; + private static final String KEY_MIN_ASSOC_LOG_DURATION = "min_assoc_log_duration"; public static long MIN_ASSOC_LOG_DURATION = DEFAULT_MIN_ASSOC_LOG_DURATION; @@ -863,6 +879,8 @@ final class ActivityManagerConstants extends ContentObserver { public static boolean BINDER_HEAVY_HITTER_AUTO_SAMPLER_ENABLED; public static int BINDER_HEAVY_HITTER_AUTO_SAMPLER_BATCHSIZE; public static float BINDER_HEAVY_HITTER_AUTO_SAMPLER_THRESHOLD; + public static boolean PROACTIVE_KILLS_ENABLED = DEFAULT_PROACTIVE_KILLS_ENABLED; + public static float LOW_SWAP_THRESHOLD_PERCENT = DEFAULT_LOW_SWAP_THRESHOLD_PERCENT; private final OnPropertiesChangedListener mOnDeviceConfigChangedListener = new OnPropertiesChangedListener() { @@ -990,6 +1008,12 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_NETWORK_ACCESS_TIMEOUT_MS: updateNetworkAccessTimeoutMs(); break; + case KEY_PROACTIVE_KILLS_ENABLED: + updateProactiveKillsEnabled(); + break; + case KEY_LOW_SWAP_THRESHOLD_PERCENT: + updateLowSwapThresholdPercent(); + break; default: break; } @@ -1592,6 +1616,20 @@ final class ActivityManagerConstants extends ContentObserver { CUR_TRIM_CACHED_PROCESSES = (MAX_CACHED_PROCESSES-rawMaxEmptyProcesses)/3; } + private void updateProactiveKillsEnabled() { + PROACTIVE_KILLS_ENABLED = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_PROACTIVE_KILLS_ENABLED, + DEFAULT_PROACTIVE_KILLS_ENABLED); + } + + private void updateLowSwapThresholdPercent() { + LOW_SWAP_THRESHOLD_PERCENT = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_LOW_SWAP_THRESHOLD_PERCENT, + DEFAULT_LOW_SWAP_THRESHOLD_PERCENT); + } + private void updateMinAssocLogDuration() { MIN_ASSOC_LOG_DURATION = DeviceConfig.getLong( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_MIN_ASSOC_LOG_DURATION, @@ -1779,6 +1817,10 @@ final class ActivityManagerConstants extends ContentObserver { pw.print("="); pw.println(mServiceBindAlmostPerceptibleTimeoutMs); pw.print(" "); pw.print(KEY_NETWORK_ACCESS_TIMEOUT_MS); pw.print("="); pw.println(mNetworkAccessTimeoutMs); + pw.print(" "); pw.print(KEY_PROACTIVE_KILLS_ENABLED); + pw.print("="); pw.println(PROACTIVE_KILLS_ENABLED); + pw.print(" "); pw.print(KEY_LOW_SWAP_THRESHOLD_PERCENT); + pw.print("="); pw.println(LOW_SWAP_THRESHOLD_PERCENT); pw.println(); if (mOverrideMaxCachedProcesses >= 0) { diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 992195611d0c..cee9f79285a7 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -651,7 +651,7 @@ public final class CachedAppOptimizer { /** * Retrieves the free swap percentage. */ - static private native double getFreeSwapPercent(); + static native double getFreeSwapPercent(); /** * Reads the flag value from DeviceConfig to determine whether app compaction diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index bc939d6279cd..441506d1c327 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1034,6 +1034,12 @@ public class OomAdjuster { private long mNextNoKillDebugMessageTime; + private double mLastFreeSwapPercent = 1.00; + + private static double getFreeSwapPercent() { + return CachedAppOptimizer.getFreeSwapPercent(); + } + @GuardedBy({"mService", "mProcLock"}) private boolean updateAndTrimProcessLSP(final long now, final long nowElapsed, final long oldTime, final ActiveUids activeUids, String oomAdjReason) { @@ -1058,6 +1064,11 @@ public class OomAdjuster { int numEmpty = 0; int numTrimming = 0; + boolean proactiveKillsEnabled = mConstants.PROACTIVE_KILLS_ENABLED; + double lowSwapThresholdPercent = mConstants.LOW_SWAP_THRESHOLD_PERCENT; + double freeSwapPercent = proactiveKillsEnabled ? getFreeSwapPercent() : 1.00; + ProcessRecord lruCachedApp = null; + for (int i = numLru - 1; i >= 0; i--) { ProcessRecord app = lruList.get(i); final ProcessStateRecord state = app.mState; @@ -1095,6 +1106,8 @@ public class OomAdjuster { ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_TOO_MANY_CACHED, true); + } else if (proactiveKillsEnabled) { + lruCachedApp = app; } break; case PROCESS_STATE_CACHED_EMPTY: @@ -1114,6 +1127,8 @@ public class OomAdjuster { ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_TOO_MANY_EMPTY, true); + } else if (proactiveKillsEnabled) { + lruCachedApp = app; } } break; @@ -1145,6 +1160,20 @@ public class OomAdjuster { } } + if (proactiveKillsEnabled // Proactive kills enabled? + && doKillExcessiveProcesses // Should kill excessive processes? + && freeSwapPercent < lowSwapThresholdPercent // Swap below threshold? + && lruCachedApp != null // If no cached app, let LMKD decide + // If swap is non-decreasing, give reclaim a chance to catch up + && freeSwapPercent < mLastFreeSwapPercent) { + lruCachedApp.killLocked("swap low and too many cached", + ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_TOO_MANY_CACHED, + true); + } + + mLastFreeSwapPercent = freeSwapPercent; + return mService.mAppProfiler.updateLowMemStateLSP(numCached, numEmpty, numTrimming); } |