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

Commit e8ee43ff authored by Chen Bai's avatar Chen Bai Committed by Android (Google) Code Review
Browse files

Merge "oom: not skip evaluation of connection with BIND_SCHEDULE_LIKE_TOP_APP" into main

parents ca7b0517 8287345a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ALLOWLIST;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BACKUP;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SERVICE_BINDER_CALL;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BIND_SERVICE;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_COMPONENT_DISABLED;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_EXECUTING_SERVICE;
@@ -52,6 +51,7 @@ import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_RECONFIGURATION
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_PROVIDER;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_TASK;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_RESTRICTION_CHANGE;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SERVICE_BINDER_CALL;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SHELL;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SHORT_FGS_TIMEOUT;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_START_RECEIVER;
+45 −19
Original line number Diff line number Diff line
@@ -991,13 +991,12 @@ public class OomAdjusterImpl extends OomAdjuster {
            ConnectionRecord cr = psr.getConnectionAt(i);
            ProcessRecord service = cr.hasFlag(ServiceInfo.FLAG_ISOLATED_PROCESS)
                    ? cr.binding.service.isolationHostProc : cr.binding.service.app;
            if (service == null || service == app
                    || (service.mState.getMaxAdj() >= SYSTEM_ADJ
                    && service.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
                    || (service.mState.getCurAdj() <= FOREGROUND_APP_ADJ
                    && service.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
                    && service.mState.getCurProcState() <= PROCESS_STATE_TOP)
                    || (service.isSdkSandbox && cr.binding.attributedClient != null)) {
            if (service == null || service == app || isSandboxAttributedConnection(cr, service)) {
                continue;
            }
            // If the host is high priority, skip the connection recompute unless the connection has
            // flags, which needs extra consideration. e.g. BIND_SCHEDULE_LIKE_TOP_APP
            if (isHighPriorityProcess(service) && allowSkipForBindScheduleLikeTopApp(cr, service)) {
                continue;
            }
            connectionConsumer.accept(cr, service);
@@ -1006,12 +1005,10 @@ public class OomAdjusterImpl extends OomAdjuster {
        for (int i = psr.numberOfSdkSandboxConnections() - 1; i >= 0; i--) {
            final ConnectionRecord cr = psr.getSdkSandboxConnectionAt(i);
            final ProcessRecord service = cr.binding.service.app;
            if (service == null || service == app
                    || (service.mState.getMaxAdj() >= SYSTEM_ADJ
                    && service.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
                    || (service.mState.getCurAdj() <= FOREGROUND_APP_ADJ
                    && service.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
                    && service.mState.getCurProcState() <= PROCESS_STATE_TOP)) {
            if (service == null || service == app) {
                continue;
            }
            if (isHighPriorityProcess(service) && allowSkipForBindScheduleLikeTopApp(cr, service)) {
                continue;
            }
            connectionConsumer.accept(cr, service);
@@ -1021,18 +1018,47 @@ public class OomAdjusterImpl extends OomAdjuster {
        for (int i = ppr.numberOfProviderConnections() - 1; i >= 0; i--) {
            ContentProviderConnection cpc = ppr.getProviderConnectionAt(i);
            ProcessRecord provider = cpc.provider.proc;
            if (provider == null || provider == app
                    || (provider.mState.getMaxAdj() >= ProcessList.SYSTEM_ADJ
                    && provider.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
                    || (provider.mState.getCurAdj() <= FOREGROUND_APP_ADJ
                    && provider.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
                    && provider.mState.getCurProcState() <= PROCESS_STATE_TOP)) {
            if (provider == null || provider == app || isHighPriorityProcess(provider)) {
                continue;
            }
            connectionConsumer.accept(cpc, provider);
        }
    }

    /**
     * This is one of the condition that blocks the skipping of connection evaluation. This method
     * returns false when the given connection has flag {@link Context#BIND_SCHEDULE_LIKE_TOP_APP}
     * but the host process has not set the corresponding flag,
     * {@link ProcessStateRecord#mScheduleLikeTopApp}.
     */
    private static boolean allowSkipForBindScheduleLikeTopApp(ConnectionRecord cr,
            ProcessRecord host) {
        // If feature flag for optionally blocking skipping is disabled. Always allow skipping.
        if (!Flags.notSkipConnectionRecomputeForBindScheduleLikeTopApp()) {
            return true;
        }

        // Need to check shouldScheduleLikeTopApp otherwise, there will be too many recompute which
        // leads to OOM.
        return !(cr.hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP)
                && !host.mState.shouldScheduleLikeTopApp());
    }

    private static boolean isSandboxAttributedConnection(ConnectionRecord cr, ProcessRecord host) {
        return host.isSdkSandbox && cr.binding.attributedClient != null;
    }

    private static boolean isHighPriorityProcess(ProcessRecord proc) {
        final boolean isPersistentSystemProcess = proc.mState.getMaxAdj() >= SYSTEM_ADJ
                && proc.mState.getMaxAdj() < FOREGROUND_APP_ADJ;

        final boolean isEffectivelyForeground = proc.mState.getCurAdj() <= FOREGROUND_APP_ADJ
                && proc.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
                && proc.mState.getCurProcState() <= PROCESS_STATE_TOP;

        return isPersistentSystemProcess || isEffectivelyForeground;
    }

    /**
     * Stream the connections from clients with {@code app} as the host to {@code
     * connectionConsumer}.
+7 −0
Original line number Diff line number Diff line
@@ -258,3 +258,10 @@ flag {
    description: "Enable ActivityManagerStructured Service"
    bug: "419409018"
}

flag {
    name: "not_skip_connection_recompute_for_bind_schedule_like_top_app"
    namespace: "wear_frameworks"
    description: "If a connection has flag BIND_SCHEDULE_LIKE_TOP_APP but the host process has not set the corresponding flag, do not skip the connection recompute."
    bug: "417720000"
}
+86 −0
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ import static com.android.server.am.ProcessList.SCHED_GROUP_TOP_APP;
import static com.android.server.am.ProcessList.SCHED_GROUP_TOP_APP_BOUND;
import static com.android.server.am.ProcessList.SERVICE_ADJ;
import static com.android.server.am.ProcessList.SERVICE_B_ADJ;
import static com.android.server.am.ProcessList.SYSTEM_ADJ;
import static com.android.server.am.ProcessList.UNKNOWN_ADJ;
import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED;
@@ -115,6 +116,7 @@ import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -3760,6 +3762,90 @@ public class MockingOomAdjusterTests {
                SCHED_GROUP_RESTRICTED);
    }

    @SuppressWarnings("GuardedBy")
    @Test
    public void testUpdateOomAdj_bindScheduleLikeTopApp_systemClient_hostGetsTopSchedGroup() {
        // When system client binds a service with BIND_SCHEDULE_LIKE_TOP_APP, the service should
        // will be prioritized as top app.
        ProcessRecord host = makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME,
                MOCKAPP_PACKAGENAME, true);
        host.mState.setCurrentSchedulingGroup(SCHED_GROUP_DEFAULT);
        ProcessRecord client = makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false);
        mProcessStateController.setMaxAdj(client, SYSTEM_ADJ);

        bindService(host, client, null, null, Context.BIND_SCHEDULE_LIKE_TOP_APP,
                mock(IBinder.class));
        updateOomAdj(client);

        assertTrue(host.mState.shouldScheduleLikeTopApp());
        assertEquals(SCHED_GROUP_TOP_APP, host.mState.getCurrentSchedulingGroup());
    }

    @SuppressWarnings("GuardedBy")
    @Test
    public void testUpdateOomAdj_bindScheduleLikeTopApp_nonSystemClient_hostNotGetTopSchedGroup() {
        ProcessRecord host = makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME,
                MOCKAPP_PACKAGENAME, true);
        ProcessRecord client = makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false);
        mProcessStateController.setMaxAdj(client, PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ);

        bindService(host, client, null, null, Context.BIND_SCHEDULE_LIKE_TOP_APP,
                mock(IBinder.class));
        updateOomAdj(client);

        assertFalse(host.mState.shouldScheduleLikeTopApp());
        assertNotEquals(SCHED_GROUP_TOP_APP, host.mState.getCurrentSchedulingGroup());
    }

    @SuppressWarnings("GuardedBy")
    @Test
    @DisableFlags(Flags.FLAG_NOT_SKIP_CONNECTION_RECOMPUTE_FOR_BIND_SCHEDULE_LIKE_TOP_APP)
    public void testUpdateOomAdj_bindScheduleLikeTopApp_systemClient_hostPrivileged_skipConnectionCompute_hostNotGetTopSchedGroup() {
        // Similar to testUpdateOomAdj_bindScheduleLikeTopApp_systemClient_hostGetsTopSchedGroup,
        // but now the host process is already marked as privileged(see
        // OomAdjusterImpl#isHighPriorityProcess for detail). In this case, connection evaluation
        // will be skipped, as a result, the scheduling group stays default.
        ProcessRecord host = makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME,
                MOCKAPP_PACKAGENAME, true);
        mProcessStateController.setMaxAdj(host, PERSISTENT_SERVICE_ADJ);
        ProcessRecord client = makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false);
        mProcessStateController.setMaxAdj(client, SYSTEM_ADJ);

        bindService(host, client, null, null, Context.BIND_SCHEDULE_LIKE_TOP_APP,
                mock(IBinder.class));
        updateOomAdj(client);

        // The update for host by its client connection evaluation is skipped.
        assertFalse(host.mState.shouldScheduleLikeTopApp());
        assertNotEquals(SCHED_GROUP_TOP_APP, host.mState.getSetSchedGroup());
    }

    @SuppressWarnings("GuardedBy")
    @Test
    @EnableFlags(Flags.FLAG_NOT_SKIP_CONNECTION_RECOMPUTE_FOR_BIND_SCHEDULE_LIKE_TOP_APP)
    public void testUpdateOomAdj_bindScheduleLikeTopApp_systemClient_hostPrivileged_notSkipConnectionCompute_hostGetsTopSchedGroup() {
        // Similar to its counter-part "withoutFlag" but when the feature flag
        // "not_skip_connection_recompute_for_bind_schedule_like_top_app" is enabled, the evaluation
        // of connection with BIND_SCHEDULE_LIKE_TOP_APP will not be skipped if the corresponding
        // flag has not yet been set.
        ProcessRecord host = makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME,
                MOCKAPP_PACKAGENAME, true);
        mProcessStateController.setMaxAdj(host, PERSISTENT_SERVICE_ADJ);
        ProcessRecord client = makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false);
        mProcessStateController.setMaxAdj(client, SYSTEM_ADJ);

        bindService(host, client, null, null, Context.BIND_SCHEDULE_LIKE_TOP_APP,
                mock(IBinder.class));
        updateOomAdj(client);

        assertTrue(host.mState.shouldScheduleLikeTopApp());
        assertEquals(SCHED_GROUP_TOP_APP, host.mState.getCurrentSchedulingGroup());
    }

    private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
            String packageName, boolean hasShownUi) {
        return new ProcessRecordBuilder(pid, uid, processName, packageName).setHasShownUi(