From 09dbf1fdbee6d155917a15f669b9fbda1fd750ab Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Sun, 19 Mar 2023 20:59:55 -0700 Subject: [PATCH] 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 --- .../server/am/ActivityManagerConstants.java | 16 ++++++++++ .../com/android/server/am/AppProfiler.java | 31 +++++++++++++++++++ .../android/server/am/CachedAppOptimizer.java | 14 +++++++++ 3 files changed, 61 insertions(+) diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 553706db34d8e..41f1e85c27c3a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -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); diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java index ccd739006713d..25ac956d328d7 100644 --- a/services/core/java/com/android/server/am/AppProfiler.java +++ b/services/core/java/com/android/server/am/AppProfiler.java @@ -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; diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 9c1546324e4b5..78edbba2e5698 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -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),