Loading services/core/java/com/android/server/am/ActivityManagerService.java +2 −0 Original line number Diff line number Diff line Loading @@ -8302,6 +8302,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized(this) { mConstants.dump(pw); mOomAdjuster.dumpCachedAppOptimizerSettings(pw); mOomAdjuster.dumpCacheOomRankerSettings(pw); pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); Loading Loading @@ -8722,6 +8723,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { mConstants.dump(pw); mOomAdjuster.dumpCachedAppOptimizerSettings(pw); mOomAdjuster.dumpCacheOomRankerSettings(pw); } } else if ("services".equals(cmd) || "s".equals(cmd)) { if (dumpClient) { Loading services/core/java/com/android/server/am/CacheOomRanker.java 0 → 100644 +308 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.am; import android.provider.DeviceConfig; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.concurrent.Executor; /** * Class to re-rank a number of the least recently used processes before they * are assigned oom adjust scores. */ public class CacheOomRanker { @VisibleForTesting static final String KEY_USE_OOM_RE_RANKING = "use_oom_re_ranking"; private static final boolean DEFAULT_USE_OOM_RE_RANKING = false; @VisibleForTesting static final String KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK = "oom_re_ranking_number_to_re_rank"; @VisibleForTesting static final int DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK = 8; @VisibleForTesting static final String KEY_OOM_RE_RANKING_LRU_WEIGHT = "oom_re_ranking_lru_weight"; @VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_LRU_WEIGHT = 0.35f; @VisibleForTesting static final String KEY_OOM_RE_RANKING_USES_WEIGHT = "oom_re_ranking_uses_weight"; @VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_USES_WEIGHT = 0.5f; @VisibleForTesting static final String KEY_OOM_RE_RANKING_RSS_WEIGHT = "oom_re_ranking_rss_weight"; @VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_RSS_WEIGHT = 0.15f; private static final Comparator<RankedProcessRecord> SCORED_PROCESS_RECORD_COMPARATOR = new ScoreComparator(); private static final Comparator<RankedProcessRecord> CACHE_USE_COMPARATOR = new CacheUseComparator(); private static final Comparator<RankedProcessRecord> LAST_RSS_COMPARATOR = new LastRssComparator(); private static final Comparator<RankedProcessRecord> LAST_ACTIVITY_TIME_COMPARATOR = new LastActivityTimeComparator(); private final Object mPhenotypeFlagLock = new Object(); @GuardedBy("mPhenotypeFlagLock") private boolean mUseOomReRanking = DEFAULT_USE_OOM_RE_RANKING; // Weight to apply to the LRU ordering. @GuardedBy("mPhenotypeFlagLock") @VisibleForTesting float mLruWeight = DEFAULT_OOM_RE_RANKING_LRU_WEIGHT; // Weight to apply to the ordering by number of times the process has been added to the cache. @GuardedBy("mPhenotypeFlagLock") @VisibleForTesting float mUsesWeight = DEFAULT_OOM_RE_RANKING_USES_WEIGHT; // Weight to apply to the ordering by RSS used by the processes. @GuardedBy("mPhenotypeFlagLock") @VisibleForTesting float mRssWeight = DEFAULT_OOM_RE_RANKING_RSS_WEIGHT; // Positions to replace in the lru list. @GuardedBy("mPhenotypeFlagLock") private int[] mLruPositions; // Processes to re-rank @GuardedBy("mPhenotypeFlagLock") private RankedProcessRecord[] mScoredProcessRecords; private final DeviceConfig.OnPropertiesChangedListener mOnFlagsChangedListener = new DeviceConfig.OnPropertiesChangedListener() { @Override public void onPropertiesChanged(DeviceConfig.Properties properties) { synchronized (mPhenotypeFlagLock) { for (String name : properties.getKeyset()) { if (KEY_USE_OOM_RE_RANKING.equals(name)) { updateUseOomReranking(); } else if (KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK.equals(name)) { updateNumberToReRank(); } else if (KEY_OOM_RE_RANKING_LRU_WEIGHT.equals(name)) { updateLruWeight(); } else if (KEY_OOM_RE_RANKING_USES_WEIGHT.equals(name)) { updateUsesWeight(); } else if (KEY_OOM_RE_RANKING_RSS_WEIGHT.equals(name)) { updateRssWeight(); } } } } }; /** Load settings from device config and register a listener for changes. */ public void init(Executor executor) { DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, executor, mOnFlagsChangedListener); synchronized (mPhenotypeFlagLock) { updateUseOomReranking(); updateNumberToReRank(); updateLruWeight(); updateUsesWeight(); updateRssWeight(); } } /** * Returns whether oom re-ranking is enabled. */ public boolean useOomReranking() { synchronized (mPhenotypeFlagLock) { return mUseOomReRanking; } } @GuardedBy("mPhenotypeFlagLock") private void updateUseOomReranking() { mUseOomReRanking = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_USE_OOM_RE_RANKING, DEFAULT_USE_OOM_RE_RANKING); } @GuardedBy("mPhenotypeFlagLock") private void updateNumberToReRank() { int previousNumberToReRank = getNumberToReRank(); int numberToReRank = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK, DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK); if (previousNumberToReRank != numberToReRank) { mScoredProcessRecords = new RankedProcessRecord[numberToReRank]; for (int i = 0; i < mScoredProcessRecords.length; ++i) { mScoredProcessRecords[i] = new RankedProcessRecord(); } mLruPositions = new int[numberToReRank]; } } @GuardedBy("mPhenotypeFlagLock") @VisibleForTesting int getNumberToReRank() { return mScoredProcessRecords == null ? 0 : mScoredProcessRecords.length; } @GuardedBy("mPhenotypeFlagLock") private void updateLruWeight() { mLruWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_OOM_RE_RANKING_LRU_WEIGHT, DEFAULT_OOM_RE_RANKING_LRU_WEIGHT); } @GuardedBy("mPhenotypeFlagLock") private void updateUsesWeight() { mUsesWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_OOM_RE_RANKING_USES_WEIGHT, DEFAULT_OOM_RE_RANKING_USES_WEIGHT); } @GuardedBy("mPhenotypeFlagLock") private void updateRssWeight() { mRssWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_OOM_RE_RANKING_RSS_WEIGHT, DEFAULT_OOM_RE_RANKING_RSS_WEIGHT); } /** * Re-rank the cached processes in the lru list with a weighted ordering * of lru, rss size and number of times the process has been put in the cache. */ public void reRankLruCachedApps(ProcessList processList) { float lruWeight; float usesWeight; float rssWeight; int[] lruPositions; RankedProcessRecord[] scoredProcessRecords; ArrayList<ProcessRecord> lruList = processList.mLruProcesses; synchronized (mPhenotypeFlagLock) { lruWeight = mLruWeight; usesWeight = mUsesWeight; rssWeight = mRssWeight; lruPositions = mLruPositions; scoredProcessRecords = mScoredProcessRecords; } // Don't re-rank if the class hasn't been initialized with defaults. if (lruPositions == null || scoredProcessRecords == null) { return; } // Collect the least recently used processes to re-rank, only rank cached // processes further down the list than mLruProcessServiceStart. int cachedProcessPos = 0; for (int i = 0; i < processList.mLruProcessServiceStart && cachedProcessPos < scoredProcessRecords.length; ++i) { ProcessRecord app = lruList.get(i); // Processes that will be assigned a cached oom adj score. if (!app.killedByAm && app.thread != null && app.curAdj >= ProcessList.UNKNOWN_ADJ) { scoredProcessRecords[cachedProcessPos].proc = app; scoredProcessRecords[cachedProcessPos].score = 0.0f; lruPositions[cachedProcessPos] = i; ++cachedProcessPos; } } // TODO maybe ensure a certain number above this in the cache before re-ranking. if (cachedProcessPos < scoredProcessRecords.length) { // Ignore we don't have enough processes to worry about re-ranking. return; } // Add scores for each of the weighted features we want to rank based on. if (lruWeight > 0.0f) { // This doesn't use the LRU list ordering as after the first re-ranking // that will no longer be lru. Arrays.sort(scoredProcessRecords, LAST_ACTIVITY_TIME_COMPARATOR); addToScore(scoredProcessRecords, lruWeight); } if (rssWeight > 0.0f) { Arrays.sort(scoredProcessRecords, LAST_RSS_COMPARATOR); addToScore(scoredProcessRecords, rssWeight); } if (usesWeight > 0.0f) { Arrays.sort(scoredProcessRecords, CACHE_USE_COMPARATOR); addToScore(scoredProcessRecords, usesWeight); } // Re-rank by the new combined score. Arrays.sort(scoredProcessRecords, SCORED_PROCESS_RECORD_COMPARATOR); if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) { boolean printedHeader = false; for (int i = 0; i < scoredProcessRecords.length; ++i) { if (scoredProcessRecords[i].proc.pid != lruList.get(lruPositions[i]).pid) { if (!printedHeader) { Slog.i(OomAdjuster.TAG, "reRankLruCachedApps"); printedHeader = true; } Slog.i(OomAdjuster.TAG, " newPos=" + lruPositions[i] + " " + scoredProcessRecords[i].proc); } } } for (int i = 0; i < scoredProcessRecords.length; ++i) { lruList.set(lruPositions[i], scoredProcessRecords[i].proc); scoredProcessRecords[i].proc = null; } } private static void addToScore(RankedProcessRecord[] scores, float weight) { for (int i = 1; i < scores.length; ++i) { scores[i].score += i * weight; } } void dump(PrintWriter pw) { pw.println("CacheOomRanker settings"); synchronized (mPhenotypeFlagLock) { pw.println(" " + KEY_USE_OOM_RE_RANKING + "=" + mUseOomReRanking); pw.println(" " + KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK + "=" + getNumberToReRank()); pw.println(" " + KEY_OOM_RE_RANKING_LRU_WEIGHT + "=" + mLruWeight); pw.println(" " + KEY_OOM_RE_RANKING_USES_WEIGHT + "=" + mUsesWeight); pw.println(" " + KEY_OOM_RE_RANKING_RSS_WEIGHT + "=" + mRssWeight); } } private static class ScoreComparator implements Comparator<RankedProcessRecord> { @Override public int compare(RankedProcessRecord o1, RankedProcessRecord o2) { return Float.compare(o1.score, o2.score); } } private static class LastActivityTimeComparator implements Comparator<RankedProcessRecord> { @Override public int compare(RankedProcessRecord o1, RankedProcessRecord o2) { return Long.compare(o1.proc.lastActivityTime, o2.proc.lastActivityTime); } } private static class CacheUseComparator implements Comparator<RankedProcessRecord> { @Override public int compare(RankedProcessRecord o1, RankedProcessRecord o2) { return Long.compare(o1.proc.getCacheOomRankerUseCount(), o2.proc.getCacheOomRankerUseCount()); } } private static class LastRssComparator implements Comparator<RankedProcessRecord> { @Override public int compare(RankedProcessRecord o1, RankedProcessRecord o2) { // High RSS first to match least recently used. return Long.compare(o2.proc.mLastRss, o1.proc.mLastRss); } } private static class RankedProcessRecord { public ProcessRecord proc; public float score; } } services/core/java/com/android/server/am/OomAdjuster.java +18 −1 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ import static com.android.server.am.AppProfiler.TAG_PSS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ApplicationExitInfo; import android.app.usage.UsageEvents; import android.compat.annotation.ChangeId; Loading Loading @@ -119,7 +120,7 @@ import java.util.Arrays; * All of the code required to compute proc states and oom_adj values. */ public final class OomAdjuster { private static final String TAG = "OomAdjuster"; static final String TAG = "OomAdjuster"; static final String OOM_ADJ_REASON_METHOD = "updateOomAdj"; static final String OOM_ADJ_REASON_NONE = OOM_ADJ_REASON_METHOD + "_meh"; static final String OOM_ADJ_REASON_ACTIVITY = OOM_ADJ_REASON_METHOD + "_activityChange"; Loading Loading @@ -169,6 +170,12 @@ public final class OomAdjuster { */ CachedAppOptimizer mCachedAppOptimizer; /** * Re-rank apps getting a cache oom adjustment from lru to weighted order * based on weighted scores for LRU, PSS and cache use count. */ CacheOomRanker mCacheOomRanker; ActivityManagerConstants mConstants; final long[] mTmpLong = new long[3]; Loading Loading @@ -331,6 +338,7 @@ public final class OomAdjuster { mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class); mConstants = mService.mConstants; mCachedAppOptimizer = new CachedAppOptimizer(mService); mCacheOomRanker = new CacheOomRanker(); mProcessGroupHandler = new Handler(adjusterThread.getLooper(), msg -> { final int pid = msg.arg1; Loading Loading @@ -361,6 +369,7 @@ public final class OomAdjuster { void initSettings() { mCachedAppOptimizer.init(); mCacheOomRanker.init(ActivityThread.currentApplication().getMainExecutor()); if (mService.mConstants.KEEP_WARMING_SERVICES.size() > 0) { final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); mService.mContext.registerReceiverForAllUsers(new BroadcastReceiver() { Loading Loading @@ -769,6 +778,9 @@ public final class OomAdjuster { } } if (mCacheOomRanker.useOomReranking()) { mCacheOomRanker.reRankLruCachedApps(mProcessList); } assignCachedAdjIfNecessary(mProcessList.mLruProcesses); if (computeClients) { // There won't be cycles if we didn't compute clients above. Loading Loading @@ -2774,6 +2786,11 @@ public final class OomAdjuster { mCachedAppOptimizer.dump(pw); } @GuardedBy("mService") void dumpCacheOomRankerSettings(PrintWriter pw) { mCacheOomRanker.dump(pw); } @GuardedBy("mService") void updateAppFreezeStateLocked(ProcessRecord app) { if (!mCachedAppOptimizer.useFreezer()) { Loading services/core/java/com/android/server/am/ProcessRecord.java +17 −1 Original line number Diff line number Diff line Loading @@ -360,6 +360,13 @@ class ProcessRecord implements WindowProcessListener { int mCachedProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; int mCachedSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND; // Approximates the usage count of the app, used for cache re-ranking by CacheOomRanker. // // Counts the number of times the process is re-added to the cache (i.e. setCached(false); // setCached(true)). This over counts, as setCached is sometimes reset while remaining in the // cache. However, this happens uniformly across processes, so ranking is not affected. private int mCacheOomRankerUseCount; boolean mReachable; // Whether or not this process is reachable from given process long mKillTime; // The timestamp in uptime when this process was killed. Loading Loading @@ -828,7 +835,12 @@ class ProcessRecord implements WindowProcessListener { } void setCached(boolean cached) { if (mCached != cached) { mCached = cached; if (cached) { ++mCacheOomRankerUseCount; } } } @Override Loading @@ -836,6 +848,10 @@ class ProcessRecord implements WindowProcessListener { return mCached; } int getCacheOomRankerUseCount() { return mCacheOomRankerUseCount; } boolean hasActivities() { return mWindowProcessController.hasActivities(); } Loading services/tests/mockingservicestests/AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -21,11 +21,13 @@ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/> <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/> <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/> <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" /> <uses-permission android:name="android.permission.HARDWARE_TEST"/> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="android.permission.MANAGE_APPOPS"/> <uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"/> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/> <!-- needed by MasterClearReceiverTest to display a system dialog --> <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/> Loading Loading
services/core/java/com/android/server/am/ActivityManagerService.java +2 −0 Original line number Diff line number Diff line Loading @@ -8302,6 +8302,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized(this) { mConstants.dump(pw); mOomAdjuster.dumpCachedAppOptimizerSettings(pw); mOomAdjuster.dumpCacheOomRankerSettings(pw); pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); Loading Loading @@ -8722,6 +8723,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { mConstants.dump(pw); mOomAdjuster.dumpCachedAppOptimizerSettings(pw); mOomAdjuster.dumpCacheOomRankerSettings(pw); } } else if ("services".equals(cmd) || "s".equals(cmd)) { if (dumpClient) { Loading
services/core/java/com/android/server/am/CacheOomRanker.java 0 → 100644 +308 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.am; import android.provider.DeviceConfig; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.concurrent.Executor; /** * Class to re-rank a number of the least recently used processes before they * are assigned oom adjust scores. */ public class CacheOomRanker { @VisibleForTesting static final String KEY_USE_OOM_RE_RANKING = "use_oom_re_ranking"; private static final boolean DEFAULT_USE_OOM_RE_RANKING = false; @VisibleForTesting static final String KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK = "oom_re_ranking_number_to_re_rank"; @VisibleForTesting static final int DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK = 8; @VisibleForTesting static final String KEY_OOM_RE_RANKING_LRU_WEIGHT = "oom_re_ranking_lru_weight"; @VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_LRU_WEIGHT = 0.35f; @VisibleForTesting static final String KEY_OOM_RE_RANKING_USES_WEIGHT = "oom_re_ranking_uses_weight"; @VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_USES_WEIGHT = 0.5f; @VisibleForTesting static final String KEY_OOM_RE_RANKING_RSS_WEIGHT = "oom_re_ranking_rss_weight"; @VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_RSS_WEIGHT = 0.15f; private static final Comparator<RankedProcessRecord> SCORED_PROCESS_RECORD_COMPARATOR = new ScoreComparator(); private static final Comparator<RankedProcessRecord> CACHE_USE_COMPARATOR = new CacheUseComparator(); private static final Comparator<RankedProcessRecord> LAST_RSS_COMPARATOR = new LastRssComparator(); private static final Comparator<RankedProcessRecord> LAST_ACTIVITY_TIME_COMPARATOR = new LastActivityTimeComparator(); private final Object mPhenotypeFlagLock = new Object(); @GuardedBy("mPhenotypeFlagLock") private boolean mUseOomReRanking = DEFAULT_USE_OOM_RE_RANKING; // Weight to apply to the LRU ordering. @GuardedBy("mPhenotypeFlagLock") @VisibleForTesting float mLruWeight = DEFAULT_OOM_RE_RANKING_LRU_WEIGHT; // Weight to apply to the ordering by number of times the process has been added to the cache. @GuardedBy("mPhenotypeFlagLock") @VisibleForTesting float mUsesWeight = DEFAULT_OOM_RE_RANKING_USES_WEIGHT; // Weight to apply to the ordering by RSS used by the processes. @GuardedBy("mPhenotypeFlagLock") @VisibleForTesting float mRssWeight = DEFAULT_OOM_RE_RANKING_RSS_WEIGHT; // Positions to replace in the lru list. @GuardedBy("mPhenotypeFlagLock") private int[] mLruPositions; // Processes to re-rank @GuardedBy("mPhenotypeFlagLock") private RankedProcessRecord[] mScoredProcessRecords; private final DeviceConfig.OnPropertiesChangedListener mOnFlagsChangedListener = new DeviceConfig.OnPropertiesChangedListener() { @Override public void onPropertiesChanged(DeviceConfig.Properties properties) { synchronized (mPhenotypeFlagLock) { for (String name : properties.getKeyset()) { if (KEY_USE_OOM_RE_RANKING.equals(name)) { updateUseOomReranking(); } else if (KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK.equals(name)) { updateNumberToReRank(); } else if (KEY_OOM_RE_RANKING_LRU_WEIGHT.equals(name)) { updateLruWeight(); } else if (KEY_OOM_RE_RANKING_USES_WEIGHT.equals(name)) { updateUsesWeight(); } else if (KEY_OOM_RE_RANKING_RSS_WEIGHT.equals(name)) { updateRssWeight(); } } } } }; /** Load settings from device config and register a listener for changes. */ public void init(Executor executor) { DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, executor, mOnFlagsChangedListener); synchronized (mPhenotypeFlagLock) { updateUseOomReranking(); updateNumberToReRank(); updateLruWeight(); updateUsesWeight(); updateRssWeight(); } } /** * Returns whether oom re-ranking is enabled. */ public boolean useOomReranking() { synchronized (mPhenotypeFlagLock) { return mUseOomReRanking; } } @GuardedBy("mPhenotypeFlagLock") private void updateUseOomReranking() { mUseOomReRanking = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_USE_OOM_RE_RANKING, DEFAULT_USE_OOM_RE_RANKING); } @GuardedBy("mPhenotypeFlagLock") private void updateNumberToReRank() { int previousNumberToReRank = getNumberToReRank(); int numberToReRank = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK, DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK); if (previousNumberToReRank != numberToReRank) { mScoredProcessRecords = new RankedProcessRecord[numberToReRank]; for (int i = 0; i < mScoredProcessRecords.length; ++i) { mScoredProcessRecords[i] = new RankedProcessRecord(); } mLruPositions = new int[numberToReRank]; } } @GuardedBy("mPhenotypeFlagLock") @VisibleForTesting int getNumberToReRank() { return mScoredProcessRecords == null ? 0 : mScoredProcessRecords.length; } @GuardedBy("mPhenotypeFlagLock") private void updateLruWeight() { mLruWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_OOM_RE_RANKING_LRU_WEIGHT, DEFAULT_OOM_RE_RANKING_LRU_WEIGHT); } @GuardedBy("mPhenotypeFlagLock") private void updateUsesWeight() { mUsesWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_OOM_RE_RANKING_USES_WEIGHT, DEFAULT_OOM_RE_RANKING_USES_WEIGHT); } @GuardedBy("mPhenotypeFlagLock") private void updateRssWeight() { mRssWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_OOM_RE_RANKING_RSS_WEIGHT, DEFAULT_OOM_RE_RANKING_RSS_WEIGHT); } /** * Re-rank the cached processes in the lru list with a weighted ordering * of lru, rss size and number of times the process has been put in the cache. */ public void reRankLruCachedApps(ProcessList processList) { float lruWeight; float usesWeight; float rssWeight; int[] lruPositions; RankedProcessRecord[] scoredProcessRecords; ArrayList<ProcessRecord> lruList = processList.mLruProcesses; synchronized (mPhenotypeFlagLock) { lruWeight = mLruWeight; usesWeight = mUsesWeight; rssWeight = mRssWeight; lruPositions = mLruPositions; scoredProcessRecords = mScoredProcessRecords; } // Don't re-rank if the class hasn't been initialized with defaults. if (lruPositions == null || scoredProcessRecords == null) { return; } // Collect the least recently used processes to re-rank, only rank cached // processes further down the list than mLruProcessServiceStart. int cachedProcessPos = 0; for (int i = 0; i < processList.mLruProcessServiceStart && cachedProcessPos < scoredProcessRecords.length; ++i) { ProcessRecord app = lruList.get(i); // Processes that will be assigned a cached oom adj score. if (!app.killedByAm && app.thread != null && app.curAdj >= ProcessList.UNKNOWN_ADJ) { scoredProcessRecords[cachedProcessPos].proc = app; scoredProcessRecords[cachedProcessPos].score = 0.0f; lruPositions[cachedProcessPos] = i; ++cachedProcessPos; } } // TODO maybe ensure a certain number above this in the cache before re-ranking. if (cachedProcessPos < scoredProcessRecords.length) { // Ignore we don't have enough processes to worry about re-ranking. return; } // Add scores for each of the weighted features we want to rank based on. if (lruWeight > 0.0f) { // This doesn't use the LRU list ordering as after the first re-ranking // that will no longer be lru. Arrays.sort(scoredProcessRecords, LAST_ACTIVITY_TIME_COMPARATOR); addToScore(scoredProcessRecords, lruWeight); } if (rssWeight > 0.0f) { Arrays.sort(scoredProcessRecords, LAST_RSS_COMPARATOR); addToScore(scoredProcessRecords, rssWeight); } if (usesWeight > 0.0f) { Arrays.sort(scoredProcessRecords, CACHE_USE_COMPARATOR); addToScore(scoredProcessRecords, usesWeight); } // Re-rank by the new combined score. Arrays.sort(scoredProcessRecords, SCORED_PROCESS_RECORD_COMPARATOR); if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) { boolean printedHeader = false; for (int i = 0; i < scoredProcessRecords.length; ++i) { if (scoredProcessRecords[i].proc.pid != lruList.get(lruPositions[i]).pid) { if (!printedHeader) { Slog.i(OomAdjuster.TAG, "reRankLruCachedApps"); printedHeader = true; } Slog.i(OomAdjuster.TAG, " newPos=" + lruPositions[i] + " " + scoredProcessRecords[i].proc); } } } for (int i = 0; i < scoredProcessRecords.length; ++i) { lruList.set(lruPositions[i], scoredProcessRecords[i].proc); scoredProcessRecords[i].proc = null; } } private static void addToScore(RankedProcessRecord[] scores, float weight) { for (int i = 1; i < scores.length; ++i) { scores[i].score += i * weight; } } void dump(PrintWriter pw) { pw.println("CacheOomRanker settings"); synchronized (mPhenotypeFlagLock) { pw.println(" " + KEY_USE_OOM_RE_RANKING + "=" + mUseOomReRanking); pw.println(" " + KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK + "=" + getNumberToReRank()); pw.println(" " + KEY_OOM_RE_RANKING_LRU_WEIGHT + "=" + mLruWeight); pw.println(" " + KEY_OOM_RE_RANKING_USES_WEIGHT + "=" + mUsesWeight); pw.println(" " + KEY_OOM_RE_RANKING_RSS_WEIGHT + "=" + mRssWeight); } } private static class ScoreComparator implements Comparator<RankedProcessRecord> { @Override public int compare(RankedProcessRecord o1, RankedProcessRecord o2) { return Float.compare(o1.score, o2.score); } } private static class LastActivityTimeComparator implements Comparator<RankedProcessRecord> { @Override public int compare(RankedProcessRecord o1, RankedProcessRecord o2) { return Long.compare(o1.proc.lastActivityTime, o2.proc.lastActivityTime); } } private static class CacheUseComparator implements Comparator<RankedProcessRecord> { @Override public int compare(RankedProcessRecord o1, RankedProcessRecord o2) { return Long.compare(o1.proc.getCacheOomRankerUseCount(), o2.proc.getCacheOomRankerUseCount()); } } private static class LastRssComparator implements Comparator<RankedProcessRecord> { @Override public int compare(RankedProcessRecord o1, RankedProcessRecord o2) { // High RSS first to match least recently used. return Long.compare(o2.proc.mLastRss, o1.proc.mLastRss); } } private static class RankedProcessRecord { public ProcessRecord proc; public float score; } }
services/core/java/com/android/server/am/OomAdjuster.java +18 −1 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ import static com.android.server.am.AppProfiler.TAG_PSS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ApplicationExitInfo; import android.app.usage.UsageEvents; import android.compat.annotation.ChangeId; Loading Loading @@ -119,7 +120,7 @@ import java.util.Arrays; * All of the code required to compute proc states and oom_adj values. */ public final class OomAdjuster { private static final String TAG = "OomAdjuster"; static final String TAG = "OomAdjuster"; static final String OOM_ADJ_REASON_METHOD = "updateOomAdj"; static final String OOM_ADJ_REASON_NONE = OOM_ADJ_REASON_METHOD + "_meh"; static final String OOM_ADJ_REASON_ACTIVITY = OOM_ADJ_REASON_METHOD + "_activityChange"; Loading Loading @@ -169,6 +170,12 @@ public final class OomAdjuster { */ CachedAppOptimizer mCachedAppOptimizer; /** * Re-rank apps getting a cache oom adjustment from lru to weighted order * based on weighted scores for LRU, PSS and cache use count. */ CacheOomRanker mCacheOomRanker; ActivityManagerConstants mConstants; final long[] mTmpLong = new long[3]; Loading Loading @@ -331,6 +338,7 @@ public final class OomAdjuster { mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class); mConstants = mService.mConstants; mCachedAppOptimizer = new CachedAppOptimizer(mService); mCacheOomRanker = new CacheOomRanker(); mProcessGroupHandler = new Handler(adjusterThread.getLooper(), msg -> { final int pid = msg.arg1; Loading Loading @@ -361,6 +369,7 @@ public final class OomAdjuster { void initSettings() { mCachedAppOptimizer.init(); mCacheOomRanker.init(ActivityThread.currentApplication().getMainExecutor()); if (mService.mConstants.KEEP_WARMING_SERVICES.size() > 0) { final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); mService.mContext.registerReceiverForAllUsers(new BroadcastReceiver() { Loading Loading @@ -769,6 +778,9 @@ public final class OomAdjuster { } } if (mCacheOomRanker.useOomReranking()) { mCacheOomRanker.reRankLruCachedApps(mProcessList); } assignCachedAdjIfNecessary(mProcessList.mLruProcesses); if (computeClients) { // There won't be cycles if we didn't compute clients above. Loading Loading @@ -2774,6 +2786,11 @@ public final class OomAdjuster { mCachedAppOptimizer.dump(pw); } @GuardedBy("mService") void dumpCacheOomRankerSettings(PrintWriter pw) { mCacheOomRanker.dump(pw); } @GuardedBy("mService") void updateAppFreezeStateLocked(ProcessRecord app) { if (!mCachedAppOptimizer.useFreezer()) { Loading
services/core/java/com/android/server/am/ProcessRecord.java +17 −1 Original line number Diff line number Diff line Loading @@ -360,6 +360,13 @@ class ProcessRecord implements WindowProcessListener { int mCachedProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; int mCachedSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND; // Approximates the usage count of the app, used for cache re-ranking by CacheOomRanker. // // Counts the number of times the process is re-added to the cache (i.e. setCached(false); // setCached(true)). This over counts, as setCached is sometimes reset while remaining in the // cache. However, this happens uniformly across processes, so ranking is not affected. private int mCacheOomRankerUseCount; boolean mReachable; // Whether or not this process is reachable from given process long mKillTime; // The timestamp in uptime when this process was killed. Loading Loading @@ -828,7 +835,12 @@ class ProcessRecord implements WindowProcessListener { } void setCached(boolean cached) { if (mCached != cached) { mCached = cached; if (cached) { ++mCacheOomRankerUseCount; } } } @Override Loading @@ -836,6 +848,10 @@ class ProcessRecord implements WindowProcessListener { return mCached; } int getCacheOomRankerUseCount() { return mCacheOomRankerUseCount; } boolean hasActivities() { return mWindowProcessController.hasActivities(); } Loading
services/tests/mockingservicestests/AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -21,11 +21,13 @@ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/> <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/> <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/> <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" /> <uses-permission android:name="android.permission.HARDWARE_TEST"/> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="android.permission.MANAGE_APPOPS"/> <uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"/> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/> <!-- needed by MasterClearReceiverTest to display a system dialog --> <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/> Loading