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

Commit f345d0b9 authored by Michael Wachenschwanz's avatar Michael Wachenschwanz Committed by Android (Google) Code Review
Browse files

Merge "OomAdjuster Freeze Handling with CPU capability" into main

parents 2a76c44a 19abe3a7
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -1016,6 +1016,12 @@ public class ActivityManager {
     */
    public static final int PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL = 1 << 6;

    /**
     * @hide
     * Process is guaranteed cpu time (IE. it will not be frozen).
     */
    public static final int PROCESS_CAPABILITY_CPU_TIME = 1 << 7;

    /**
     * @hide all capabilities, the ORing of all flags in {@link ProcessCapability}.
     *
@@ -1028,7 +1034,8 @@ public class ActivityManager {
            | PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
            | PROCESS_CAPABILITY_BFSL
            | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK
            | PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
            | PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL
            | PROCESS_CAPABILITY_CPU_TIME;

    /**
     * All implicit capabilities. This capability set is currently only used for processes under
@@ -1053,6 +1060,7 @@ public class ActivityManager {
        pw.print((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-');
        pw.print((caps & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0 ? 'U' : '-');
        pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL) != 0 ? 'A' : '-');
        pw.print((caps & PROCESS_CAPABILITY_CPU_TIME) != 0 ? 'T' : '-');
    }

    /** @hide */
@@ -1065,6 +1073,7 @@ public class ActivityManager {
        sb.append((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-');
        sb.append((caps & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0 ? 'U' : '-');
        sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL) != 0 ? 'A' : '-');
        sb.append((caps & PROCESS_CAPABILITY_CPU_TIME) != 0 ? 'T' : '-');
    }

    /**
+1 −1
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ import java.util.Random;
import java.util.Set;
import java.util.concurrent.Executor;

public final class CachedAppOptimizer {
public class CachedAppOptimizer {

    // Flags stored in the DeviceConfig API.
    @VisibleForTesting static final String KEY_USE_COMPACTION = "use_compaction";
+163 −41
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.am;
import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL_IMPLICIT;
import static android.app.ActivityManager.PROCESS_CAPABILITY_BFSL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_CPU_TIME;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
@@ -155,6 +156,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -469,7 +471,6 @@ public class OomAdjuster {
            }
            Process.setThreadPriority(tid, priority);
        }

    }

    // TODO(b/346822474): hook up global state usage.
@@ -499,7 +500,8 @@ public class OomAdjuster {
    }

    OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
            ServiceThread adjusterThread, GlobalState globalState, Injector injector) {
            ServiceThread adjusterThread, GlobalState globalState,
            CachedAppOptimizer cachedAppOptimizer, Injector injector) {
        mService = service;
        mGlobalState = globalState;
        mInjector = injector;
@@ -508,7 +510,7 @@ public class OomAdjuster {
        mActiveUids = activeUids;

        mConstants = mService.mConstants;
        mCachedAppOptimizer = new CachedAppOptimizer(mService);
        mCachedAppOptimizer = cachedAppOptimizer;
        mCacheOomRanker = new CacheOomRanker(service);

        mLogger = new OomAdjusterDebugLogger(this, mService.mConstants);
@@ -2590,6 +2592,7 @@ public class OomAdjuster {
        }

        capability |= getDefaultCapability(app, procState);
        capability |= getCpuCapability(app, now);

        // Procstates below BFGS should never have this capability.
        if (procState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
@@ -2732,10 +2735,14 @@ public class OomAdjuster {
            if (app.mOptRecord.setShouldNotFreeze(true, dryRun,
                    app.mOptRecord.shouldNotFreezeReason()
                    | client.mOptRecord.shouldNotFreezeReason(), mAdjSeq)) {
                if (Flags.useCpuTimeCapability()) {
                    // Do nothing, capability updated check will handle the dryrun output.
                } else {
                    // Bail out early, as we only care about the return value for a dryrun.
                    return true;
                }
            }
        }

        boolean trackedProcState = false;

@@ -2744,6 +2751,8 @@ public class OomAdjuster {
        // we check the final procstate, and remove it if the procsate is below BFGS.
        capability |= getBfslCapabilityFromClient(client);

        capability |= getCpuCapabilityFromClient(client);

        if (cr.notHasFlag(Context.BIND_WAIVE_PRIORITY)) {
            if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
                capability |= cstate.getCurCapability();
@@ -2802,10 +2811,15 @@ public class OomAdjuster {
                            app.mOptRecord.shouldNotFreezeReason()
                            | ProcessCachedOptimizerRecord
                            .SHOULD_NOT_FREEZE_REASON_BINDER_ALLOW_OOM_MANAGEMENT, mAdjSeq)) {
                        if (Flags.useCpuTimeCapability()) {
                            // Do nothing, capability updated check will handle the dryrun output.
                        } else {
                            // Bail out early, as we only care about the return value for a dryrun.
                            return true;
                        }
                    }
                    capability |= PROCESS_CAPABILITY_CPU_TIME;
                }
                // Not doing bind OOM management, so treat
                // this guy more like a started service.
                if (state.hasShownUi() && !state.getCachedIsHomeProcess()) {
@@ -3046,10 +3060,15 @@ public class OomAdjuster {
                        app.mOptRecord.shouldNotFreezeReason()
                        | ProcessCachedOptimizerRecord
                        .SHOULD_NOT_FREEZE_REASON_BIND_WAIVE_PRIORITY, mAdjSeq)) {
                    if (Flags.useCpuTimeCapability()) {
                        // Do nothing, capability updated check will handle the dryrun output.
                    } else {
                        // Bail out early, as we only care about the return value for a dryrun.
                        return true;
                    }
                }
                capability |= PROCESS_CAPABILITY_CPU_TIME;
            }
        }
        if (cr.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
            if (!dryRun) {
@@ -3101,9 +3120,24 @@ public class OomAdjuster {
            capability &= ~PROCESS_CAPABILITY_BFSL;
        }
        if (!updated) {
            updated = adj < prevRawAdj || procState < prevProcState || schedGroup > prevSchedGroup
                || (capability != prevCapability
                        && (capability & prevCapability) == prevCapability);
            if (adj < prevRawAdj || procState < prevProcState || schedGroup > prevSchedGroup) {
                updated = true;
            }

            if (Flags.useCpuTimeCapability()) {
                if ((capability != prevCapability)
                        && ((capability & prevCapability) == prevCapability)) {
                    updated = true;
                }
            } else {
                // Ignore PROCESS_CAPABILITY_CPU_TIME in capability comparison
                final int curFiltered = capability & ~PROCESS_CAPABILITY_CPU_TIME;
                final int prevFiltered = prevCapability & ~PROCESS_CAPABILITY_CPU_TIME;
                if ((curFiltered != prevFiltered)
                        && ((curFiltered & prevFiltered) == prevFiltered)) {
                    updated = true;
                }
            }
        }

        if (dryRun) {
@@ -3179,6 +3213,8 @@ public class OomAdjuster {
        // we check the final procstate, and remove it if the procsate is below BFGS.
        capability |= getBfslCapabilityFromClient(client);

        capability |= getCpuCapabilityFromClient(client);

        if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
            // If the other app is cached for any reason, for purposes here
            // we are going to consider it empty.
@@ -3189,10 +3225,14 @@ public class OomAdjuster {
            if (app.mOptRecord.setShouldNotFreeze(true, dryRun,
                    app.mOptRecord.shouldNotFreezeReason()
                    | client.mOptRecord.shouldNotFreezeReason(), mAdjSeq)) {
                if (Flags.useCpuTimeCapability()) {
                    // Do nothing, capability updated check will handle the dryrun output.
                } else {
                    // Bail out early, as we only care about the return value for a dryrun.
                    return true;
                }
            }
        }

        if (!dryRun) {
            state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp()
@@ -3266,12 +3306,27 @@ public class OomAdjuster {
            capability &= ~PROCESS_CAPABILITY_BFSL;
        }

        if (dryRun && (adj < prevRawAdj || procState < prevProcState || schedGroup > prevSchedGroup
                || (capability != prevCapability
                        && (capability & prevCapability) == prevCapability))) {
        if (dryRun) {
            if (adj < prevRawAdj || procState < prevProcState || schedGroup > prevSchedGroup) {
                return true;
            }

            if (Flags.useCpuTimeCapability()) {
                if ((capability != prevCapability)
                        && ((capability & prevCapability) == prevCapability)) {
                    return true;
                }
            } else {
                // Ignore PROCESS_CAPABILITY_CPU_TIME in capability comparison
                final int curFiltered = capability & ~PROCESS_CAPABILITY_CPU_TIME;
                final int prevFiltered = prevCapability & ~PROCESS_CAPABILITY_CPU_TIME;
                if ((curFiltered != prevFiltered)
                        && ((curFiltered & prevFiltered) == prevFiltered)) {
                    return true;
                }
            }
        }

        if (adj < prevRawAdj) {
            schedGroup = setIntermediateAdjLSP(app, adj, prevRawAdj, schedGroup);
        }
@@ -3321,6 +3376,29 @@ public class OomAdjuster {
        return baseCapabilities | networkCapabilities;
    }

    private static int getCpuCapability(ProcessRecord app, long nowUptime) {
        final UidRecord uidRec = app.getUidRecord();
        if (uidRec != null && uidRec.isCurAllowListed()) {
            // Process has user visible activities.
            return PROCESS_CAPABILITY_CPU_TIME;
        }
        if (UserHandle.isCore(app.uid)) {
            // Make sure all system components are not frozen.
            return PROCESS_CAPABILITY_CPU_TIME;
        }
        if (app.mState.getCachedHasVisibleActivities()) {
            // Process has user visible activities.
            return PROCESS_CAPABILITY_CPU_TIME;
        }
        if (app.mServices.hasUndemotedShortForegroundService(nowUptime)) {
            // It running a short fgs, just give it cpu time.
            return PROCESS_CAPABILITY_CPU_TIME;
        }
        // TODO(b/370817323): Populate this method with all of the reasons to keep a process
        //  unfrozen.
        return 0;
    }

    /**
     * @return the BFSL capability from a client (of a service binding or provider).
     */
@@ -3368,6 +3446,15 @@ public class OomAdjuster {
        return client.mState.getCurCapability() & PROCESS_CAPABILITY_BFSL;
    }

    /**
     * @return the CPU capability from a client (of a service binding or provider).
     */
    private static int getCpuCapabilityFromClient(ProcessRecord client) {
        // Just grant CPU capability every time
        // TODO(b/370817323): Populate with reasons to not propagate cpu capability across bindings.
        return client.mState.getCurCapability() & PROCESS_CAPABILITY_CPU_TIME;
    }

    /**
     * Checks if for the given app and client, there's a cycle that should skip over the client
     * for now or use partial values to evaluate the effect of the client binding.
@@ -3949,6 +4036,39 @@ public class OomAdjuster {
        mCacheOomRanker.dump(pw);
    }

    /**
     * Return whether or not a process should be frozen.
     */
    boolean getFreezePolicy(ProcessRecord proc) {
        // Reasons to not freeze:
        if (Flags.useCpuTimeCapability()) {
            if ((proc.mState.getCurCapability() & PROCESS_CAPABILITY_CPU_TIME) != 0) {
                /// App is important enough (see {@link #getCpuCapability}) or bound by something
                /// important enough to not be frozen.
                return false;
            }
        } else {
            // The CPU capability handling covers all setShouldNotFreeze paths. Must check
            // shouldNotFreeze, if the CPU capability is not being used.
            if (proc.mOptRecord.shouldNotFreeze()) {
                return false;
            }
        }

        if (proc.mOptRecord.isFreezeExempt()) {
            return false;
        }

        // Reasons to freeze:
        if (proc.mState.getCurAdj() >= FREEZER_CUTOFF_ADJ) {
            // Oomscore is in a high enough state, it is safe to freeze.
            return true;
        }

        // Default, do not freeze a process.
        return false;
    }

    @GuardedBy({"mService", "mProcLock"})
    void updateAppFreezeStateLSP(ProcessRecord app, @OomAdjReason int oomAdjReason,
            boolean immediate, int oldOomAdj) {
@@ -3963,45 +4083,46 @@ public class OomAdjuster {
                    (state.getCurAdj() >= FREEZER_CUTOFF_ADJ ^ oldOomAdj >= FREEZER_CUTOFF_ADJ)
                    || oldOomAdj == UNKNOWN_ADJ;
            final boolean shouldNotFreezeChanged = opt.shouldNotFreezeAdjSeq() == mAdjSeq;
            if ((oomAdjChanged || shouldNotFreezeChanged)
            final boolean hasCpuCapability =
                    (PROCESS_CAPABILITY_CPU_TIME & app.mState.getCurCapability())
                            == PROCESS_CAPABILITY_CPU_TIME;
            final boolean usedToHaveCpuCapability =
                    (PROCESS_CAPABILITY_CPU_TIME & app.mState.getSetCapability())
                            == PROCESS_CAPABILITY_CPU_TIME;
            final boolean cpuCapabilityChanged = hasCpuCapability != usedToHaveCpuCapability;
            if ((oomAdjChanged || shouldNotFreezeChanged || cpuCapabilityChanged)
                    && Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                Trace.instantForTrack(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        CachedAppOptimizer.ATRACE_FREEZER_TRACK,
                        "updateAppFreezeStateLSP " + app.processName
                        + " pid: " + app.getPid()
                        + " isFreezeExempt: " + opt.isFreezeExempt()
                        + " isFrozen: " + opt.isFrozen()
                        + " shouldNotFreeze: " + opt.shouldNotFreeze()
                        + " shouldNotFreezeReason: " + opt.shouldNotFreezeReason()
                        + " curAdj: " + state.getCurAdj()
                        + " oldOomAdj: " + oldOomAdj
                        + " immediate: " + immediate);
                        + " immediate: " + immediate
                        + " cpuCapability: " + hasCpuCapability);
            }
        }

        if (app.mOptRecord.isFreezeExempt()) {
            return;
        }

        // if an app is already frozen and shouldNotFreeze becomes true, immediately unfreeze
        if (opt.isFrozen() && opt.shouldNotFreeze()) {
            mCachedAppOptimizer.unfreezeAppLSP(app,
                    CachedAppOptimizer.getUnfreezeReasonCodeFromOomAdjReason(oomAdjReason));
            return;
        }

        // Use current adjustment when freezing, set adjustment when unfreezing.
        if (state.getCurAdj() >= FREEZER_CUTOFF_ADJ && !opt.isFrozen()
                && !opt.shouldNotFreeze()) {
            if (!immediate) {
                mCachedAppOptimizer.freezeAppAsyncLSP(app);
            } else {
        if (getFreezePolicy(app)) {
            // This process should be frozen.
            if (immediate && !opt.isFrozen()) {
                // And it will be frozen immediately.
                mCachedAppOptimizer.freezeAppAsyncAtEarliestLSP(app);
            } else if (!opt.isFrozen() || !opt.isPendingFreeze()) {
                mCachedAppOptimizer.freezeAppAsyncLSP(app);
            }
        } else if (state.getSetAdj() < FREEZER_CUTOFF_ADJ) {
        } else {
            // This process should not be frozen.
            if (opt.isFrozen() || opt.isPendingFreeze()) {
                mCachedAppOptimizer.unfreezeAppLSP(app,
                        CachedAppOptimizer.getUnfreezeReasonCodeFromOomAdjReason(oomAdjReason));
            }
        }
    }

    @GuardedBy("mService")
    void unfreezeTemporarily(ProcessRecord app, @OomAdjReason int reason) {
@@ -4023,7 +4144,8 @@ public class OomAdjuster {
        final int size = processes.size();
        for (int i = 0; i < size; i++) {
            ProcessRecord proc = processes.get(i);
            mCachedAppOptimizer.unfreezeTemporarily(proc, reason);
            mCachedAppOptimizer.unfreezeTemporarily(proc,
                    CachedAppOptimizer.getUnfreezeReasonCodeFromOomAdjReason(reason));
        }
        processes.clear();
    }
+3 −2
Original line number Diff line number Diff line
@@ -758,8 +758,9 @@ public class OomAdjusterModernImpl extends OomAdjuster {

    OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
            ActiveUids activeUids, ServiceThread adjusterThread, GlobalState globalState,
            Injector injector) {
        super(service, processList, activeUids, adjusterThread, globalState, injector);
            CachedAppOptimizer cachedAppOptimizer, Injector injector) {
        super(service, processList, activeUids, adjusterThread, globalState, cachedAppOptimizer,
                injector);
    }

    private final ProcessRecordNodes mProcessRecordProcStateNodes = new ProcessRecordNodes(
+8 −2
Original line number Diff line number Diff line
@@ -256,18 +256,24 @@ final class ProcessServiceRecord {
        }
        // Now we need to look at all short-FGS within the process and see if all of them are
        // procstate-timed-out or not.
        return !hasUndemotedShortForegroundService(nowUptime);
    }

    boolean hasUndemotedShortForegroundService(long nowUptime) {
        for (int i = mServices.size() - 1; i >= 0; i--) {
            final ServiceRecord sr = mServices.valueAt(i);
            if (!sr.isShortFgs() || !sr.hasShortFgsInfo()) {
                continue;
            }
            if (sr.getShortFgsInfo().getProcStateDemoteTime() >= nowUptime) {
                return false;
                // This short fgs has not timed out yet.
                return true;
            }
        }
        return true;
        return false;
    }


    int getReportedForegroundServiceTypes() {
        return mRepFgServiceTypes;
    }
Loading