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

Commit 09dbf1fd authored by Tim Murray's avatar Tim Murray
Browse files

Add support for modern trim memory dispatch.

This CL adds flagged implementation of onTrimMemory dispatch to
improve consistency of dispatch and prevent unnecessary work from
unnecessary onTrimMemory calls. When the flag is enabled, trim level
dispatch is coupled to process state and completely decoupled from
memory state.

- When an app becomes eligible for freezing, TRIM_MEMORY_BACKGROUND
  will be triggered.

- Due to the likelihood of causing additional memory pressure when the
  device is already under memory pressure, no other TRIM_MEMORY
  constants will be used.

This implementation is behind the ActivityManager "use_modern_trim"
flag, which is currently set to false.

Test: atest android.app.cts.ActivityManagerTest
Bug: 253914117
Change-Id: I2c5b7db4b322723c2cc608d5f67946b8ccf77efb
parent 74da091e
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -151,6 +151,7 @@ final class ActivityManagerConstants extends ContentObserver {

    static final String KEY_USE_TIERED_CACHED_ADJ = "use_tiered_cached_adj";
    static final String KEY_TIERED_CACHED_ADJ_DECAY_TIME = "tiered_cached_adj_decay_time";
    static final String KEY_USE_MODERN_TRIM = "use_modern_trim";

    private static final int DEFAULT_MAX_CACHED_PROCESSES = 1024;
    private static final boolean DEFAULT_PRIORITIZE_ALARM_BROADCASTS = true;
@@ -212,6 +213,8 @@ final class ActivityManagerConstants extends ContentObserver {
    private static final boolean DEFAULT_USE_TIERED_CACHED_ADJ = false;
    private static final long DEFAULT_TIERED_CACHED_ADJ_DECAY_TIME = 60 * 1000;

    private static final boolean DEFAULT_USE_MODERN_TRIM = false;

    /**
     * Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
     */
@@ -1052,6 +1055,9 @@ final class ActivityManagerConstants extends ContentObserver {
    /** @see #KEY_TIERED_CACHED_ADJ_DECAY_TIME */
    public long TIERED_CACHED_ADJ_DECAY_TIME = DEFAULT_TIERED_CACHED_ADJ_DECAY_TIME;

    /** @see #KEY_USE_MODERN_TRIM */
    public boolean USE_MODERN_TRIM = DEFAULT_USE_MODERN_TRIM;

    private final OnPropertiesChangedListener mOnDeviceConfigChangedListener =
            new OnPropertiesChangedListener() {
                @Override
@@ -1227,6 +1233,9 @@ final class ActivityManagerConstants extends ContentObserver {
                            case KEY_TIERED_CACHED_ADJ_DECAY_TIME:
                                updateUseTieredCachedAdj();
                                break;
                            case KEY_USE_MODERN_TRIM:
                                updateUseModernTrim();
                                break;
                            default:
                                updateFGSPermissionEnforcementFlagsIfNecessary(name);
                                break;
@@ -1991,6 +2000,13 @@ final class ActivityManagerConstants extends ContentObserver {
            DEFAULT_TIERED_CACHED_ADJ_DECAY_TIME);
    }

    private void updateUseModernTrim() {
        USE_MODERN_TRIM = DeviceConfig.getBoolean(
            DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
            KEY_USE_MODERN_TRIM,
            DEFAULT_USE_MODERN_TRIM);
    }

    private void updateFGSPermissionEnforcementFlagsIfNecessary(@NonNull String name) {
        ForegroundServiceTypePolicy.getDefaultPolicy()
                .updatePermissionEnforcementFlagIfNecessary(name);
+31 −0
Original line number Diff line number Diff line
@@ -1005,6 +1005,37 @@ public class AppProfiler {
            mBgHandler.obtainMessage(BgHandler.MEMORY_PRESSURE_CHANGED, mLastMemoryLevel, memFactor)
                    .sendToTarget();
        }

        if (mService.mConstants.USE_MODERN_TRIM) {
            // Modern trim is not sent based on lowmem state
            // Dispatch UI_HIDDEN to processes that need it
            mService.mProcessList.forEachLruProcessesLOSP(true, app -> {
                final ProcessProfileRecord profile = app.mProfile;
                final IApplicationThread thread;
                final ProcessStateRecord state = app.mState;
                if (state.hasProcStateChanged()) {
                    state.setProcStateChanged(false);
                }
                int procState = app.mState.getCurProcState();
                if (((procState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
                        && procState < ActivityManager.PROCESS_STATE_CACHED_ACTIVITY)
                        || app.mState.isSystemNoUi()) && app.mProfile.hasPendingUiClean()) {
                    // If this application is now in the background and it
                    // had done UI, then give it the special trim level to
                    // have it free UI resources.
                    if ((thread = app.getThread()) != null) {
                        try {
                            thread.scheduleTrimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
                            app.mProfile.setPendingUiClean(false);
                        } catch (RemoteException e) {

                        }
                    }
                }
            });
            return false;
        }

        mLastMemoryLevel = memFactor;
        mLastNumProcesses = mService.mProcessList.getLruSizeLOSP();
        boolean allChanged;
+14 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.am;

import static android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_FROZEN;
import static android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_UNFROZEN;
import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;

import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_COMPACTION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FREEZER;
@@ -27,12 +28,14 @@ import android.annotation.IntDef;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ApplicationExitInfo;
import android.app.IApplicationThread;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.provider.DeviceConfig;
@@ -1231,6 +1234,17 @@ public final class CachedAppOptimizer {
            return;
        }

        if (mAm.mConstants.USE_MODERN_TRIM
                && app.mState.getSetAdj() >= ProcessList.CACHED_APP_MIN_ADJ) {
            final IApplicationThread thread = app.getThread();
            if (thread != null) {
                try {
                    thread.scheduleTrimMemory(TRIM_MEMORY_BACKGROUND);
                } catch (RemoteException e) {
                    // do nothing
                }
            }
        }
        mFreezeHandler.sendMessageDelayed(
                mFreezeHandler.obtainMessage(
                    SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app),