Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 57c0df88 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

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
parent 5123bbc2
Loading
Loading
Loading
Loading
+76 −0
Original line number Diff line number Diff line
@@ -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) {
+34 −5
Original line number Diff line number Diff line
@@ -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();

+0 −3
Original line number Diff line number Diff line
@@ -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;

+14 −0
Original line number Diff line number Diff line
@@ -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.
     *