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

Commit b735830a authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Keep app in high memory adjust if moving from TOP to FGS

If an app was in the TOP state and immediately moved
to a foreground service state, then try harder to keep it
in memory for another 20 seconds before releasing the
memory to bound foreground services. Using an oom_adj value
of 50 which is between "fore" and "vis". So BFGS apps might
get killed ("vis") before this recently FGS'ed app. That
way any app that has a lot of state in memory that it needs
to persist before getting killed has a chance to do so.

Also bind NotificationListeners with a special bind flag
to rank them below FGS (perceptible adj) so that they
can be killed before any other foreground services or
bound services get killed.

Bug: 110969183
Test: Manual for now. Take a bunch of portrait
      pictures and hit home, while being under memory
      pressure with a bunch of notification listeners.
Change-Id: Ie8934c2331afe6450c582b209869aeca7272f58a
Merged-In: Ie8934c2331afe6450c582b209869aeca7272f58a
parent 82b41342
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -325,6 +325,15 @@ public abstract class Context {
     */
    public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0080;

    /**
     * Flag for {@link #bindService}: If binding from something better than perceptible,
     * still set the adjust below perceptible. This would be used for bound services that can
     * afford to be evicted when under extreme memory pressure, but should be restarted as soon
     * as possible.
     * @hide
     */
    public static final int BIND_ADJUST_BELOW_PERCEPTIBLE = 0x0100;

    /**
     * @hide Flag for {@link #bindService}: allows binding to a service provided
     * by an instant app. Note that the caller may not have access to the instant
+10 −1
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ final class ActivityManagerConstants extends ContentObserver {
    static final String KEY_BOUND_SERVICE_CRASH_RESTART_DURATION = "service_crash_restart_duration";
    static final String KEY_BOUND_SERVICE_CRASH_MAX_RETRY = "service_crash_max_retry";
    static final String KEY_PROCESS_START_ASYNC = "process_start_async";
    static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";

    private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
    private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -95,7 +96,7 @@ final class ActivityManagerConstants extends ContentObserver {
    private static final long DEFAULT_BOUND_SERVICE_CRASH_RESTART_DURATION = 30*60_000;
    private static final int DEFAULT_BOUND_SERVICE_CRASH_MAX_RETRY = 16;
    private static final boolean DEFAULT_PROCESS_START_ASYNC = true;

    private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;

    // Maximum number of cached processes we will allow.
    public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -207,6 +208,10 @@ final class ActivityManagerConstants extends ContentObserver {
    // Indicates if the processes need to be started asynchronously.
    public boolean FLAG_PROCESS_START_ASYNC = DEFAULT_PROCESS_START_ASYNC;

    // Allow app just moving from TOP to FOREGROUND_SERVICE to stay in a higher adj value for
    // this long.
    public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION;

    // Indicates whether the activity starts logging is enabled.
    // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
    boolean mFlagActivityStartsLoggingEnabled;
@@ -348,6 +353,8 @@ final class ActivityManagerConstants extends ContentObserver {
                DEFAULT_BOUND_SERVICE_CRASH_MAX_RETRY);
            FLAG_PROCESS_START_ASYNC = mParser.getBoolean(KEY_PROCESS_START_ASYNC,
                    DEFAULT_PROCESS_START_ASYNC);
            TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION,
                    DEFAULT_TOP_TO_FGS_GRACE_DURATION);

            updateMaxCachedProcesses();
        }
@@ -423,6 +430,8 @@ final class ActivityManagerConstants extends ContentObserver {
        pw.println(MAX_SERVICE_INACTIVITY);
        pw.print("  "); pw.print(KEY_BG_START_TIMEOUT); pw.print("=");
        pw.println(BG_START_TIMEOUT);
        pw.print("  "); pw.print(KEY_TOP_TO_FGS_GRACE_DURATION); pw.print("=");
        pw.println(TOP_TO_FGS_GRACE_DURATION);

        pw.println();
        if (mOverrideMaxCachedProcesses >= 0) {
+26 −0
Original line number Diff line number Diff line
@@ -23390,6 +23390,19 @@ public class ActivityManagerService extends IActivityManager.Stub
            }
        }
        // If the app was recently in the foreground and moved to a foreground service status,
        // allow it to get a higher rank in memory for some time, compared to other foreground
        // services so that it can finish performing any persistence/processing of in-memory state.
        if (app.foregroundServices && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ
                && (app.lastTopTime + mConstants.TOP_TO_FGS_GRACE_DURATION > now
                    || app.setProcState <= ActivityManager.PROCESS_STATE_TOP)) {
            adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
            app.adjType = "fg-service-act";
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg: " + app);
            }
        }
        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                || procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
            if (app.forcingToImportant != null) {
@@ -23654,6 +23667,10 @@ public class ActivityManagerService extends IActivityManager.Stub
                                        schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                                        procState = ActivityManager.PROCESS_STATE_PERSISTENT;
                                    }
                                } else if ((cr.flags & Context.BIND_ADJUST_BELOW_PERCEPTIBLE) != 0
                                        && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
                                        && adj > ProcessList.PERCEPTIBLE_APP_ADJ + 1) {
                                    newAdj = ProcessList.PERCEPTIBLE_APP_ADJ + 1;
                                } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
                                        && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
                                        && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -24624,6 +24641,8 @@ public class ActivityManagerService extends IActivityManager.Stub
            // Must be called before updating setProcState
            maybeUpdateUsageStatsLocked(app, nowElapsed);
            maybeUpdateLastTopTime(app, now);
            app.setProcState = app.curProcState;
            if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
                app.notCachedSinceIdle = false;
@@ -24848,6 +24867,13 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
    }
    private void maybeUpdateLastTopTime(ProcessRecord app, long nowUptime) {
        if (app.setProcState <= ActivityManager.PROCESS_STATE_TOP
                && app.curProcState > ActivityManager.PROCESS_STATE_TOP) {
            app.lastTopTime = nowUptime;
        }
    }
    private final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
        if (proc.thread != null) {
            if (proc.baseProcessTracker != null) {
+5 −0
Original line number Diff line number Diff line
@@ -104,6 +104,11 @@ public final class ProcessList {
    static final int VISIBLE_APP_ADJ = 100;
    static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;

    // This is a process that was recently TOP and moved to FGS. Continue to treat it almost
    // like a foreground app for a while.
    // @see TOP_TO_FGS_GRACE_PERIOD
    static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;

    // This is the process running the current foreground app.  We'd really
    // rather not kill it!
    static final int FOREGROUND_APP_ADJ = 0;
+6 −0
Original line number Diff line number Diff line
@@ -163,6 +163,7 @@ final class ProcessRecord {
    long lastRequestedGc;       // When we last asked the app to do a gc
    long lastLowMemory;         // When we last told the app that memory is low
    long lastProviderTime;      // The last time someone else was using a provider in this process.
    long lastTopTime;           // The last time the process was in the TOP state or greater.
    boolean reportLowMemory;    // Set to true when waiting to report low mem
    boolean empty;              // Is this an empty background process?
    boolean cached;             // Is this a cached process?
@@ -380,6 +381,11 @@ final class ProcessRecord {
            TimeUtils.formatDuration(lastProviderTime, nowUptime, pw);
            pw.println();
        }
        if (lastTopTime > 0) {
            pw.print(prefix); pw.print("lastTopTime=");
            TimeUtils.formatDuration(lastTopTime, nowUptime, pw);
            pw.println();
        }
        if (hasStartedServices) {
            pw.print(prefix); pw.print("hasStartedServices="); pw.println(hasStartedServices);
        }
Loading