OomAdjuster: use oom_adj_score tiers for cached apps
Metrics suggest that cached apps do not get promoted out of cached in anything resembling LRU ordering. Maintaining the LRU order is expensive for both ActivityManager and LMKD. Instead of a strict LRU, use tiers of oom_adj_scores for cached apps: - 900 for cached apps bound with BIND_WAIVE_PRIORITY or similar - 910 for freezer-eligible apps that entered cached in the last 60s - 950 for freezer-eligible apps that entered cached more than 60s ago Tiered oom_adj_scores for cached apps can be enabled with the "use_tiered_cached_adj" DeviceConfig flag, and the decay time (in ms) can be modified with the "tiered_cached_adj_decay_time" DeviceConfig flag. oom_adj_score tiers currently default to off. Bug: 253908413 Test: atest MockingOomAdjusterTests Change-Id: Ie386672c321227eb689902863df0b0022fa09e49 Merged-in: Ie386672c321227eb689902863df0b0022fa09e49
This commit is contained in:
@@ -146,6 +146,9 @@ final class ActivityManagerConstants extends ContentObserver {
|
|||||||
*/
|
*/
|
||||||
static final String KEY_NETWORK_ACCESS_TIMEOUT_MS = "network_access_timeout_ms";
|
static final String KEY_NETWORK_ACCESS_TIMEOUT_MS = "network_access_timeout_ms";
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
|
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
|
||||||
private static final boolean DEFAULT_PRIORITIZE_ALARM_BROADCASTS = true;
|
private static final boolean DEFAULT_PRIORITIZE_ALARM_BROADCASTS = true;
|
||||||
private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
|
private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
|
||||||
@@ -201,6 +204,9 @@ final class ActivityManagerConstants extends ContentObserver {
|
|||||||
|
|
||||||
static final int DEFAULT_MAX_SERVICE_CONNECTIONS_PER_PROCESS = 3000;
|
static final int DEFAULT_MAX_SERVICE_CONNECTIONS_PER_PROCESS = 3000;
|
||||||
|
|
||||||
|
private static final boolean DEFAULT_USE_TIERED_CACHED_ADJ = false;
|
||||||
|
private static final long DEFAULT_TIERED_CACHED_ADJ_DECAY_TIME = 60 * 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
|
* Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
|
||||||
*/
|
*/
|
||||||
@@ -1011,6 +1017,12 @@ final class ActivityManagerConstants extends ContentObserver {
|
|||||||
public volatile long mShortFgsAnrExtraWaitDuration =
|
public volatile long mShortFgsAnrExtraWaitDuration =
|
||||||
DEFAULT_SHORT_FGS_ANR_EXTRA_WAIT_DURATION;
|
DEFAULT_SHORT_FGS_ANR_EXTRA_WAIT_DURATION;
|
||||||
|
|
||||||
|
/** @see #KEY_USE_TIERED_CACHED_ADJ */
|
||||||
|
public boolean USE_TIERED_CACHED_ADJ = DEFAULT_USE_TIERED_CACHED_ADJ;
|
||||||
|
|
||||||
|
/** @see #KEY_TIERED_CACHED_ADJ_DECAY_TIME */
|
||||||
|
public long TIERED_CACHED_ADJ_DECAY_TIME = DEFAULT_TIERED_CACHED_ADJ_DECAY_TIME;
|
||||||
|
|
||||||
private final OnPropertiesChangedListener mOnDeviceConfigChangedListener =
|
private final OnPropertiesChangedListener mOnDeviceConfigChangedListener =
|
||||||
new OnPropertiesChangedListener() {
|
new OnPropertiesChangedListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -1179,6 +1191,10 @@ final class ActivityManagerConstants extends ContentObserver {
|
|||||||
case KEY_MAX_PREVIOUS_TIME:
|
case KEY_MAX_PREVIOUS_TIME:
|
||||||
updateMaxPreviousTime();
|
updateMaxPreviousTime();
|
||||||
break;
|
break;
|
||||||
|
case KEY_USE_TIERED_CACHED_ADJ:
|
||||||
|
case KEY_TIERED_CACHED_ADJ_DECAY_TIME:
|
||||||
|
updateUseTieredCachedAdj();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1924,6 +1940,17 @@ final class ActivityManagerConstants extends ContentObserver {
|
|||||||
DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION);
|
DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateUseTieredCachedAdj() {
|
||||||
|
USE_TIERED_CACHED_ADJ = DeviceConfig.getBoolean(
|
||||||
|
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||||
|
KEY_USE_TIERED_CACHED_ADJ,
|
||||||
|
DEFAULT_USE_TIERED_CACHED_ADJ);
|
||||||
|
TIERED_CACHED_ADJ_DECAY_TIME = DeviceConfig.getLong(
|
||||||
|
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||||
|
KEY_TIERED_CACHED_ADJ_DECAY_TIME,
|
||||||
|
DEFAULT_TIERED_CACHED_ADJ_DECAY_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
@NeverCompile // Avoid size overhead of debugging code.
|
@NeverCompile // Avoid size overhead of debugging code.
|
||||||
void dump(PrintWriter pw) {
|
void dump(PrintWriter pw) {
|
||||||
pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
|
pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
|
||||||
@@ -2108,6 +2135,11 @@ final class ActivityManagerConstants extends ContentObserver {
|
|||||||
pw.print(" "); pw.print(KEY_SHORT_FGS_ANR_EXTRA_WAIT_DURATION);
|
pw.print(" "); pw.print(KEY_SHORT_FGS_ANR_EXTRA_WAIT_DURATION);
|
||||||
pw.print("="); pw.println(mShortFgsAnrExtraWaitDuration);
|
pw.print("="); pw.println(mShortFgsAnrExtraWaitDuration);
|
||||||
|
|
||||||
|
pw.print(" "); pw.print(KEY_USE_TIERED_CACHED_ADJ);
|
||||||
|
pw.print("="); pw.println(USE_TIERED_CACHED_ADJ);
|
||||||
|
pw.print(" "); pw.print(KEY_TIERED_CACHED_ADJ_DECAY_TIME);
|
||||||
|
pw.print("="); pw.println(TIERED_CACHED_ADJ_DECAY_TIME);
|
||||||
|
|
||||||
pw.println();
|
pw.println();
|
||||||
if (mOverrideMaxCachedProcesses >= 0) {
|
if (mOverrideMaxCachedProcesses >= 0) {
|
||||||
pw.print(" mOverrideMaxCachedProcesses="); pw.println(mOverrideMaxCachedProcesses);
|
pw.print(" mOverrideMaxCachedProcesses="); pw.println(mOverrideMaxCachedProcesses);
|
||||||
|
|||||||
@@ -1073,7 +1073,34 @@ public class OomAdjuster {
|
|||||||
@GuardedBy({"mService", "mProcLock"})
|
@GuardedBy({"mService", "mProcLock"})
|
||||||
private void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) {
|
private void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) {
|
||||||
final int numLru = lruList.size();
|
final int numLru = lruList.size();
|
||||||
|
if (mConstants.USE_TIERED_CACHED_ADJ) {
|
||||||
|
final long now = SystemClock.uptimeMillis();
|
||||||
|
for (int i = numLru - 1; i >= 0; i--) {
|
||||||
|
ProcessRecord app = lruList.get(i);
|
||||||
|
final ProcessStateRecord state = app.mState;
|
||||||
|
final ProcessCachedOptimizerRecord opt = app.mOptRecord;
|
||||||
|
if (!app.isKilledByAm() && app.getThread() != null && state.getCurAdj()
|
||||||
|
>= UNKNOWN_ADJ) {
|
||||||
|
final ProcessServiceRecord psr = app.mServices;
|
||||||
|
int targetAdj = CACHED_APP_MIN_ADJ;
|
||||||
|
|
||||||
|
if (opt != null && opt.isFreezeExempt()) {
|
||||||
|
// BIND_WAIVE_PRIORITY and the like get oom_adj 900
|
||||||
|
targetAdj += 0;
|
||||||
|
} else if ((state.getSetAdj() >= CACHED_APP_MIN_ADJ)
|
||||||
|
&& (state.getLastStateTime()
|
||||||
|
+ mConstants.TIERED_CACHED_ADJ_DECAY_TIME) < now) {
|
||||||
|
// Older cached apps get 950
|
||||||
|
targetAdj += 50;
|
||||||
|
} else {
|
||||||
|
// Newer cached apps get 910
|
||||||
|
targetAdj += 10;
|
||||||
|
}
|
||||||
|
state.setCurRawAdj(targetAdj);
|
||||||
|
state.setCurAdj(psr.modifyRawOomAdj(targetAdj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// First update the OOM adjustment for each of the
|
// First update the OOM adjustment for each of the
|
||||||
// application processes based on their current state.
|
// application processes based on their current state.
|
||||||
int curCachedAdj = CACHED_APP_MIN_ADJ;
|
int curCachedAdj = CACHED_APP_MIN_ADJ;
|
||||||
@@ -1099,7 +1126,8 @@ public class OomAdjuster {
|
|||||||
// instead of a gazillion empty processes.
|
// instead of a gazillion empty processes.
|
||||||
numEmptyProcs = cachedProcessLimit;
|
numEmptyProcs = cachedProcessLimit;
|
||||||
}
|
}
|
||||||
int cachedFactor = (mNumCachedHiddenProcs > 0 ? (mNumCachedHiddenProcs + mNumSlots - 1) : 1)
|
int cachedFactor = (mNumCachedHiddenProcs > 0
|
||||||
|
? (mNumCachedHiddenProcs + mNumSlots - 1) : 1)
|
||||||
/ mNumSlots;
|
/ mNumSlots;
|
||||||
if (cachedFactor < 1) cachedFactor = 1;
|
if (cachedFactor < 1) cachedFactor = 1;
|
||||||
|
|
||||||
@@ -1112,6 +1140,7 @@ public class OomAdjuster {
|
|||||||
int lastCachedGroupImportance = 0;
|
int lastCachedGroupImportance = 0;
|
||||||
int lastCachedGroupUid = 0;
|
int lastCachedGroupUid = 0;
|
||||||
|
|
||||||
|
|
||||||
for (int i = numLru - 1; i >= 0; i--) {
|
for (int i = numLru - 1; i >= 0; i--) {
|
||||||
ProcessRecord app = lruList.get(i);
|
ProcessRecord app = lruList.get(i);
|
||||||
final ProcessStateRecord state = app.mState;
|
final ProcessStateRecord state = app.mState;
|
||||||
@@ -1193,7 +1222,8 @@ public class OomAdjuster {
|
|||||||
state.setCurAdj(psr.modifyRawOomAdj(curEmptyAdj));
|
state.setCurAdj(psr.modifyRawOomAdj(curEmptyAdj));
|
||||||
if (DEBUG_LRU) {
|
if (DEBUG_LRU) {
|
||||||
Slog.d(TAG_LRU, "Assigning empty LRU #" + i
|
Slog.d(TAG_LRU, "Assigning empty LRU #" + i
|
||||||
+ " adj: " + state.getCurAdj() + " (curEmptyAdj=" + curEmptyAdj
|
+ " adj: " + state.getCurAdj()
|
||||||
|
+ " (curEmptyAdj=" + curEmptyAdj
|
||||||
+ ")");
|
+ ")");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1201,7 +1231,7 @@ public class OomAdjuster {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private long mNextNoKillDebugMessageTime;
|
private long mNextNoKillDebugMessageTime;
|
||||||
|
|
||||||
private double mLastFreeSwapPercent = 1.00;
|
private double mLastFreeSwapPercent = 1.00;
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ public class MockingOomAdjusterTests {
|
|||||||
private static final String MOCKAPP5_PROCESSNAME = "test #5";
|
private static final String MOCKAPP5_PROCESSNAME = "test #5";
|
||||||
private static final String MOCKAPP5_PACKAGENAME = "com.android.test.test5";
|
private static final String MOCKAPP5_PACKAGENAME = "com.android.test.test5";
|
||||||
private static final int MOCKAPP2_UID_OTHER = MOCKAPP2_UID + UserHandle.PER_USER_RANGE;
|
private static final int MOCKAPP2_UID_OTHER = MOCKAPP2_UID + UserHandle.PER_USER_RANGE;
|
||||||
private static final int FIRST_CACHED_ADJ = ProcessList.CACHED_APP_MIN_ADJ
|
private static int sFirstCachedAdj = ProcessList.CACHED_APP_MIN_ADJ
|
||||||
+ ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
|
+ ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
|
||||||
private static Context sContext;
|
private static Context sContext;
|
||||||
private static PackageManagerInternal sPackageManagerInternal;
|
private static PackageManagerInternal sPackageManagerInternal;
|
||||||
@@ -208,6 +208,9 @@ public class MockingOomAdjusterTests {
|
|||||||
new ActiveUids(sService, false));
|
new ActiveUids(sService, false));
|
||||||
sService.mOomAdjuster.mAdjSeq = 10000;
|
sService.mOomAdjuster.mAdjSeq = 10000;
|
||||||
sService.mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE);
|
sService.mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE);
|
||||||
|
if (sService.mConstants.USE_TIERED_CACHED_ADJ) {
|
||||||
|
sFirstCachedAdj = ProcessList.CACHED_APP_MIN_ADJ + 10;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
@@ -834,7 +837,7 @@ public class MockingOomAdjusterTests {
|
|||||||
updateOomAdj(client, app);
|
updateOomAdj(client, app);
|
||||||
doReturn(null).when(sService).getTopApp();
|
doReturn(null).when(sService).getTopApp();
|
||||||
|
|
||||||
assertProcStates(app, PROCESS_STATE_SERVICE, FIRST_CACHED_ADJ, SCHED_GROUP_BACKGROUND);
|
assertProcStates(app, PROCESS_STATE_SERVICE, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("GuardedBy")
|
@SuppressWarnings("GuardedBy")
|
||||||
@@ -882,7 +885,7 @@ public class MockingOomAdjusterTests {
|
|||||||
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
|
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
|
||||||
updateOomAdj(app);
|
updateOomAdj(app);
|
||||||
|
|
||||||
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FIRST_CACHED_ADJ, SCHED_GROUP_BACKGROUND);
|
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("GuardedBy")
|
@SuppressWarnings("GuardedBy")
|
||||||
@@ -1286,7 +1289,7 @@ public class MockingOomAdjusterTests {
|
|||||||
bindProvider(app, app, null, null, false);
|
bindProvider(app, app, null, null, false);
|
||||||
updateOomAdj(app);
|
updateOomAdj(app);
|
||||||
|
|
||||||
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FIRST_CACHED_ADJ, SCHED_GROUP_BACKGROUND);
|
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("GuardedBy")
|
@SuppressWarnings("GuardedBy")
|
||||||
@@ -1301,7 +1304,7 @@ public class MockingOomAdjusterTests {
|
|||||||
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
|
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
|
||||||
updateOomAdj(app, client);
|
updateOomAdj(app, client);
|
||||||
|
|
||||||
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FIRST_CACHED_ADJ, SCHED_GROUP_BACKGROUND);
|
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("GuardedBy")
|
@SuppressWarnings("GuardedBy")
|
||||||
@@ -2378,8 +2381,12 @@ public class MockingOomAdjusterTests {
|
|||||||
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
|
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
|
||||||
final int userOwner = 0;
|
final int userOwner = 0;
|
||||||
final int userOther = 1;
|
final int userOther = 1;
|
||||||
final int cachedAdj1 = CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
|
final int cachedAdj1 = sService.mConstants.USE_TIERED_CACHED_ADJ
|
||||||
final int cachedAdj2 = cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
|
? CACHED_APP_MIN_ADJ + 10
|
||||||
|
: CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
|
||||||
|
final int cachedAdj2 = sService.mConstants.USE_TIERED_CACHED_ADJ
|
||||||
|
? CACHED_APP_MIN_ADJ + 10
|
||||||
|
: cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
|
||||||
doReturn(userOwner).when(sService.mUserController).getCurrentUserId();
|
doReturn(userOwner).when(sService.mUserController).getCurrentUserId();
|
||||||
|
|
||||||
final ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP();
|
final ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP();
|
||||||
|
|||||||
Reference in New Issue
Block a user