diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java index 9216343e05d8d..c73c808450109 100644 --- a/services/core/java/com/android/server/am/AppCompactor.java +++ b/services/core/java/com/android/server/am/AppCompactor.java @@ -51,6 +51,8 @@ public final class AppCompactor { @VisibleForTesting static final String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2"; @VisibleForTesting static final String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3"; @VisibleForTesting static final String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4"; + @VisibleForTesting static final String KEY_COMPACT_THROTTLE_5 = "compact_throttle_5"; + @VisibleForTesting static final String KEY_COMPACT_THROTTLE_6 = "compact_throttle_6"; @VisibleForTesting static final String KEY_COMPACT_STATSD_SAMPLE_RATE = "compact_statsd_sample_rate"; @@ -73,6 +75,8 @@ public final class AppCompactor { @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000; @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500; @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_4 = 10_000; + @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_5 = 10 * 60 * 1000; + @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_6 = 10 * 60 * 1000; // The sampling rate to push app compaction events into statsd for upload. @VisibleForTesting static final float DEFAULT_STATSD_SAMPLE_RATE = 0.1f; @@ -85,6 +89,8 @@ public final class AppCompactor { // Handler constants. static final int COMPACT_PROCESS_SOME = 1; static final int COMPACT_PROCESS_FULL = 2; + static final int COMPACT_PROCESS_PERSISTENT = 3; + static final int COMPACT_PROCESS_BFGS = 4; static final int COMPACT_PROCESS_MSG = 1; /** @@ -142,6 +148,10 @@ public final class AppCompactor { @GuardedBy("mPhenotypeFlagLock") @VisibleForTesting volatile long mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4; @GuardedBy("mPhenotypeFlagLock") + @VisibleForTesting volatile long mCompactThrottleBFGS = DEFAULT_COMPACT_THROTTLE_5; + @GuardedBy("mPhenotypeFlagLock") + @VisibleForTesting volatile long mCompactThrottlePersistent = DEFAULT_COMPACT_THROTTLE_6; + @GuardedBy("mPhenotypeFlagLock") private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION; private final Random mRandom = new Random(); @@ -224,6 +234,36 @@ public final class AppCompactor { } + @GuardedBy("mAm") + void compactAppPersistent(ProcessRecord app) { + app.reqCompactAction = COMPACT_PROCESS_PERSISTENT; + mPendingCompactionProcesses.add(app); + mCompactionHandler.sendMessage( + mCompactionHandler.obtainMessage( + COMPACT_PROCESS_MSG, app.curAdj, app.setProcState)); + } + + @GuardedBy("mAm") + boolean shouldCompactPersistent(ProcessRecord app, long now) { + return (app.lastCompactTime == 0 + || (now - app.lastCompactTime) > mCompactThrottlePersistent); + } + + @GuardedBy("mAm") + void compactAppBfgs(ProcessRecord app) { + app.reqCompactAction = COMPACT_PROCESS_BFGS; + mPendingCompactionProcesses.add(app); + mCompactionHandler.sendMessage( + mCompactionHandler.obtainMessage( + COMPACT_PROCESS_MSG, app.curAdj, app.setProcState)); + } + + @GuardedBy("mAm") + boolean shouldCompactBFGS(ProcessRecord app, long now) { + return (app.lastCompactTime == 0 + || (now - app.lastCompactTime) > mCompactThrottleBFGS); + } + /** * Reads the flag value from DeviceConfig to determine whether app compaction * should be enabled, and starts/stops the compaction thread as needed. @@ -265,10 +305,18 @@ public final class AppCompactor { String throttleFullFullFlag = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_COMPACT_THROTTLE_4); + String throttleBFGSFlag = + DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_COMPACT_THROTTLE_5); + String throttlePersistentFlag = + DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_COMPACT_THROTTLE_6); if (TextUtils.isEmpty(throttleSomeSomeFlag) || TextUtils.isEmpty(throttleSomeFullFlag) || TextUtils.isEmpty(throttleFullSomeFlag) - || TextUtils.isEmpty(throttleFullFullFlag)) { + || TextUtils.isEmpty(throttleFullFullFlag) + || TextUtils.isEmpty(throttleBFGSFlag) + || TextUtils.isEmpty(throttlePersistentFlag)) { // Set defaults for all if any are not set. useThrottleDefaults = true; } else { @@ -277,6 +325,8 @@ public final class AppCompactor { mCompactThrottleSomeFull = Integer.parseInt(throttleSomeFullFlag); mCompactThrottleFullSome = Integer.parseInt(throttleFullSomeFlag); mCompactThrottleFullFull = Integer.parseInt(throttleFullFullFlag); + mCompactThrottleBFGS = Integer.parseInt(throttleBFGSFlag); + mCompactThrottlePersistent = Integer.parseInt(throttlePersistentFlag); } catch (NumberFormatException e) { useThrottleDefaults = true; } @@ -287,6 +337,8 @@ public final class AppCompactor { mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2; mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3; mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4; + mCompactThrottleBFGS = DEFAULT_COMPACT_THROTTLE_5; + mCompactThrottlePersistent = DEFAULT_COMPACT_THROTTLE_6; } } @@ -332,14 +384,19 @@ public final class AppCompactor { synchronized (mAm) { proc = mPendingCompactionProcesses.remove(0); + pendingAction = proc.reqCompactAction; + // don't compact if the process has returned to perceptible - if (proc.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) { + // and this is only a cached/home/prev compaction + if ((pendingAction == COMPACT_PROCESS_SOME + || pendingAction == COMPACT_PROCESS_FULL) + && (proc.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ)) { return; } pid = proc.pid; name = proc.processName; - pendingAction = proc.reqCompactAction; + lastCompactAction = proc.lastCompactAction; lastCompactTime = proc.lastCompactTime; } @@ -356,31 +413,49 @@ public final class AppCompactor { // Note that we explicitly don't take mPhenotypeFlagLock here as the flags // should very seldom change, and taking the risk of using the wrong action is // preferable to taking the lock for every single compaction action. - if (pendingAction == COMPACT_PROCESS_SOME) { - if ((lastCompactAction == COMPACT_PROCESS_SOME - && (start - lastCompactTime < mCompactThrottleSomeSome)) - || (lastCompactAction == COMPACT_PROCESS_FULL - && (start - lastCompactTime - < mCompactThrottleSomeFull))) { - return; - } - } else { - if ((lastCompactAction == COMPACT_PROCESS_SOME - && (start - lastCompactTime < mCompactThrottleFullSome)) - || (lastCompactAction == COMPACT_PROCESS_FULL - && (start - lastCompactTime - < mCompactThrottleFullFull))) { - return; + if (lastCompactTime != 0) { + if (pendingAction == COMPACT_PROCESS_SOME) { + if ((lastCompactAction == COMPACT_PROCESS_SOME + && (start - lastCompactTime < mCompactThrottleSomeSome)) + || (lastCompactAction == COMPACT_PROCESS_FULL + && (start - lastCompactTime + < mCompactThrottleSomeFull))) { + return; + } + } else if (pendingAction == COMPACT_PROCESS_FULL) { + if ((lastCompactAction == COMPACT_PROCESS_SOME + && (start - lastCompactTime < mCompactThrottleFullSome)) + || (lastCompactAction == COMPACT_PROCESS_FULL + && (start - lastCompactTime + < mCompactThrottleFullFull))) { + return; + } + } else if (pendingAction == COMPACT_PROCESS_PERSISTENT) { + if (start - lastCompactTime < mCompactThrottlePersistent) { + return; + } + } else if (pendingAction == COMPACT_PROCESS_BFGS) { + if (start - lastCompactTime < mCompactThrottleBFGS) { + return; + } } } - - if (pendingAction == COMPACT_PROCESS_SOME) { - action = mCompactActionSome; - } else { - action = mCompactActionFull; + switch (pendingAction) { + case COMPACT_PROCESS_SOME: + action = mCompactActionSome; + break; + // For the time being, treat these as equivalent. + case COMPACT_PROCESS_FULL: + case COMPACT_PROCESS_PERSISTENT: + case COMPACT_PROCESS_BFGS: + action = mCompactActionFull; + break; + default: + action = COMPACT_ACTION_NONE; + break; } - if (action.equals(COMPACT_ACTION_NONE)) { + if (COMPACT_ACTION_NONE.equals(action)) { return; } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index aa03de1115b23..c1b9a20d143d6 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1686,9 +1686,10 @@ public final class OomAdjuster { int changes = 0; - if (app.curAdj != app.setAdj) { - // don't compact during bootup - if (mAppCompact.useCompaction() && mService.mBooted) { + // don't compact during bootup + if (mAppCompact.useCompaction() && mService.mBooted) { + // Cached and prev/home compaction + if (app.curAdj != app.setAdj) { // Perform a minor compaction when a perceptible app becomes the prev/home app // Perform a major compaction when any app enters cached // reminder: here, setAdj is previous state, curAdj is upcoming state @@ -1702,7 +1703,23 @@ public final class OomAdjuster { && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) { mAppCompact.compactAppFull(app); } + } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE + && app.setAdj < ProcessList.FOREGROUND_APP_ADJ + // Because these can fire independent of oom_adj/procstate changes, we need + // to throttle the actual dispatch of these requests in addition to the + // processing of the requests. As a result, there is throttling both here + // and in AppCompactor. + && mAppCompact.shouldCompactPersistent(app, now)) { + mAppCompact.compactAppPersistent(app); + } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE + && app.getCurProcState() + == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE + && mAppCompact.shouldCompactBFGS(app, now)) { + mAppCompact.compactAppBfgs(app); } + } + + if (app.curAdj != app.setAdj) { ProcessList.setOomAdj(app.pid, app.uid, app.curAdj); if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) { String msg = "Set " + app.pid + " " + app.processName + " adj "