Do not proactively kill cached/empty processes post boot
Added three configs: Do not proactively kill cached processes until user-0 is being unlocked: (default: false) $ device_config put activity_manager no_kill_cached_processes_until_boot_completed true Do not proactively kill cached processes for 10 minutes after any user is being unlocked: (default: 0) $ device_config put activity_manager no_kill_cached_processes_post_boot_completed_duration_millis 60000 Also added the following config to control MAX_EMPTY_TIME: (default: 30 minutes) $ device_config put activity_manager max_empty_time_millis 1800000 Bug: 222365734 Test: Manual test Change-Id: I48c0d6dd5f1836159be458ff00e58a59d9987dcf
This commit is contained in:
@@ -650,6 +650,38 @@ final class ActivityManagerConstants extends ContentObserver {
|
||||
// initialized in the constructor.
|
||||
public int CUR_MAX_EMPTY_PROCESSES;
|
||||
|
||||
|
||||
/** @see #mNoKillCachedProcessesUntilBootCompleted */
|
||||
private static final String KEY_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED =
|
||||
"no_kill_cached_processes_until_boot_completed";
|
||||
|
||||
/** @see #mNoKillCachedProcessesPostBootCompletedDurationMillis */
|
||||
private static final String KEY_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS =
|
||||
"no_kill_cached_processes_post_boot_completed_duration_millis";
|
||||
|
||||
/** @see #mNoKillCachedProcessesUntilBootCompleted */
|
||||
private static final boolean DEFAULT_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED = false;
|
||||
|
||||
/** @see #mNoKillCachedProcessesPostBootCompletedDurationMillis */
|
||||
private static final long
|
||||
DEFAULT_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS = 0;
|
||||
|
||||
/**
|
||||
* If true, do not kill excessive cached processes proactively, until user-0 is unlocked.
|
||||
* @see #mNoKillCachedProcessesPostBootCompletedDurationMillis
|
||||
*/
|
||||
volatile boolean mNoKillCachedProcessesUntilBootCompleted =
|
||||
DEFAULT_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED;
|
||||
|
||||
/**
|
||||
* Do not kill excessive cached processes proactively, for this duration after each user is
|
||||
* unlocked.
|
||||
* Note we don't proactively kill extra cached processes after this. The next oomadjuster pass
|
||||
* will naturally do it.
|
||||
*/
|
||||
volatile long mNoKillCachedProcessesPostBootCompletedDurationMillis =
|
||||
DEFAULT_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS;
|
||||
|
||||
// The number of empty apps at which we don't consider it necessary to do
|
||||
// memory trimming.
|
||||
public int CUR_TRIM_EMPTY_PROCESSES = computeEmptyProcessLimit(MAX_CACHED_PROCESSES) / 2;
|
||||
@@ -659,6 +691,14 @@ final class ActivityManagerConstants extends ContentObserver {
|
||||
public int CUR_TRIM_CACHED_PROCESSES =
|
||||
(MAX_CACHED_PROCESSES - computeEmptyProcessLimit(MAX_CACHED_PROCESSES)) / 3;
|
||||
|
||||
/** @see #mNoKillCachedProcessesUntilBootCompleted */
|
||||
private static final String KEY_MAX_EMPTY_TIME_MILLIS =
|
||||
"max_empty_time_millis";
|
||||
|
||||
private static final long DEFAULT_MAX_EMPTY_TIME_MILLIS = 30 * 60 * 1000;
|
||||
|
||||
volatile long mMaxEmptyTimeMillis = DEFAULT_MAX_EMPTY_TIME_MILLIS;
|
||||
|
||||
/**
|
||||
* Packages that can't be killed even if it's requested to be killed on imperceptible.
|
||||
*/
|
||||
@@ -869,6 +909,15 @@ final class ActivityManagerConstants extends ContentObserver {
|
||||
case KEY_DEFER_BOOT_COMPLETED_BROADCAST:
|
||||
updateDeferBootCompletedBroadcast();
|
||||
break;
|
||||
case KEY_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED:
|
||||
updateNoKillCachedProcessesUntilBootCompleted();
|
||||
break;
|
||||
case KEY_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS:
|
||||
updateNoKillCachedProcessesPostBootCompletedDurationMillis();
|
||||
break;
|
||||
case KEY_MAX_EMPTY_TIME_MILLIS:
|
||||
updateMaxEmptyTimeMillis();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1288,6 +1337,27 @@ final class ActivityManagerConstants extends ContentObserver {
|
||||
DEFAULT_DEFER_BOOT_COMPLETED_BROADCAST);
|
||||
}
|
||||
|
||||
private void updateNoKillCachedProcessesUntilBootCompleted() {
|
||||
mNoKillCachedProcessesUntilBootCompleted = DeviceConfig.getBoolean(
|
||||
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||
KEY_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED,
|
||||
DEFAULT_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED);
|
||||
}
|
||||
|
||||
private void updateNoKillCachedProcessesPostBootCompletedDurationMillis() {
|
||||
mNoKillCachedProcessesPostBootCompletedDurationMillis = DeviceConfig.getLong(
|
||||
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||
KEY_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS,
|
||||
DEFAULT_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS);
|
||||
}
|
||||
|
||||
private void updateMaxEmptyTimeMillis() {
|
||||
mMaxEmptyTimeMillis = DeviceConfig.getLong(
|
||||
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||
KEY_MAX_EMPTY_TIME_MILLIS,
|
||||
DEFAULT_MAX_EMPTY_TIME_MILLIS);
|
||||
}
|
||||
|
||||
private long[] parseLongArray(@NonNull String key, @NonNull long[] def) {
|
||||
final String val = DeviceConfig.getString(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||
key, null);
|
||||
@@ -1562,6 +1632,12 @@ final class ActivityManagerConstants extends ContentObserver {
|
||||
pw.print("="); pw.println(mComponentAliasOverrides);
|
||||
pw.print(" "); pw.print(KEY_DEFER_BOOT_COMPLETED_BROADCAST);
|
||||
pw.print("="); pw.println(mDeferBootCompletedBroadcast);
|
||||
pw.print(" "); pw.print(KEY_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED);
|
||||
pw.print("="); pw.println(mNoKillCachedProcessesUntilBootCompleted);
|
||||
pw.print(" "); pw.print(KEY_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS);
|
||||
pw.print("="); pw.println(mNoKillCachedProcessesPostBootCompletedDurationMillis);
|
||||
pw.print(" "); pw.print(KEY_MAX_EMPTY_TIME_MILLIS);
|
||||
pw.print("="); pw.println(mMaxEmptyTimeMillis);
|
||||
|
||||
pw.println();
|
||||
if (mOverrideMaxCachedProcesses >= 0) {
|
||||
|
||||
@@ -750,7 +750,7 @@ public class OomAdjuster {
|
||||
}
|
||||
final long now = SystemClock.uptimeMillis();
|
||||
final long nowElapsed = SystemClock.elapsedRealtime();
|
||||
final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
|
||||
final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
|
||||
final boolean fullUpdate = processes == null;
|
||||
ActiveUids activeUids = uids;
|
||||
ArrayList<ProcessRecord> activeProcesses = fullUpdate ? mProcessList.getLruProcessesLOSP()
|
||||
@@ -1031,15 +1031,25 @@ public class OomAdjuster {
|
||||
}
|
||||
}
|
||||
|
||||
private long mNextNoKillDebugMessageTime;
|
||||
|
||||
@GuardedBy({"mService", "mProcLock"})
|
||||
private boolean updateAndTrimProcessLSP(final long now, final long nowElapsed,
|
||||
final long oldTime, final ActiveUids activeUids) {
|
||||
ArrayList<ProcessRecord> lruList = mProcessList.getLruProcessesLOSP();
|
||||
final int numLru = lruList.size();
|
||||
|
||||
final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;
|
||||
final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES
|
||||
- emptyProcessLimit;
|
||||
final boolean doKillExcessiveProcesses = shouldKillExcessiveProcesses(now);
|
||||
if (!doKillExcessiveProcesses) {
|
||||
if (mNextNoKillDebugMessageTime < now) {
|
||||
Slog.d(TAG, "Not killing cached processes"); // STOPSHIP Remove it b/222365734
|
||||
mNextNoKillDebugMessageTime = now + 5000; // Every 5 seconds
|
||||
}
|
||||
}
|
||||
final int emptyProcessLimit = doKillExcessiveProcesses
|
||||
? mConstants.CUR_MAX_EMPTY_PROCESSES : Integer.MAX_VALUE;
|
||||
final int cachedProcessLimit = doKillExcessiveProcesses
|
||||
? (mConstants.CUR_MAX_CACHED_PROCESSES - emptyProcessLimit) : Integer.MAX_VALUE;
|
||||
int lastCachedGroup = 0;
|
||||
int lastCachedGroupUid = 0;
|
||||
int numCached = 0;
|
||||
@@ -1089,7 +1099,7 @@ public class OomAdjuster {
|
||||
case PROCESS_STATE_CACHED_EMPTY:
|
||||
if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES
|
||||
&& app.getLastActivityTime() < oldTime) {
|
||||
app.killLocked("empty for " + ((oldTime + ProcessList.MAX_EMPTY_TIME
|
||||
app.killLocked("empty for " + ((now
|
||||
- app.getLastActivityTime()) / 1000) + "s",
|
||||
"empty for too long",
|
||||
ApplicationExitInfo.REASON_OTHER,
|
||||
@@ -1258,6 +1268,25 @@ public class OomAdjuster {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we should kill excessive cached/empty processes.
|
||||
*/
|
||||
private boolean shouldKillExcessiveProcesses(long nowUptime) {
|
||||
final long lastUserUnlockingUptime = mService.mUserController.getLastUserUnlockingUptime();
|
||||
|
||||
if (lastUserUnlockingUptime == 0) {
|
||||
// No users have been unlocked.
|
||||
return !mConstants.mNoKillCachedProcessesUntilBootCompleted;
|
||||
}
|
||||
final long noKillCachedProcessesPostBootCompletedDurationMillis =
|
||||
mConstants.mNoKillCachedProcessesPostBootCompletedDurationMillis;
|
||||
if ((lastUserUnlockingUptime + noKillCachedProcessesPostBootCompletedDurationMillis)
|
||||
> nowUptime) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback =
|
||||
new ComputeOomAdjWindowCallback();
|
||||
|
||||
|
||||
@@ -293,9 +293,6 @@ public final class ProcessList {
|
||||
// without empty apps being able to push them out of memory.
|
||||
static final int MIN_CACHED_APPS = 2;
|
||||
|
||||
// We allow empty processes to stick around for at most 30 minutes.
|
||||
static final long MAX_EMPTY_TIME = 30 * 60 * 1000;
|
||||
|
||||
// Threshold of number of cached+empty where we consider memory critical.
|
||||
static final int TRIM_CRITICAL_THRESHOLD = 3;
|
||||
|
||||
|
||||
@@ -399,6 +399,9 @@ class UserController implements Handler.Callback {
|
||||
@GuardedBy("mLock")
|
||||
private @StopUserOnSwitch int mStopUserOnSwitch = STOP_USER_ON_SWITCH_DEFAULT;
|
||||
|
||||
/** @see #getLastUserUnlockingUptime */
|
||||
private volatile long mLastUserUnlockingUptime = 0;
|
||||
|
||||
UserController(ActivityManagerService service) {
|
||||
this(new Injector(service));
|
||||
}
|
||||
@@ -661,6 +664,8 @@ class UserController implements Handler.Callback {
|
||||
|
||||
uss.mUnlockProgress.setProgress(20);
|
||||
|
||||
mLastUserUnlockingUptime = SystemClock.uptimeMillis();
|
||||
|
||||
// Dispatch unlocked to system services; when fully dispatched,
|
||||
// that calls through to the next "unlocked" phase
|
||||
mHandler.obtainMessage(USER_UNLOCK_MSG, userId, 0, uss).sendToTarget();
|
||||
@@ -2753,6 +2758,7 @@ class UserController implements Handler.Callback {
|
||||
if (mSwitchingToSystemUserMessage != null) {
|
||||
pw.println(" mSwitchingToSystemUserMessage: " + mSwitchingToSystemUserMessage);
|
||||
}
|
||||
pw.println(" mLastUserUnlockingUptime:" + mLastUserUnlockingUptime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3077,6 +3083,14 @@ class UserController implements Handler.Callback {
|
||||
return bOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uptime when any user was being unlocked most recently. 0 if no users have been unlocked
|
||||
* yet. To avoid lock contention (since it's used by OomAdjuster), it's volatile internally.
|
||||
*/
|
||||
public long getLastUserUnlockingUptime() {
|
||||
return mLastUserUnlockingUptime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to store user journey and session id.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user