diff options
| author | 2023-08-03 14:40:04 -0700 | |
|---|---|---|
| committer | 2023-08-03 14:42:32 -0700 | |
| commit | 4b776e47ce801dedc0bb4d10fabea9c76c556022 (patch) | |
| tree | 32e73a44040b021f0be890babe6f57c9127004ce | |
| parent | 13d5c914100cc799d9363f465e81ce394b49d223 (diff) | |
Revert "[1/n] OomAdjuster implementation correctness and efficiency overhaul"
This reverts commit 87ccf4197790b9ae5fc17353dafb12622cdec138.
Reason for revert: b/294181870
Bug: 294181870
Test: Treehugger
Change-Id: I40d38b76d77f5065c271f1a6bc0f909a5d4d56d5
11 files changed, 518 insertions, 2097 deletions
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index da2588b12054..73e827249569 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -6434,7 +6434,6 @@ public final class ActiveServices { } updateServiceConnectionActivitiesLocked(psr); psr.removeAllConnections(); - psr.removeAllSdkSandboxConnections(); psr.mAllowlistManager = false; diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index c20f0aa4a62a..89d8c7756b44 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -22,7 +22,6 @@ import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_NONE; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK; import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY; import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY; -import static com.android.server.am.BroadcastConstants.getDeviceConfigBoolean; import android.annotation.NonNull; import android.app.ActivityThread; @@ -155,11 +154,6 @@ final class ActivityManagerConstants extends ContentObserver { static final String KEY_TIERED_CACHED_ADJ_DECAY_TIME = "tiered_cached_adj_decay_time"; static final String KEY_USE_MODERN_TRIM = "use_modern_trim"; - /** - * Whether or not to enable the new oom adjuster implementation. - */ - static final String KEY_ENABLE_NEW_OOMADJ = "enable_new_oom_adj"; - private static final int DEFAULT_MAX_CACHED_PROCESSES = 1024; private static final boolean DEFAULT_PRIORITIZE_ALARM_BROADCASTS = true; private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000; @@ -223,11 +217,6 @@ final class ActivityManagerConstants extends ContentObserver { private static final boolean DEFAULT_USE_MODERN_TRIM = true; /** - * The default value to {@link #KEY_ENABLE_NEW_OOMADJ}. - */ - private static final boolean DEFAULT_ENABLE_NEW_OOM_ADJ = false; - - /** * Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED} */ private static final int @@ -1063,9 +1052,6 @@ final class ActivityManagerConstants extends ContentObserver { /** @see #KEY_USE_MODERN_TRIM */ public boolean USE_MODERN_TRIM = DEFAULT_USE_MODERN_TRIM; - /** @see #KEY_ENABLE_NEW_OOMADJ */ - public boolean ENABLE_NEW_OOMADJ = DEFAULT_ENABLE_NEW_OOM_ADJ; - /** * Indicates whether PSS profiling in AppProfiler is disabled or not. */ @@ -1335,7 +1321,6 @@ final class ActivityManagerConstants extends ContentObserver { CUR_TRIM_EMPTY_PROCESSES = rawMaxEmptyProcesses / 2; CUR_TRIM_CACHED_PROCESSES = (Integer.min(CUR_MAX_CACHED_PROCESSES, MAX_CACHED_PROCESSES) - rawMaxEmptyProcesses) / 3; - loadNativeBootDeviceConfigConstants(); mDefaultDisableAppProfilerPssProfiling = context.getResources().getBoolean( R.bool.config_am_disablePssProfiling); APP_PROFILER_PSS_PROFILING_DISABLED = mDefaultDisableAppProfilerPssProfiling; @@ -1378,11 +1363,6 @@ final class ActivityManagerConstants extends ContentObserver { DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS)); } - private void loadNativeBootDeviceConfigConstants() { - ENABLE_NEW_OOMADJ = getDeviceConfigBoolean(KEY_ENABLE_NEW_OOMADJ, - DEFAULT_ENABLE_NEW_OOM_ADJ); - } - public void setOverrideMaxCachedProcesses(int value) { mOverrideMaxCachedProcesses = value; updateMaxCachedProcesses(); @@ -2033,13 +2013,6 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_USE_MODERN_TRIM); } - private void updateEnableNewOomAdj() { - ENABLE_NEW_OOMADJ = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, - KEY_ENABLE_NEW_OOMADJ, - DEFAULT_ENABLE_NEW_OOM_ADJ); - } - private void updateFGSPermissionEnforcementFlagsIfNecessary(@NonNull String name) { ForegroundServiceTypePolicy.getDefaultPolicy() .updatePermissionEnforcementFlagIfNecessary(name); @@ -2236,9 +2209,6 @@ final class ActivityManagerConstants extends ContentObserver { pw.print(" "); pw.print(KEY_TIERED_CACHED_ADJ_DECAY_TIME); pw.print("="); pw.println(TIERED_CACHED_ADJ_DECAY_TIME); - pw.print(" "); pw.print(KEY_ENABLE_NEW_OOMADJ); - pw.print("="); pw.println(ENABLE_NEW_OOMADJ); - pw.print(" "); pw.print(KEY_DISABLE_APP_PROFILER_PSS_PROFILING); pw.print("="); pw.println(APP_PROFILER_PSS_PROFILING_DISABLED); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c1f2f6731e43..a0fae26fcac1 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2029,7 +2029,6 @@ public class ActivityManagerService extends IActivityManager.Stub app.makeActive(mSystemThread.getApplicationThread(), mProcessStats); app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_SYSTEM); addPidLocked(app); - mOomAdjuster.onProcessBeginLocked(app); updateLruProcessLocked(app, false, null); updateOomAdjLocked(OOM_ADJ_REASON_SYSTEM_INIT); } @@ -2423,9 +2422,7 @@ public class ActivityManagerService extends IActivityManager.Stub mProcessList.init(this, activeUids, mPlatformCompat); mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(), null); mPhantomProcessList = new PhantomProcessList(this); - mOomAdjuster = mConstants.ENABLE_NEW_OOMADJ - ? new OomAdjusterModernImpl(this, mProcessList, activeUids, handlerThread) - : new OomAdjuster(this, mProcessList, activeUids, handlerThread); + mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids, handlerThread); mIntentFirewall = null; mProcessStats = new ProcessStatsService(this, mContext.getCacheDir()); @@ -2486,9 +2483,7 @@ public class ActivityManagerService extends IActivityManager.Stub mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(), new LowMemDetector(this)); mPhantomProcessList = new PhantomProcessList(this); - mOomAdjuster = mConstants.ENABLE_NEW_OOMADJ - ? new OomAdjusterModernImpl(this, mProcessList, activeUids) - : new OomAdjuster(this, mProcessList, activeUids); + mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids); // Broadcast policy parameters final BroadcastConstants foreConstants = new BroadcastConstants( @@ -4600,7 +4595,6 @@ public class ActivityManagerService extends IActivityManager.Stub EventLogTags.writeAmProcBound(app.userId, pid, app.processName); synchronized (mProcLock) { - mOomAdjuster.onProcessBeginLocked(app); mOomAdjuster.setAttachingProcessStatesLSP(app); clearProcessForegroundLocked(app); app.setDebugging(false); @@ -6986,7 +6980,6 @@ public class ActivityManagerService extends IActivityManager.Stub sdkSandboxClientAppPackage, new HostingRecord(HostingRecord.HOSTING_TYPE_ADDED_APPLICATION, customProcess != null ? customProcess : info.processName)); - mOomAdjuster.onProcessBeginLocked(app); updateLruProcessLocked(app, false, null); updateOomAdjLocked(app, OOM_ADJ_REASON_PROCESS_BEGIN); } diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java index 2fff79b3fb26..8c1fd516028e 100644 --- a/services/core/java/com/android/server/am/BroadcastConstants.java +++ b/services/core/java/com/android/server/am/BroadcastConstants.java @@ -373,7 +373,7 @@ public class BroadcastConstants { * Return the {@link SystemProperty} name for the given key in our * {@link DeviceConfig} namespace. */ - private static @NonNull String propertyFor(@NonNull String key) { + private @NonNull String propertyFor(@NonNull String key) { return "persist.device_config." + NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT + "." + key; } @@ -382,11 +382,11 @@ public class BroadcastConstants { * {@link DeviceConfig} namespace, but with a different prefix that can be * used to locally override the {@link DeviceConfig} value. */ - private static @NonNull String propertyOverrideFor(@NonNull String key) { + private @NonNull String propertyOverrideFor(@NonNull String key) { return "persist.sys." + NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT + "." + key; } - static boolean getDeviceConfigBoolean(@NonNull String key, boolean def) { + private boolean getDeviceConfigBoolean(@NonNull String key, boolean def) { return SystemProperties.getBoolean(propertyOverrideFor(key), SystemProperties.getBoolean(propertyFor(key), def)); } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 1f9e89e30782..459c6ff3504a 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -41,7 +41,6 @@ import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI; import static android.app.ActivityManager.PROCESS_STATE_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND; -import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ALLOWLIST; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BACKUP; @@ -125,7 +124,6 @@ import static com.android.server.am.ProcessList.UNKNOWN_ADJ; import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal.OomAdjReason; @@ -371,21 +369,20 @@ public class OomAdjuster { */ private final Handler mProcessGroupHandler; - protected final int[] mTmpSchedGroup = new int[1]; + private final int[] mTmpSchedGroup = new int[1]; - final ActivityManagerService mService; - final ProcessList mProcessList; - final ActivityManagerGlobalLock mProcLock; + private final ActivityManagerService mService; + private final ProcessList mProcessList; + private final ActivityManagerGlobalLock mProcLock; private final int mNumSlots; - protected final ArrayList<ProcessRecord> mTmpProcessList = new ArrayList<ProcessRecord>(); - protected final ArrayList<ProcessRecord> mTmpProcessList2 = new ArrayList<ProcessRecord>(); - protected final ArrayList<UidRecord> mTmpBecameIdle = new ArrayList<UidRecord>(); - protected final ActiveUids mTmpUidRecords; - protected final ArrayDeque<ProcessRecord> mTmpQueue; - protected final ArraySet<ProcessRecord> mTmpProcessSet = new ArraySet<>(); - protected final ArraySet<ProcessRecord> mPendingProcessSet = new ArraySet<>(); - protected final ArraySet<ProcessRecord> mProcessesInCycle = new ArraySet<>(); + private final ArrayList<ProcessRecord> mTmpProcessList = new ArrayList<ProcessRecord>(); + private final ArrayList<UidRecord> mTmpBecameIdle = new ArrayList<UidRecord>(); + private final ActiveUids mTmpUidRecords; + private final ArrayDeque<ProcessRecord> mTmpQueue; + private final ArraySet<ProcessRecord> mTmpProcessSet = new ArraySet<>(); + private final ArraySet<ProcessRecord> mPendingProcessSet = new ArraySet<>(); + private final ArraySet<ProcessRecord> mProcessesInCycle = new ArraySet<>(); /** * Flag to mark if there is an ongoing oomAdjUpdate: potentially the oomAdjUpdate @@ -415,7 +412,7 @@ public class OomAdjuster { this(service, processList, activeUids, createAdjusterThread()); } - static ServiceThread createAdjusterThread() { + private static ServiceThread createAdjusterThread() { // The process group is usually critical to the response time of foreground app, so the // setter should apply it as soon as possible. final ServiceThread adjusterThread = @@ -535,7 +532,7 @@ public class OomAdjuster { mPendingProcessSet.remove(app); mProcessesInCycle.clear(); - computeOomAdjLSP(app, cachedAdj, topApp, false, now, false, true, oomAdjReason, true); + computeOomAdjLSP(app, cachedAdj, topApp, false, now, false, true); if (!mProcessesInCycle.isEmpty()) { // We can't use the score here if there is a cycle, abort. for (int i = mProcessesInCycle.size() - 1; i >= 0; i--) { @@ -553,7 +550,7 @@ public class OomAdjuster { && (uidRec.getSetProcState() != uidRec.getCurProcState() || uidRec.getSetCapability() != uidRec.getCurCapability() || uidRec.isSetAllowListed() != uidRec.isCurAllowListed())) { - final ActiveUids uids = mTmpUidRecords; + ActiveUids uids = mTmpUidRecords; uids.clear(); uids.put(uidRec.getUid(), uidRec); updateUidsLSP(uids, SystemClock.elapsedRealtime()); @@ -636,20 +633,19 @@ public class OomAdjuster { } @GuardedBy({"mService", "mProcLock"}) - protected boolean performUpdateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) { + private boolean performUpdateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) { final ProcessRecord topApp = mService.getTopApp(); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason)); mService.mOomAdjProfiler.oomAdjStarted(); mAdjSeq++; + // Firstly, try to see if the importance of itself gets changed final ProcessStateRecord state = app.mState; final boolean wasCached = state.isCached(); final int oldAdj = state.getCurRawAdj(); final int cachedAdj = oldAdj >= CACHED_APP_MIN_ADJ ? oldAdj : UNKNOWN_ADJ; - - // Firstly, try to see if the importance of itself gets changed final boolean wasBackground = ActivityManager.isProcStateBackground( state.getSetProcState()); final int oldCap = state.getSetCapability(); @@ -697,6 +693,8 @@ public class OomAdjuster { mPendingProcessSet.clear(); if (!containsCycle) { + // Reset the flag + state.setReachable(false); // Remove this app from the return list because we've done the computation on it. processes.remove(app); } @@ -720,13 +718,8 @@ public class OomAdjuster { return true; } - /** - * Collect the reachable processes from the given {@code apps}, the result will be - * returned in the given {@code processes}, which will include the processes from - * the given {@code apps}. - */ @GuardedBy("mService") - protected boolean collectReachableProcessesLocked(ArraySet<ProcessRecord> apps, + private boolean collectReachableProcessesLocked(ArraySet<ProcessRecord> apps, ArrayList<ProcessRecord> processes, ActiveUids uids) { final ArrayDeque<ProcessRecord> queue = mTmpQueue; queue.clear(); @@ -831,15 +824,11 @@ public class OomAdjuster { if (size > 0) { // Reverse the process list, since the updateOomAdjInnerLSP scans from the end of it. for (int l = 0, r = size - 1; l < r; l++, r--) { - final ProcessRecord t = processes.get(l); - final ProcessRecord u = processes.get(r); - t.mState.setReachable(false); - u.mState.setReachable(false); - processes.set(l, u); + ProcessRecord t = processes.get(l); + processes.set(l, processes.get(r)); processes.set(r, t); } } - return containsCycle; } @@ -939,18 +928,24 @@ public class OomAdjuster { * Update OomAdj for all processes within the given list (could be partial), or the whole LRU * list if the given list is null; when it's partial update, each process's client proc won't * get evaluated recursively here. - * - * <p>Note: If the given {@code processes} is not null, the expectation to it is, the caller - * must have called {@link collectReachableProcessesLocked} on it. */ @GuardedBy({"mService", "mProcLock"}) - protected void updateOomAdjInnerLSP(@OomAdjReason int oomAdjReason, final ProcessRecord topApp, + private void updateOomAdjInnerLSP(@OomAdjReason int oomAdjReason, final ProcessRecord topApp, ArrayList<ProcessRecord> processes, ActiveUids uids, boolean potentialCycles, boolean startProfiling) { + if (startProfiling) { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason)); + mService.mOomAdjProfiler.oomAdjStarted(); + } + final long now = SystemClock.uptimeMillis(); + final long nowElapsed = SystemClock.elapsedRealtime(); + final long oldTime = now - mConstants.mMaxEmptyTimeMillis; final boolean fullUpdate = processes == null; - final ArrayList<ProcessRecord> activeProcesses = fullUpdate - ? mProcessList.getLruProcessesLOSP() : processes; ActiveUids activeUids = uids; + ArrayList<ProcessRecord> activeProcesses = fullUpdate ? mProcessList.getLruProcessesLOSP() + : processes; + final int numProc = activeProcesses.size(); + if (activeUids == null) { final int numUids = mActiveUids.size(); activeUids = mTmpUidRecords; @@ -961,14 +956,14 @@ public class OomAdjuster { } } - if (startProfiling) { - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason)); - mService.mOomAdjProfiler.oomAdjStarted(); + // Reset state in all uid records. + for (int i = activeUids.size() - 1; i >= 0; i--) { + final UidRecord uidRec = activeUids.valueAt(i); + if (DEBUG_UID_OBSERVERS) { + Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec); + } + uidRec.reset(); } - final long now = SystemClock.uptimeMillis(); - final long nowElapsed = SystemClock.elapsedRealtime(); - final long oldTime = now - mConstants.mMaxEmptyTimeMillis; - final int numProc = activeProcesses.size(); mAdjSeq++; if (fullUpdate) { @@ -976,9 +971,6 @@ public class OomAdjuster { mNewNumAServiceProcs = 0; } - // Reset state in all uid records. - resetUidRecordsLsp(activeUids); - boolean retryCycles = false; boolean computeClients = fullUpdate || potentialCycles; @@ -1004,9 +996,8 @@ public class OomAdjuster { if (!app.isKilledByAm() && app.getThread() != null) { state.setProcStateChanged(false); app.mOptRecord.setLastOomAdjChangeReason(oomAdjReason); - // It won't enter cycle if not computing clients. computeOomAdjLSP(app, UNKNOWN_ADJ, topApp, fullUpdate, now, false, - computeClients, oomAdjReason, true); + computeClients); // It won't enter cycle if not computing clients. // if any app encountered a cycle, we need to perform an additional loop later retryCycles |= state.containsCycle(); // Keep the completedAdjSeq to up to date. @@ -1043,7 +1034,7 @@ public class OomAdjuster { final ProcessStateRecord state = app.mState; if (!app.isKilledByAm() && app.getThread() != null && state.containsCycle()) { if (computeOomAdjLSP(app, UNKNOWN_ADJ, topApp, true, now, - true, true, oomAdjReason, true)) { + true, true)) { retryCycles = true; } } @@ -1054,33 +1045,10 @@ public class OomAdjuster { assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP()); - postUpdateOomAdjInnerLSP(oomAdjReason, activeUids, now, nowElapsed, oldTime); - - if (startProfiling) { - mService.mOomAdjProfiler.oomAdjEnded(); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - } - } - - @GuardedBy({"mService", "mProcLock"}) - private void resetUidRecordsLsp(@NonNull ActiveUids activeUids) { - // Reset state in all uid records. - for (int i = activeUids.size() - 1; i >= 0; i--) { - final UidRecord uidRec = activeUids.valueAt(i); - if (DEBUG_UID_OBSERVERS) { - Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec); - } - uidRec.reset(); - } - } - - @GuardedBy({"mService", "mProcLock"}) - protected void postUpdateOomAdjInnerLSP(@OomAdjReason int oomAdjReason, ActiveUids activeUids, - long now, long nowElapsed, long oldTime) { mNumNonCachedProcs = 0; mNumCachedHiddenProcs = 0; - final boolean allChanged = updateAndTrimProcessLSP(now, nowElapsed, oldTime, activeUids, + boolean allChanged = updateAndTrimProcessLSP(now, nowElapsed, oldTime, activeUids, oomAdjReason); mNumServiceProcs = mNewNumServiceProcs; @@ -1117,10 +1085,14 @@ public class OomAdjuster { Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms"); } } + if (startProfiling) { + mService.mOomAdjProfiler.oomAdjEnded(); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + } } @GuardedBy({"mService", "mProcLock"}) - protected void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) { + private void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) { final int numLru = lruList.size(); if (mConstants.USE_TIERED_CACHED_ADJ) { final long now = SystemClock.uptimeMillis(); @@ -1441,7 +1413,7 @@ public class OomAdjuster { } @GuardedBy({"mService", "mProcLock"}) - protected void updateAppUidRecIfNecessaryLSP(final ProcessRecord app) { + private void updateAppUidRecIfNecessaryLSP(final ProcessRecord app) { if (!app.isKilledByAm() && app.getThread() != null) { if (app.isolated && app.mServices.numberOfRunningServices() <= 0 && app.getIsolatedEntryPoint() == null) { @@ -1470,7 +1442,7 @@ public class OomAdjuster { } @GuardedBy({"mService", "mProcLock"}) - protected void updateUidsLSP(ActiveUids activeUids, final long nowElapsed) { + private void updateUidsLSP(ActiveUids activeUids, final long nowElapsed) { // This compares previously set procstate to the current procstate in regards to whether // or not the app's network access will be blocked. So, this needs to be called before // we update the UidRecord's procstate by calling {@link UidRecord#setSetProcState}. @@ -1608,7 +1580,7 @@ public class OomAdjuster { return true; } - protected final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback = + private final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback = new ComputeOomAdjWindowCallback(); /** These methods are called inline during computeOomAdjLSP(), on the same thread */ @@ -1747,30 +1719,24 @@ public class OomAdjuster { } @GuardedBy({"mService", "mProcLock"}) - protected boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj, + private boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj, ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval, - boolean computeClients, int oomAdjReason, boolean couldRecurse) { + boolean computeClients) { final ProcessStateRecord state = app.mState; - if (couldRecurse) { - if (mAdjSeq == state.getAdjSeq()) { - if (state.getAdjSeq() == state.getCompletedAdjSeq()) { - // This adjustment has already been computed successfully. - return false; - } else { - // The process is being computed, so there is a cycle. We cannot - // rely on this process's state. - state.setContainsCycle(true); - mProcessesInCycle.add(app); + if (mAdjSeq == state.getAdjSeq()) { + if (state.getAdjSeq() == state.getCompletedAdjSeq()) { + // This adjustment has already been computed successfully. + return false; + } else { + // The process is being computed, so there is a cycle. We cannot + // rely on this process's state. + state.setContainsCycle(true); + mProcessesInCycle.add(app); - return false; - } + return false; } } - int prevAppAdj = getInitialAdj(app); - int prevProcState = getInitialProcState(app); - int prevCapability = getInitialCapability(app); - if (app.getThread() == null) { state.setAdjSeq(mAdjSeq); state.setCurrentSchedulingGroup(SCHED_GROUP_BACKGROUND); @@ -1779,8 +1745,6 @@ public class OomAdjuster { state.setCurRawAdj(CACHED_APP_MAX_ADJ); state.setCompletedAdjSeq(state.getAdjSeq()); state.setCurCapability(PROCESS_CAPABILITY_NONE); - onProcessStateChanged(app, prevProcState); - onProcessOomAdjChanged(app, prevAppAdj); return false; } @@ -1789,7 +1753,7 @@ public class OomAdjuster { state.setAdjTarget(null); state.setEmpty(false); state.setCached(false); - if (!couldRecurse || !cycleReEval) { + if (!cycleReEval) { // Don't reset this flag when doing cycles re-evaluation. state.setNoKillOnBgRestrictedAndIdle(false); // If this UID is currently allowlisted, it should not be frozen. @@ -1800,6 +1764,9 @@ public class OomAdjuster { final int appUid = app.info.uid; final int logUid = mService.mCurOomAdjUid; + int prevAppAdj = state.getCurAdj(); + int prevProcState = state.getCurProcState(); + int prevCapability = state.getCurCapability(); final ProcessServiceRecord psr = app.mServices; if (state.getMaxAdj() <= FOREGROUND_APP_ADJ) { @@ -1845,8 +1812,6 @@ public class OomAdjuster { state.setCurRawProcState(state.getCurProcState()); state.setCurAdj(state.getMaxAdj()); state.setCompletedAdjSeq(state.getAdjSeq()); - onProcessStateChanged(app, prevProcState); - onProcessOomAdjChanged(app, prevAppAdj); // if curAdj is less than prevAppAdj, then this process was promoted return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState; } @@ -1860,7 +1825,7 @@ public class OomAdjuster { int adj; int schedGroup; int procState; - int capability = cycleReEval ? getInitialCapability(app) : 0; + int capability = cycleReEval ? app.mState.getCurCapability() : 0; boolean foregroundActivities = false; boolean hasVisibleActivities = false; @@ -1939,7 +1904,7 @@ public class OomAdjuster { // value that the caller wants us to. adj = cachedAdj; procState = PROCESS_STATE_CACHED_EMPTY; - if (!couldRecurse || !state.containsCycle()) { + if (!state.containsCycle()) { state.setCached(true); state.setEmpty(true); state.setAdjType("cch-empty"); @@ -2204,10 +2169,8 @@ public class OomAdjuster { } } - state.setCurBoundByNonBgRestrictedApp(getInitialIsCurBoundByNonBgRestrictedApp(app)); - - state.setScheduleLikeTopApp(false); - + boolean boundByNonBgRestricted = state.isCurBoundByNonBgRestrictedApp(); + boolean scheduleLikeTopApp = false; for (int is = psr.numberOfRunningServices() - 1; is >= 0 && (adj > FOREGROUND_APP_ADJ || schedGroup == SCHED_GROUP_BACKGROUND @@ -2280,18 +2243,6 @@ public class OomAdjuster { } } - if (!couldRecurse) { - // We're entering recursive functions below, if we're told it's not a recursive - // loop, abort here. - continue; - } - - - state.setCurRawAdj(adj); - state.setCurRawProcState(procState); - state.setCurrentSchedulingGroup(schedGroup); - state.setCurCapability(capability); - ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = s.getConnections(); for (int conni = serviceConnections.size() - 1; conni >= 0 && (adj > FOREGROUND_APP_ADJ @@ -2312,13 +2263,335 @@ public class OomAdjuster { continue; } - computeServiceHostOomAdjLSP(cr, app, cr.binding.client, now, topApp, doingAll, - cycleReEval, computeClients, oomAdjReason, cachedAdj, true); + boolean trackedProcState = false; + + ProcessRecord client = cr.binding.client; + if (app.isSdkSandbox && cr.binding.attributedClient != null) { + // For SDK sandboxes, use the attributed client (eg the app that + // requested the sandbox) + client = cr.binding.attributedClient; + } + final ProcessStateRecord cstate = client.mState; + if (computeClients) { + computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, + cycleReEval, true); + } else { + cstate.setCurRawAdj(cstate.getCurAdj()); + cstate.setCurRawProcState(cstate.getCurProcState()); + } + + int clientAdj = cstate.getCurRawAdj(); + int clientProcState = cstate.getCurRawProcState(); + + final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP; + + boundByNonBgRestricted |= cstate.isCurBoundByNonBgRestrictedApp() + || clientProcState <= PROCESS_STATE_BOUND_TOP + || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE + && !cstate.isBackgroundRestricted()); + + if (client.mOptRecord.shouldNotFreeze()) { + // Propagate the shouldNotFreeze flag down the bindings. + app.mOptRecord.setShouldNotFreeze(true); + } + + // We always propagate PROCESS_CAPABILITY_BFSL over bindings here, + // but, right before actually setting it to the process, + // we check the final procstate, and remove it if the procsate is below BFGS. + capability |= getBfslCapabilityFromClient(client); + + if (cr.notHasFlag(Context.BIND_WAIVE_PRIORITY)) { + if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) { + capability |= cstate.getCurCapability(); + } + + // If an app has network capability by default + // (by having procstate <= BFGS), then the apps it binds to will get + // elevated to a high enough procstate anyway to get network unless they + // request otherwise, so don't propagate the network capability by default + // in this case unless they explicitly request it. + if ((cstate.getCurCapability() + & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0) { + if (clientProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { + // This is used to grant network access to Expedited Jobs. + if (cr.hasFlag(Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS)) { + capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; + } + } else { + capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; + } + } + if ((cstate.getCurCapability() + & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0) { + if (clientProcState <= PROCESS_STATE_IMPORTANT_FOREGROUND) { + // This is used to grant network access to User Initiated Jobs. + if (cr.hasFlag(Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS)) { + capability |= PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK; + } + } + } + + if (shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) { + continue; + } - adj = state.getCurRawAdj(); - procState = state.getCurRawProcState(); - schedGroup = state.getCurrentSchedulingGroup(); - capability = state.getCurCapability(); + if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) { + // If the other app is cached for any reason, for purposes here + // we are going to consider it empty. The specific cached state + // doesn't propagate except under certain conditions. + clientProcState = PROCESS_STATE_CACHED_EMPTY; + } + String adjType = null; + if (cr.hasFlag(Context.BIND_ALLOW_OOM_MANAGEMENT)) { + // Similar to BIND_WAIVE_PRIORITY, keep it unfrozen. + if (clientAdj < CACHED_APP_MIN_ADJ) { + app.mOptRecord.setShouldNotFreeze(true); + } + // Not doing bind OOM management, so treat + // this guy more like a started service. + if (state.hasShownUi() && !state.getCachedIsHomeProcess()) { + // If this process has shown some UI, let it immediately + // go to the LRU list because it may be pretty heavy with + // UI stuff. We'll tag it with a label just to help + // debug and understand what is going on. + if (adj > clientAdj) { + adjType = "cch-bound-ui-services"; + } + state.setCached(false); + clientAdj = adj; + clientProcState = procState; + } else { + if (now >= (s.lastActivity + + mConstants.MAX_SERVICE_INACTIVITY)) { + // This service has not seen activity within + // recent memory, so allow it to drop to the + // LRU list if there is no other reason to keep + // it around. We'll also tag it with a label just + // to help debug and undertand what is going on. + if (adj > clientAdj) { + adjType = "cch-bound-services"; + } + clientAdj = adj; + } + } + } + if (adj > clientAdj) { + // If this process has recently shown UI, and + // the process that is binding to it is less + // important than being visible, then we don't + // care about the binding as much as we care + // about letting this process get into the LRU + // list to be killed and restarted if needed for + // memory. + if (state.hasShownUi() && !state.getCachedIsHomeProcess() + && clientAdj > PERCEPTIBLE_APP_ADJ) { + if (adj >= CACHED_APP_MIN_ADJ) { + adjType = "cch-bound-ui-services"; + } + } else { + int newAdj; + int lbAdj = VISIBLE_APP_ADJ; // lower bound of adj. + if (cr.hasFlag(Context.BIND_ABOVE_CLIENT + | Context.BIND_IMPORTANT)) { + if (clientAdj >= PERSISTENT_SERVICE_ADJ) { + newAdj = clientAdj; + } else { + // make this service persistent + newAdj = PERSISTENT_SERVICE_ADJ; + schedGroup = SCHED_GROUP_DEFAULT; + procState = ActivityManager.PROCESS_STATE_PERSISTENT; + cr.trackProcState(procState, mAdjSeq); + trackedProcState = true; + } + } else if (cr.hasFlag(Context.BIND_NOT_PERCEPTIBLE) + && clientAdj <= PERCEPTIBLE_APP_ADJ + && adj >= (lbAdj = PERCEPTIBLE_LOW_APP_ADJ)) { + newAdj = PERCEPTIBLE_LOW_APP_ADJ; + } else if (cr.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE) + && cr.notHasFlag(Context.BIND_NOT_FOREGROUND) + && clientAdj < PERCEPTIBLE_APP_ADJ + && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) { + // This is for user-initiated jobs. + // We use APP_ADJ + 1 here, so we can tell them apart from FGS. + newAdj = PERCEPTIBLE_APP_ADJ + 1; + } else if (cr.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE) + && cr.hasFlag(Context.BIND_NOT_FOREGROUND) + && clientAdj < PERCEPTIBLE_APP_ADJ + && adj >= (lbAdj = (PERCEPTIBLE_MEDIUM_APP_ADJ + 2))) { + // This is for expedited jobs. + // We use MEDIUM_APP_ADJ + 2 here, so we can tell apart + // EJ and short-FGS. + newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ + 2; + } else if (cr.hasFlag(Context.BIND_NOT_VISIBLE) + && clientAdj < PERCEPTIBLE_APP_ADJ + && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) { + newAdj = PERCEPTIBLE_APP_ADJ; + } else if (clientAdj >= PERCEPTIBLE_APP_ADJ) { + newAdj = clientAdj; + } else if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE) + && clientAdj <= VISIBLE_APP_ADJ + && adj > VISIBLE_APP_ADJ) { + newAdj = VISIBLE_APP_ADJ; + } else { + if (adj > VISIBLE_APP_ADJ) { + // TODO: Is this too limiting for apps bound from TOP? + newAdj = Math.max(clientAdj, lbAdj); + } else { + newAdj = adj; + } + } + if (!cstate.isCached()) { + state.setCached(false); + } + if (adj > newAdj) { + adj = newAdj; + state.setCurRawAdj(adj); + adjType = "service"; + } + } + } + if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND + | Context.BIND_IMPORTANT_BACKGROUND)) { + // This will treat important bound services identically to + // the top app, which may behave differently than generic + // foreground work. + final int curSchedGroup = cstate.getCurrentSchedulingGroup(); + if (curSchedGroup > schedGroup) { + if (cr.hasFlag(Context.BIND_IMPORTANT)) { + schedGroup = curSchedGroup; + } else { + schedGroup = SCHED_GROUP_DEFAULT; + } + } + if (clientProcState < PROCESS_STATE_TOP) { + // Special handling for above-top states (persistent + // processes). These should not bring the current process + // into the top state, since they are not on top. Instead + // give them the best bound state after that. + if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE)) { + clientProcState = PROCESS_STATE_FOREGROUND_SERVICE; + } else if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) { + clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE; + } else if (mService.mWakefulness.get() + == PowerManagerInternal.WAKEFULNESS_AWAKE + && cr.hasFlag(Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)) + { + clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE; + } else { + clientProcState = + PROCESS_STATE_IMPORTANT_FOREGROUND; + } + } else if (clientProcState == PROCESS_STATE_TOP) { + // Go at most to BOUND_TOP, unless requested to elevate + // to client's state. + clientProcState = PROCESS_STATE_BOUND_TOP; + final boolean enabled = cstate.getCachedCompatChange( + CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY); + if (enabled) { + if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) { + // TOP process passes all capabilities to the service. + capability |= cstate.getCurCapability(); + } else { + // TOP process passes no capability to the service. + } + } else { + // TOP process passes all capabilities to the service. + capability |= cstate.getCurCapability(); + } + } + } else if (cr.notHasFlag(Context.BIND_IMPORTANT_BACKGROUND)) { + if (clientProcState < + PROCESS_STATE_TRANSIENT_BACKGROUND) { + clientProcState = + PROCESS_STATE_TRANSIENT_BACKGROUND; + } + } else { + if (clientProcState < + PROCESS_STATE_IMPORTANT_BACKGROUND) { + clientProcState = + PROCESS_STATE_IMPORTANT_BACKGROUND; + } + } + + if (schedGroup < SCHED_GROUP_TOP_APP + && cr.hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP) + && clientIsSystem) { + schedGroup = SCHED_GROUP_TOP_APP; + scheduleLikeTopApp = true; + } + + if (!trackedProcState) { + cr.trackProcState(clientProcState, mAdjSeq); + } + + if (procState > clientProcState) { + procState = clientProcState; + state.setCurRawProcState(procState); + if (adjType == null) { + adjType = "service"; + } + } + if (procState < PROCESS_STATE_IMPORTANT_BACKGROUND + && cr.hasFlag(Context.BIND_SHOWING_UI)) { + app.setPendingUiClean(true); + } + if (adjType != null) { + state.setAdjType(adjType); + state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo + .REASON_SERVICE_IN_USE); + state.setAdjSource(client); + state.setAdjSourceProcState(clientProcState); + state.setAdjTarget(s.instanceName); + if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { + reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType + + ": " + app + ", due to " + client + + " adj=" + adj + " procState=" + + ProcessList.makeProcStateString(procState)); + } + } + } else { // BIND_WAIVE_PRIORITY == true + // BIND_WAIVE_PRIORITY bindings are special when it comes to the + // freezer. Processes bound via WPRI are expected to be running, + // but they are not promoted in the LRU list to keep them out of + // cached. As a result, they can freeze based on oom_adj alone. + // Normally, bindToDeath would fire when a cached app would die + // in the background, but nothing will fire when a running process + // pings a frozen process. Accordingly, any cached app that is + // bound by an unfrozen app via a WPRI binding has to remain + // unfrozen. + if (clientAdj < CACHED_APP_MIN_ADJ) { + app.mOptRecord.setShouldNotFreeze(true); + } + } + if (cr.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) { + psr.setTreatLikeActivity(true); + } + final ActivityServiceConnectionsHolder a = cr.activity; + if (cr.hasFlag(Context.BIND_ADJUST_WITH_ACTIVITY)) { + if (a != null && adj > FOREGROUND_APP_ADJ + && a.isActivityVisible()) { + adj = FOREGROUND_APP_ADJ; + state.setCurRawAdj(adj); + if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND)) { + if (cr.hasFlag(Context.BIND_IMPORTANT)) { + schedGroup = SCHED_GROUP_TOP_APP_BOUND; + } else { + schedGroup = SCHED_GROUP_DEFAULT; + } + } + state.setCached(false); + state.setAdjType("service"); + state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo + .REASON_SERVICE_IN_USE); + state.setAdjSource(a); + state.setAdjSourceProcState(procState); + state.setAdjTarget(s.instanceName); + if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { + reportOomAdjMessageLocked(TAG_OOM_ADJ, + "Raise to service w/activity: " + app); + } + } + } } } } @@ -2330,27 +2603,97 @@ public class OomAdjuster { || procState > PROCESS_STATE_TOP); provi--) { ContentProviderRecord cpr = ppr.getProviderAt(provi); - if (couldRecurse) { - // We're entering recursive functions below. - state.setCurRawAdj(adj); - state.setCurRawProcState(procState); - state.setCurrentSchedulingGroup(schedGroup); - state.setCurCapability(capability); - - for (int i = cpr.connections.size() - 1; - i >= 0 && (adj > FOREGROUND_APP_ADJ - || schedGroup == SCHED_GROUP_BACKGROUND - || procState > PROCESS_STATE_TOP); - i--) { - ContentProviderConnection conn = cpr.connections.get(i); - ProcessRecord client = conn.client; - computeProviderHostOomAdjLSP(conn, app, client, now, topApp, doingAll, - cycleReEval, computeClients, oomAdjReason, cachedAdj, true); + for (int i = cpr.connections.size() - 1; + i >= 0 && (adj > FOREGROUND_APP_ADJ + || schedGroup == SCHED_GROUP_BACKGROUND + || procState > PROCESS_STATE_TOP); + i--) { + ContentProviderConnection conn = cpr.connections.get(i); + ProcessRecord client = conn.client; + final ProcessStateRecord cstate = client.mState; + if (client == app) { + // Being our own client is not interesting. + continue; + } + if (computeClients) { + computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, cycleReEval, true); + } else { + cstate.setCurRawAdj(cstate.getCurAdj()); + cstate.setCurRawProcState(cstate.getCurProcState()); + } + + if (shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) { + continue; + } + + int clientAdj = cstate.getCurRawAdj(); + int clientProcState = cstate.getCurRawProcState(); + + // We always propagate PROCESS_CAPABILITY_BFSL to providers here, + // but, right before actually setting it to the process, + // we check the final procstate, and remove it if the procsate is below BFGS. + capability |= getBfslCapabilityFromClient(client); + + if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) { + // If the other app is cached for any reason, for purposes here + // we are going to consider it empty. + clientProcState = PROCESS_STATE_CACHED_EMPTY; + } + if (client.mOptRecord.shouldNotFreeze()) { + // Propagate the shouldNotFreeze flag down the bindings. + app.mOptRecord.setShouldNotFreeze(true); + } + + boundByNonBgRestricted |= cstate.isCurBoundByNonBgRestrictedApp() + || clientProcState <= PROCESS_STATE_BOUND_TOP + || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE + && !cstate.isBackgroundRestricted()); - adj = state.getCurRawAdj(); - procState = state.getCurRawProcState(); - schedGroup = state.getCurrentSchedulingGroup(); - capability = state.getCurCapability(); + String adjType = null; + if (adj > clientAdj) { + if (state.hasShownUi() && !state.getCachedIsHomeProcess() + && clientAdj > PERCEPTIBLE_APP_ADJ) { + adjType = "cch-ui-provider"; + } else { + adj = Math.max(clientAdj, FOREGROUND_APP_ADJ); + state.setCurRawAdj(adj); + adjType = "provider"; + } + state.setCached(state.isCached() & cstate.isCached()); + } + + if (clientProcState <= PROCESS_STATE_FOREGROUND_SERVICE) { + if (adjType == null) { + adjType = "provider"; + } + if (clientProcState == PROCESS_STATE_TOP) { + clientProcState = PROCESS_STATE_BOUND_TOP; + } else { + clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE; + } + } + + conn.trackProcState(clientProcState, mAdjSeq); + if (procState > clientProcState) { + procState = clientProcState; + state.setCurRawProcState(procState); + } + if (cstate.getCurrentSchedulingGroup() > schedGroup) { + schedGroup = SCHED_GROUP_DEFAULT; + } + if (adjType != null) { + state.setAdjType(adjType); + state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo + .REASON_PROVIDER_IN_USE); + state.setAdjSource(client); + state.setAdjSourceProcState(clientProcState); + state.setAdjTarget(cpr.name); + if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { + reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType + + ": " + app + ", due to " + client + + " adj=" + adj + " procState=" + + ProcessList.makeProcStateString(procState)); + } } } // If the provider has external (non-framework) process @@ -2456,7 +2799,7 @@ public class OomAdjuster { // restrictions on screen off if (procState >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE && mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE - && !state.shouldScheduleLikeTopApp()) { + && !scheduleLikeTopApp) { if (schedGroup > SCHED_GROUP_RESTRICTED) { schedGroup = SCHED_GROUP_RESTRICTED; } @@ -2474,7 +2817,6 @@ public class OomAdjuster { capability &= ~PROCESS_CAPABILITY_BFSL; } - state.setHasForegroundActivities(foregroundActivities); if (app.isPendingFinishAttach()) { // If the app is still starting up. We reset the computations to the @@ -2492,580 +2834,22 @@ public class OomAdjuster { // it when computing the final cached adj later. Note that we don't need to // worry about this for max adj above, since max adj will always be used to // keep it out of the cached vaues. + state.setCurAdj(adj); state.setCurCapability(capability); + state.setCurrentSchedulingGroup(schedGroup); + state.setCurProcState(procState); + state.setCurRawProcState(procState); state.updateLastInvisibleTime(hasVisibleActivities); + state.setHasForegroundActivities(foregroundActivities); state.setCompletedAdjSeq(mAdjSeq); - - schedGroup = setIntermediateAdjLSP(app, adj, prevAppAdj, schedGroup); - setIntermediateProcStateLSP(app, procState, prevProcState); - setIntermediateSchedGroupLSP(state, schedGroup); + state.setCurBoundByNonBgRestrictedApp(boundByNonBgRestricted); // if curAdj or curProcState improved, then this process was promoted return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState || state.getCurCapability() != prevCapability; } - /** - * @return The proposed change to the schedGroup. - */ - @GuardedBy({"mService", "mProcLock"}) - protected int setIntermediateAdjLSP(ProcessRecord app, int adj, int prevRawAppAdj, - int schedGroup) { - final ProcessStateRecord state = app.mState; - state.setCurRawAdj(adj); - - adj = app.mServices.modifyRawOomAdj(adj); - if (adj > state.getMaxAdj()) { - adj = state.getMaxAdj(); - if (adj <= PERCEPTIBLE_LOW_APP_ADJ) { - schedGroup = SCHED_GROUP_DEFAULT; - } - } - - state.setCurAdj(adj); - - return schedGroup; - } - - @GuardedBy({"mService", "mProcLock"}) - protected void setIntermediateProcStateLSP(ProcessRecord app, int procState, - int prevProcState) { - final ProcessStateRecord state = app.mState; - state.setCurProcState(procState); - state.setCurRawProcState(procState); - } - - @GuardedBy({"mService", "mProcLock"}) - protected void setIntermediateSchedGroupLSP(ProcessStateRecord state, int schedGroup) { - // Put bound foreground services in a special sched group for additional - // restrictions on screen off - if (state.getCurProcState() >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE - && mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE - && !state.shouldScheduleLikeTopApp()) { - if (schedGroup > SCHED_GROUP_RESTRICTED) { - schedGroup = SCHED_GROUP_RESTRICTED; - } - } - - state.setCurrentSchedulingGroup(schedGroup); - } - - @GuardedBy({"mService", "mProcLock"}) - protected void computeServiceHostOomAdjLSP(ConnectionRecord cr, ProcessRecord app, - ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll, - boolean cycleReEval, boolean computeClients, int oomAdjReason, int cachedAdj, - boolean couldRecurse) { - if (app.isPendingFinishAttach()) { - // We've set the attaching process state in the computeInitialOomAdjLSP. Skip it here. - return; - } - - final ProcessStateRecord state = app.mState; - ProcessStateRecord cstate = client.mState; - - if (couldRecurse) { - if (app.isSdkSandbox && cr.binding.attributedClient != null) { - // For SDK sandboxes, use the attributed client (eg the app that - // requested the sandbox) - client = cr.binding.attributedClient; - cstate = client.mState; - } - if (computeClients) { - computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, cycleReEval, true, - oomAdjReason, true); - } else { - cstate.setCurRawAdj(cstate.getCurAdj()); - cstate.setCurRawProcState(cstate.getCurProcState()); - } - } - - int clientAdj = cstate.getCurRawAdj(); - int clientProcState = cstate.getCurRawProcState(); - - final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP; - - int adj = state.getCurRawAdj(); - int procState = state.getCurRawProcState(); - int schedGroup = state.getCurrentSchedulingGroup(); - int capability = state.getCurCapability(); - - final int prevRawAdj = adj; - final int prevProcState = procState; - final int prevSchedGroup = schedGroup; - - final int appUid = app.info.uid; - final int logUid = mService.mCurOomAdjUid; - - state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp() - || cstate.isCurBoundByNonBgRestrictedApp() - || clientProcState <= PROCESS_STATE_BOUND_TOP - || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE - && !cstate.isBackgroundRestricted())); - - if (client.mOptRecord.shouldNotFreeze()) { - // Propagate the shouldNotFreeze flag down the bindings. - app.mOptRecord.setShouldNotFreeze(true); - } - - boolean trackedProcState = false; - - // We always propagate PROCESS_CAPABILITY_BFSL over bindings here, - // but, right before actually setting it to the process, - // we check the final procstate, and remove it if the procsate is below BFGS. - capability |= getBfslCapabilityFromClient(client); - - if (cr.notHasFlag(Context.BIND_WAIVE_PRIORITY)) { - if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) { - capability |= cstate.getCurCapability(); - } - - // If an app has network capability by default - // (by having procstate <= BFGS), then the apps it binds to will get - // elevated to a high enough procstate anyway to get network unless they - // request otherwise, so don't propagate the network capability by default - // in this case unless they explicitly request it. - if ((cstate.getCurCapability() - & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0) { - if (clientProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { - // This is used to grant network access to Expedited Jobs. - if (cr.hasFlag(Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS)) { - capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; - } - } else { - capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; - } - } - if ((cstate.getCurCapability() - & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0) { - if (clientProcState <= PROCESS_STATE_IMPORTANT_FOREGROUND) { - // This is used to grant network access to User Initiated Jobs. - if (cr.hasFlag(Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS)) { - capability |= PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK; - } - } - } - - if (couldRecurse && shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) { - return; - } - - if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) { - // If the other app is cached for any reason, for purposes here - // we are going to consider it empty. The specific cached state - // doesn't propagate except under certain conditions. - clientProcState = PROCESS_STATE_CACHED_EMPTY; - } - String adjType = null; - if (cr.hasFlag(Context.BIND_ALLOW_OOM_MANAGEMENT)) { - // Similar to BIND_WAIVE_PRIORITY, keep it unfrozen. - if (clientAdj < CACHED_APP_MIN_ADJ) { - app.mOptRecord.setShouldNotFreeze(true); - } - // Not doing bind OOM management, so treat - // this guy more like a started service. - if (state.hasShownUi() && !state.getCachedIsHomeProcess()) { - // If this process has shown some UI, let it immediately - // go to the LRU list because it may be pretty heavy with - // UI stuff. We'll tag it with a label just to help - // debug and understand what is going on. - if (adj > clientAdj) { - adjType = "cch-bound-ui-services"; - } - state.setCached(false); - clientAdj = adj; - clientProcState = procState; - } else { - if (now >= (cr.binding.service.lastActivity - + mConstants.MAX_SERVICE_INACTIVITY)) { - // This service has not seen activity within - // recent memory, so allow it to drop to the - // LRU list if there is no other reason to keep - // it around. We'll also tag it with a label just - // to help debug and undertand what is going on. - if (adj > clientAdj) { - adjType = "cch-bound-services"; - } - clientAdj = adj; - } - } - } - if (adj > clientAdj) { - // If this process has recently shown UI, and - // the process that is binding to it is less - // important than being visible, then we don't - // care about the binding as much as we care - // about letting this process get into the LRU - // list to be killed and restarted if needed for - // memory. - if (state.hasShownUi() && !state.getCachedIsHomeProcess() - && clientAdj > PERCEPTIBLE_APP_ADJ) { - if (adj >= CACHED_APP_MIN_ADJ) { - adjType = "cch-bound-ui-services"; - } - } else { - int newAdj; - int lbAdj = VISIBLE_APP_ADJ; // lower bound of adj. - if (cr.hasFlag(Context.BIND_ABOVE_CLIENT - | Context.BIND_IMPORTANT)) { - if (clientAdj >= PERSISTENT_SERVICE_ADJ) { - newAdj = clientAdj; - } else { - // make this service persistent - newAdj = PERSISTENT_SERVICE_ADJ; - schedGroup = SCHED_GROUP_DEFAULT; - procState = ActivityManager.PROCESS_STATE_PERSISTENT; - cr.trackProcState(procState, mAdjSeq); - trackedProcState = true; - } - } else if (cr.hasFlag(Context.BIND_NOT_PERCEPTIBLE) - && clientAdj <= PERCEPTIBLE_APP_ADJ - && adj >= (lbAdj = PERCEPTIBLE_LOW_APP_ADJ)) { - newAdj = PERCEPTIBLE_LOW_APP_ADJ; - } else if (cr.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE) - && cr.notHasFlag(Context.BIND_NOT_FOREGROUND) - && clientAdj < PERCEPTIBLE_APP_ADJ - && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) { - // This is for user-initiated jobs. - // We use APP_ADJ + 1 here, so we can tell them apart from FGS. - newAdj = PERCEPTIBLE_APP_ADJ + 1; - } else if (cr.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE) - && cr.hasFlag(Context.BIND_NOT_FOREGROUND) - && clientAdj < PERCEPTIBLE_APP_ADJ - && adj >= (lbAdj = (PERCEPTIBLE_MEDIUM_APP_ADJ + 2))) { - // This is for expedited jobs. - // We use MEDIUM_APP_ADJ + 2 here, so we can tell apart - // EJ and short-FGS. - newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ + 2; - } else if (cr.hasFlag(Context.BIND_NOT_VISIBLE) - && clientAdj < PERCEPTIBLE_APP_ADJ - && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) { - newAdj = PERCEPTIBLE_APP_ADJ; - } else if (clientAdj >= PERCEPTIBLE_APP_ADJ) { - newAdj = clientAdj; - } else if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE) - && clientAdj <= VISIBLE_APP_ADJ - && adj > VISIBLE_APP_ADJ) { - newAdj = VISIBLE_APP_ADJ; - } else { - if (adj > VISIBLE_APP_ADJ) { - // TODO: Is this too limiting for apps bound from TOP? - newAdj = Math.max(clientAdj, lbAdj); - } else { - newAdj = adj; - } - } - if (!cstate.isCached()) { - state.setCached(false); - } - if (adj > newAdj) { - adj = newAdj; - state.setCurRawAdj(adj); - adjType = "service"; - } - } - } - if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND - | Context.BIND_IMPORTANT_BACKGROUND)) { - // This will treat important bound services identically to - // the top app, which may behave differently than generic - // foreground work. - final int curSchedGroup = cstate.getCurrentSchedulingGroup(); - if (curSchedGroup > schedGroup) { - if (cr.hasFlag(Context.BIND_IMPORTANT)) { - schedGroup = curSchedGroup; - } else { - schedGroup = SCHED_GROUP_DEFAULT; - } - } - if (clientProcState < PROCESS_STATE_TOP) { - // Special handling for above-top states (persistent - // processes). These should not bring the current process - // into the top state, since they are not on top. Instead - // give them the best bound state after that. - if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE)) { - clientProcState = PROCESS_STATE_FOREGROUND_SERVICE; - } else if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) { - clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE; - } else if (mService.mWakefulness.get() - == PowerManagerInternal.WAKEFULNESS_AWAKE - && cr.hasFlag(Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)) { - clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE; - } else { - clientProcState = - PROCESS_STATE_IMPORTANT_FOREGROUND; - } - } else if (clientProcState == PROCESS_STATE_TOP) { - // Go at most to BOUND_TOP, unless requested to elevate - // to client's state. - clientProcState = PROCESS_STATE_BOUND_TOP; - final boolean enabled = cstate.getCachedCompatChange( - CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY); - if (enabled) { - if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) { - // TOP process passes all capabilities to the service. - capability |= cstate.getCurCapability(); - } else { - // TOP process passes no capability to the service. - } - } else { - // TOP process passes all capabilities to the service. - capability |= cstate.getCurCapability(); - } - } - } else if (cr.notHasFlag(Context.BIND_IMPORTANT_BACKGROUND)) { - if (clientProcState < PROCESS_STATE_TRANSIENT_BACKGROUND) { - clientProcState = - PROCESS_STATE_TRANSIENT_BACKGROUND; - } - } else { - if (clientProcState < PROCESS_STATE_IMPORTANT_BACKGROUND) { - clientProcState = - PROCESS_STATE_IMPORTANT_BACKGROUND; - } - } - - if (schedGroup < SCHED_GROUP_TOP_APP - && cr.hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP) - && clientIsSystem) { - schedGroup = SCHED_GROUP_TOP_APP; - state.setScheduleLikeTopApp(true); - } - - if (!trackedProcState) { - cr.trackProcState(clientProcState, mAdjSeq); - } - - if (procState > clientProcState) { - procState = clientProcState; - state.setCurRawProcState(procState); - if (adjType == null) { - adjType = "service"; - } - } - if (procState < PROCESS_STATE_IMPORTANT_BACKGROUND - && cr.hasFlag(Context.BIND_SHOWING_UI)) { - app.setPendingUiClean(true); - } - if (adjType != null) { - state.setAdjType(adjType); - state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo - .REASON_SERVICE_IN_USE); - state.setAdjSource(client); - state.setAdjSourceProcState(clientProcState); - state.setAdjTarget(cr.binding.service.instanceName); - if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { - reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType - + ": " + app + ", due to " + client - + " adj=" + adj + " procState=" - + ProcessList.makeProcStateString(procState)); - } - } - } else { // BIND_WAIVE_PRIORITY == true - // BIND_WAIVE_PRIORITY bindings are special when it comes to the - // freezer. Processes bound via WPRI are expected to be running, - // but they are not promoted in the LRU list to keep them out of - // cached. As a result, they can freeze based on oom_adj alone. - // Normally, bindToDeath would fire when a cached app would die - // in the background, but nothing will fire when a running process - // pings a frozen process. Accordingly, any cached app that is - // bound by an unfrozen app via a WPRI binding has to remain - // unfrozen. - if (clientAdj < CACHED_APP_MIN_ADJ) { - app.mOptRecord.setShouldNotFreeze(true); - } - } - if (cr.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) { - app.mServices.setTreatLikeActivity(true); - if (clientProcState <= PROCESS_STATE_CACHED_ACTIVITY - && procState > PROCESS_STATE_CACHED_ACTIVITY) { - // This is a cached process, but somebody wants us to treat it like it has - // an activity, okay! - procState = PROCESS_STATE_CACHED_ACTIVITY; - state.setAdjType("cch-as-act"); - } - } - final ActivityServiceConnectionsHolder a = cr.activity; - if (cr.hasFlag(Context.BIND_ADJUST_WITH_ACTIVITY)) { - if (a != null && adj > FOREGROUND_APP_ADJ - && a.isActivityVisible()) { - adj = FOREGROUND_APP_ADJ; - state.setCurRawAdj(adj); - if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND)) { - if (cr.hasFlag(Context.BIND_IMPORTANT)) { - schedGroup = SCHED_GROUP_TOP_APP_BOUND; - } else { - schedGroup = SCHED_GROUP_DEFAULT; - } - } - state.setCached(false); - state.setAdjType("service"); - state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo - .REASON_SERVICE_IN_USE); - state.setAdjSource(a); - state.setAdjSourceProcState(procState); - state.setAdjTarget(cr.binding.service.instanceName); - if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { - reportOomAdjMessageLocked(TAG_OOM_ADJ, - "Raise to service w/activity: " + app); - } - } - } - - capability |= getDefaultCapability(app, procState); - - // Procstates below BFGS should never have this capability. - if (procState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { - capability &= ~PROCESS_CAPABILITY_BFSL; - } - - if (adj < prevRawAdj) { - schedGroup = setIntermediateAdjLSP(app, adj, prevRawAdj, schedGroup); - } - if (procState < prevProcState) { - setIntermediateProcStateLSP(app, procState, prevProcState); - } - if (schedGroup > prevSchedGroup) { - setIntermediateSchedGroupLSP(state, schedGroup); - } - state.setCurCapability(capability); - - state.setEmpty(false); - } - - protected void computeProviderHostOomAdjLSP(ContentProviderConnection conn, ProcessRecord app, - ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll, - boolean cycleReEval, boolean computeClients, int oomAdjReason, int cachedAdj, - boolean couldRecurse) { - if (app.isPendingFinishAttach()) { - // We've set the attaching process state in the computeInitialOomAdjLSP. Skip it here. - return; - } - - final ProcessStateRecord state = app.mState; - final ProcessStateRecord cstate = client.mState; - - if (client == app) { - // Being our own client is not interesting. - return; - } - if (couldRecurse) { - if (computeClients) { - computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, cycleReEval, true, - oomAdjReason, true); - } else if (couldRecurse) { - cstate.setCurRawAdj(cstate.getCurAdj()); - cstate.setCurRawProcState(cstate.getCurProcState()); - } - - if (shouldSkipDueToCycle(app, cstate, state.getCurRawProcState(), state.getCurRawAdj(), - cycleReEval)) { - return; - } - } - - int clientAdj = cstate.getCurRawAdj(); - int clientProcState = cstate.getCurRawProcState(); - - int adj = state.getCurRawAdj(); - int procState = state.getCurRawProcState(); - int schedGroup = state.getCurrentSchedulingGroup(); - int capability = state.getCurCapability(); - - final int prevRawAdj = adj; - final int prevProcState = procState; - final int prevSchedGroup = schedGroup; - - final int appUid = app.info.uid; - final int logUid = mService.mCurOomAdjUid; - - // We always propagate PROCESS_CAPABILITY_BFSL to providers here, - // but, right before actually setting it to the process, - // we check the final procstate, and remove it if the procsate is below BFGS. - capability |= getBfslCapabilityFromClient(client); - - if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) { - // If the other app is cached for any reason, for purposes here - // we are going to consider it empty. - clientProcState = PROCESS_STATE_CACHED_EMPTY; - } - if (client.mOptRecord.shouldNotFreeze()) { - // Propagate the shouldNotFreeze flag down the bindings. - app.mOptRecord.setShouldNotFreeze(true); - } - - state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp() - || cstate.isCurBoundByNonBgRestrictedApp() - || clientProcState <= PROCESS_STATE_BOUND_TOP - || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE - && !cstate.isBackgroundRestricted())); - - String adjType = null; - if (adj > clientAdj) { - if (state.hasShownUi() && !state.getCachedIsHomeProcess() - && clientAdj > PERCEPTIBLE_APP_ADJ) { - adjType = "cch-ui-provider"; - } else { - adj = Math.max(clientAdj, FOREGROUND_APP_ADJ); - state.setCurRawAdj(adj); - adjType = "provider"; - } - state.setCached(state.isCached() & cstate.isCached()); - } - - if (clientProcState <= PROCESS_STATE_FOREGROUND_SERVICE) { - if (adjType == null) { - adjType = "provider"; - } - if (clientProcState == PROCESS_STATE_TOP) { - clientProcState = PROCESS_STATE_BOUND_TOP; - } else { - clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE; - } - } - - conn.trackProcState(clientProcState, mAdjSeq); - if (procState > clientProcState) { - procState = clientProcState; - state.setCurRawProcState(procState); - } - if (cstate.getCurrentSchedulingGroup() > schedGroup) { - schedGroup = SCHED_GROUP_DEFAULT; - } - if (adjType != null) { - state.setAdjType(adjType); - state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo - .REASON_PROVIDER_IN_USE); - state.setAdjSource(client); - state.setAdjSourceProcState(clientProcState); - state.setAdjTarget(conn.provider.name); - if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { - reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType - + ": " + app + ", due to " + client - + " adj=" + adj + " procState=" - + ProcessList.makeProcStateString(procState)); - } - } - - // Procstates below BFGS should never have this capability. - if (procState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { - capability &= ~PROCESS_CAPABILITY_BFSL; - } - - if (adj < prevRawAdj) { - schedGroup = setIntermediateAdjLSP(app, adj, prevRawAdj, schedGroup); - } - if (procState < prevProcState) { - setIntermediateProcStateLSP(app, procState, prevProcState); - } - if (schedGroup > prevSchedGroup) { - setIntermediateSchedGroupLSP(state, schedGroup); - } - state.setCurCapability(capability); - - state.setEmpty(false); - } - - protected int getDefaultCapability(ProcessRecord app, int procState) { + private int getDefaultCapability(ProcessRecord app, int procState) { final int networkCapabilities = NetworkPolicyManager.getDefaultProcessNetworkCapabilities(procState); final int baseCapabilities; @@ -3098,7 +2882,7 @@ public class OomAdjuster { /** * @return the BFSL capability from a client (of a service binding or provider). */ - protected int getBfslCapabilityFromClient(ProcessRecord client) { + int getBfslCapabilityFromClient(ProcessRecord client) { // Procstates above FGS should always have this flag. We shouldn't need this logic, // but let's do it just in case. if (client.mState.getCurProcState() < PROCESS_STATE_FOREGROUND_SERVICE) { @@ -3183,7 +2967,7 @@ public class OomAdjuster { /** Inform the oomadj observer of changes to oomadj. Used by tests. */ @GuardedBy("mService") - protected void reportOomAdjMessageLocked(String tag, String msg) { + private void reportOomAdjMessageLocked(String tag, String msg) { Slog.d(tag, msg); synchronized (mService.mOomAdjObserverLock) { if (mService.mCurOomAdjObserver != null) { @@ -3199,7 +2983,7 @@ public class OomAdjuster { /** Applies the computed oomadj, procstate and sched group values and freezes them in set* */ @GuardedBy({"mService", "mProcLock"}) - protected boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now, + private boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now, long nowElapsed, @OomAdjReason int oomAdjReson) { boolean success = true; final ProcessStateRecord state = app.mState; @@ -3488,8 +3272,6 @@ public class OomAdjuster { int initialCapability = PROCESS_CAPABILITY_NONE; boolean initialCached = true; final ProcessStateRecord state = app.mState; - final int prevProcState = PROCESS_STATE_UNKNOWN; - final int prevAdj = UNKNOWN_ADJ; // If the process has been marked as foreground, it is starting as the top app (with // Zygote#START_AS_TOP_APP_ARG), so boost the thread priority of its default UI thread. if (state.hasForegroundActivities()) { @@ -3524,9 +3306,6 @@ public class OomAdjuster { state.setCurRawAdj(ProcessList.FOREGROUND_APP_ADJ); state.setForcingToImportant(null); state.setHasShownUi(false); - - onProcessStateChanged(app, prevProcState); - onProcessOomAdjChanged(app, prevAdj); } // ONLY used for unit testing in OomAdjusterTests.java @@ -3774,56 +3553,4 @@ public class OomAdjuster { } processes.clear(); } - - @GuardedBy("mService") - void onProcessBeginLocked(@NonNull ProcessRecord app) { - // Empty, the OomAdjusterModernImpl will have an implementation. - } - - @GuardedBy("mService") - void onProcessEndLocked(@NonNull ProcessRecord app) { - // Empty, the OomAdjusterModernImpl will have an implementation. - } - - /** - * Called when the process state is changed outside of the OomAdjuster. - */ - @GuardedBy("mService") - void onProcessStateChanged(@NonNull ProcessRecord app, int prevProcState) { - // Empty, the OomAdjusterModernImpl will have an implementation. - } - - /** - * Called when the oom adj is changed outside of the OomAdjuster. - */ - @GuardedBy("mService") - void onProcessOomAdjChanged(@NonNull ProcessRecord app, int prevAdj) { - // Empty, the OomAdjusterModernImpl will have an implementation. - } - - @VisibleForTesting - void resetInternal() { - // Empty, the OomAdjusterModernImpl will have an implementation. - } - - @GuardedBy("mService") - protected int getInitialAdj(@NonNull ProcessRecord app) { - return app.mState.getCurAdj(); - } - - @GuardedBy("mService") - protected int getInitialProcState(@NonNull ProcessRecord app) { - return app.mState.getCurProcState(); - } - - @GuardedBy("mService") - protected int getInitialCapability(@NonNull ProcessRecord app) { - return app.mState.getCurCapability(); - } - - @GuardedBy("mService") - protected boolean getInitialIsCurBoundByNonBgRestrictedApp(@NonNull ProcessRecord app) { - // The caller will set the initial value in this implementation. - return app.mState.isCurBoundByNonBgRestrictedApp(); - } } diff --git a/services/core/java/com/android/server/am/OomAdjuster.md b/services/core/java/com/android/server/am/OomAdjuster.md index da5e12ef21fa..16091d1c162d 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.md +++ b/services/core/java/com/android/server/am/OomAdjuster.md @@ -130,28 +130,3 @@ The Oom Adjuster maintains a global sequence ID `mAdjSeq` to track the current O * Iterate the processes from least important to most important ones. * A maximum retries of 10 is enforced, while in practice, the maximum retries could reach only 2 to 3. -## The Modern Implementation - -As aforementioned, the OomAdjuster makes the computation in a recursive way, while this is inefficient in dealing with the cycles. The overall code complexity should be around **O((1 + num(retries)) * num(procs) * num(binding connections))**. In addition, depending on the ordering of the input, the algorithm may produce different results and sometimes it's wrong. - -The new "Modern Implementation" is based on the rationale that, apps can't promote the service/provider it connects to, to a higher bucket than itself. We are introducing a bucket based, breadth first search algorithm, as illustrated below: - -``` -for all processes in the process list - compute the state of each process, but, excluding its clients - put each process to the corresponding bucket according to the state value -done - -for each bucket, starting from the top most to the bottom most - for each process in the bucket - for each process it binds to - if the state of the bindee process could be elevated because of the binding; then - move the bindee process to the higher bucket - fi - done - done -done -``` - -The overall code complexity should be around **O(num(procs) * num(binding connections))**, which saves the retry time from the existing algorithm. - diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java deleted file mode 100644 index b852ef56fceb..000000000000 --- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java +++ /dev/null @@ -1,1125 +0,0 @@ -/* - * Copyright (C) 2023 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 static android.app.ActivityManager.PROCESS_STATE_BACKUP; -import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; -import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP; -import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; -import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT; -import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY; -import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT; -import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; -import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT; -import static android.app.ActivityManager.PROCESS_STATE_HOME; -import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND; -import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; -import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY; -import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT; -import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI; -import static android.app.ActivityManager.PROCESS_STATE_RECEIVER; -import static android.app.ActivityManager.PROCESS_STATE_SERVICE; -import static android.app.ActivityManager.PROCESS_STATE_TOP; -import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING; -import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND; -import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; - -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS; -import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS; -import static com.android.server.am.ProcessList.BACKUP_APP_ADJ; -import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ; -import static com.android.server.am.ProcessList.FOREGROUND_APP_ADJ; -import static com.android.server.am.ProcessList.HEAVY_WEIGHT_APP_ADJ; -import static com.android.server.am.ProcessList.HOME_APP_ADJ; -import static com.android.server.am.ProcessList.NATIVE_ADJ; -import static com.android.server.am.ProcessList.PERCEPTIBLE_APP_ADJ; -import static com.android.server.am.ProcessList.PERCEPTIBLE_LOW_APP_ADJ; -import static com.android.server.am.ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ; -import static com.android.server.am.ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ; -import static com.android.server.am.ProcessList.PERSISTENT_PROC_ADJ; -import static com.android.server.am.ProcessList.PERSISTENT_SERVICE_ADJ; -import static com.android.server.am.ProcessList.PREVIOUS_APP_ADJ; -import static com.android.server.am.ProcessList.SCHED_GROUP_BACKGROUND; -import static com.android.server.am.ProcessList.SERVICE_ADJ; -import static com.android.server.am.ProcessList.SERVICE_B_ADJ; -import static com.android.server.am.ProcessList.SYSTEM_ADJ; -import static com.android.server.am.ProcessList.UNKNOWN_ADJ; -import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.ActivityManager; -import android.app.ActivityManagerInternal.OomAdjReason; -import android.content.pm.ServiceInfo; -import android.os.IBinder; -import android.os.SystemClock; -import android.os.Trace; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.Slog; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.server.ServiceThread; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.function.Consumer; - -/** - * A modern implementation of the oom adjuster. - */ -public class OomAdjusterModernImpl extends OomAdjuster { - static final String TAG = "OomAdjusterModernImpl"; - - // The ADJ_SLOT_INVALID is NOT an actual slot. - static final int ADJ_SLOT_INVALID = -1; - static final int ADJ_SLOT_NATIVE = 0; - static final int ADJ_SLOT_SYSTEM = 1; - static final int ADJ_SLOT_PERSISTENT_PROC = 2; - static final int ADJ_SLOT_PERSISTENT_SERVICE = 3; - static final int ADJ_SLOT_FOREGROUND_APP = 4; - static final int ADJ_SLOT_PERCEPTIBLE_RECENT_FOREGROUND_APP = 5; - static final int ADJ_SLOT_VISIBLE_APP = 6; - static final int ADJ_SLOT_PERCEPTIBLE_APP = 7; - static final int ADJ_SLOT_PERCEPTIBLE_MEDIUM_APP = 8; - static final int ADJ_SLOT_PERCEPTIBLE_LOW_APP = 9; - static final int ADJ_SLOT_BACKUP_APP = 10; - static final int ADJ_SLOT_HEAVY_WEIGHT_APP = 11; - static final int ADJ_SLOT_SERVICE = 12; - static final int ADJ_SLOT_HOME_APP = 13; - static final int ADJ_SLOT_PREVIOUS_APP = 14; - static final int ADJ_SLOT_SERVICE_B = 15; - static final int ADJ_SLOT_CACHED_APP = 16; - static final int ADJ_SLOT_UNKNOWN = 17; - - @IntDef(prefix = { "ADJ_SLOT_" }, value = { - ADJ_SLOT_INVALID, - ADJ_SLOT_NATIVE, - ADJ_SLOT_SYSTEM, - ADJ_SLOT_PERSISTENT_PROC, - ADJ_SLOT_PERSISTENT_SERVICE, - ADJ_SLOT_FOREGROUND_APP, - ADJ_SLOT_PERCEPTIBLE_RECENT_FOREGROUND_APP, - ADJ_SLOT_VISIBLE_APP, - ADJ_SLOT_PERCEPTIBLE_APP, - ADJ_SLOT_PERCEPTIBLE_MEDIUM_APP, - ADJ_SLOT_PERCEPTIBLE_LOW_APP, - ADJ_SLOT_BACKUP_APP, - ADJ_SLOT_HEAVY_WEIGHT_APP, - ADJ_SLOT_SERVICE, - ADJ_SLOT_HOME_APP, - ADJ_SLOT_PREVIOUS_APP, - ADJ_SLOT_SERVICE_B, - ADJ_SLOT_CACHED_APP, - ADJ_SLOT_UNKNOWN, - }) - @Retention(RetentionPolicy.SOURCE) - @interface AdjSlot{} - - static final int[] ADJ_SLOT_VALUES = new int[] { - NATIVE_ADJ, - SYSTEM_ADJ, - PERSISTENT_PROC_ADJ, - PERSISTENT_SERVICE_ADJ, - FOREGROUND_APP_ADJ, - PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, - VISIBLE_APP_ADJ, - PERCEPTIBLE_APP_ADJ, - PERCEPTIBLE_MEDIUM_APP_ADJ, - PERCEPTIBLE_LOW_APP_ADJ, - BACKUP_APP_ADJ, - HEAVY_WEIGHT_APP_ADJ, - SERVICE_ADJ, - HOME_APP_ADJ, - PREVIOUS_APP_ADJ, - SERVICE_B_ADJ, - CACHED_APP_MIN_ADJ, - UNKNOWN_ADJ, - }; - - /** - * Note: Always use the raw adj to call this API. - */ - static @AdjSlot int adjToSlot(int adj) { - if (adj >= ADJ_SLOT_VALUES[0] && adj <= ADJ_SLOT_VALUES[ADJ_SLOT_VALUES.length - 1]) { - // Conduct a binary search, in most of the cases it'll get a hit. - final int index = Arrays.binarySearch(ADJ_SLOT_VALUES, adj); - if (index >= 0) { - return index; - } - // If not found, the returned index above should be (-(insertion point) - 1), - // let's return the first slot that's less than the adj value. - return -(index + 1) - 1; - } - return ADJ_SLOT_VALUES.length - 1; - } - - static final int[] PROC_STATE_SLOTS = new int[] { - PROCESS_STATE_PERSISTENT, // 0 - PROCESS_STATE_PERSISTENT_UI, - PROCESS_STATE_TOP, - PROCESS_STATE_BOUND_TOP, - PROCESS_STATE_FOREGROUND_SERVICE, - PROCESS_STATE_BOUND_FOREGROUND_SERVICE, - PROCESS_STATE_IMPORTANT_FOREGROUND, - PROCESS_STATE_IMPORTANT_BACKGROUND, - PROCESS_STATE_TRANSIENT_BACKGROUND, - PROCESS_STATE_BACKUP, - PROCESS_STATE_SERVICE, - PROCESS_STATE_RECEIVER, - PROCESS_STATE_TOP_SLEEPING, - PROCESS_STATE_HEAVY_WEIGHT, - PROCESS_STATE_HOME, - PROCESS_STATE_LAST_ACTIVITY, - PROCESS_STATE_CACHED_ACTIVITY, - PROCESS_STATE_CACHED_ACTIVITY_CLIENT, - PROCESS_STATE_CACHED_RECENT, - PROCESS_STATE_CACHED_EMPTY, - PROCESS_STATE_UNKNOWN, // -1 - }; - - static int processStateToSlot(@ActivityManager.ProcessState int state) { - if (state >= PROCESS_STATE_PERSISTENT && state <= PROCESS_STATE_CACHED_EMPTY) { - return state; - } - return PROC_STATE_SLOTS.length - 1; - } - - /** - * A container node in the {@link LinkedProcessRecordList}, - * holding the references to {@link ProcessRecord}. - */ - static class ProcessRecordNode { - static final int NODE_TYPE_PROC_STATE = 0; - static final int NODE_TYPE_ADJ = 1; - - @IntDef(prefix = { "NODE_TYPE_" }, value = { - NODE_TYPE_PROC_STATE, - NODE_TYPE_ADJ, - }) - @Retention(RetentionPolicy.SOURCE) - @interface NodeType {} - - static final int NUM_NODE_TYPE = NODE_TYPE_ADJ + 1; - - @Nullable ProcessRecordNode mPrev; - @Nullable ProcessRecordNode mNext; - final @Nullable ProcessRecord mApp; - - ProcessRecordNode(@Nullable ProcessRecord app) { - mApp = app; - } - - void unlink() { - if (mPrev != null) { - mPrev.mNext = mNext; - } - if (mNext != null) { - mNext.mPrev = mPrev; - } - mPrev = mNext = null; - } - - boolean isLinked() { - return mPrev != null && mNext != null; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("ProcessRecordNode{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(' '); - sb.append(mApp); - sb.append(' '); - sb.append(mApp != null ? mApp.mState.getCurProcState() : PROCESS_STATE_UNKNOWN); - sb.append(' '); - sb.append(mApp != null ? mApp.mState.getCurAdj() : UNKNOWN_ADJ); - sb.append(' '); - sb.append(Integer.toHexString(System.identityHashCode(mPrev))); - sb.append(' '); - sb.append(Integer.toHexString(System.identityHashCode(mNext))); - sb.append('}'); - return sb.toString(); - } - } - - private class ProcessRecordNodes { - private final @ProcessRecordNode.NodeType int mType; - - private final LinkedProcessRecordList[] mProcessRecordNodes; - // The last node besides the tail. - private final ProcessRecordNode[] mLastNode; - - ProcessRecordNodes(@ProcessRecordNode.NodeType int type, int size) { - mType = type; - mProcessRecordNodes = new LinkedProcessRecordList[size]; - for (int i = 0; i < size; i++) { - mProcessRecordNodes[i] = new LinkedProcessRecordList(type); - } - mLastNode = new ProcessRecordNode[size]; - } - - int size() { - return mProcessRecordNodes.length; - } - - @VisibleForTesting - void reset() { - for (int i = 0; i < mProcessRecordNodes.length; i++) { - mProcessRecordNodes[i].reset(); - mLastNode[i] = null; - } - } - - void resetLastNodes() { - for (int i = 0; i < mProcessRecordNodes.length; i++) { - mLastNode[i] = mProcessRecordNodes[i].getLastNodeBeforeTail(); - } - } - - void setLastNodeToHead(int slot) { - mLastNode[slot] = mProcessRecordNodes[slot].HEAD; - } - - void forEachNewNode(int slot, @NonNull Consumer<OomAdjusterArgs> callback) { - ProcessRecordNode node = mLastNode[slot].mNext; - final ProcessRecordNode tail = mProcessRecordNodes[slot].TAIL; - while (node != tail) { - mTmpOomAdjusterArgs.mApp = node.mApp; - // Save the next before calling callback, since that may change the node.mNext. - final ProcessRecordNode next = node.mNext; - callback.accept(mTmpOomAdjusterArgs); - // There are couple of cases: - // a) The current node is moved to another slot - // - for this case, we'd need to keep using the "next" node. - // b) There are one or more new nodes being appended to this slot - // - for this case, we'd need to make sure we scan the new node too. - // Based on the assumption that case a) is only possible with - // the computeInitialOomAdjLSP(), where the movings are for single node only, - // we may safely assume that, if the "next" used to be the "tail" here, and it's - // now a new tail somewhere else, that's case a); otherwise, it's case b); - node = next == tail && node.mNext != null && node.mNext.mNext != null - ? node.mNext : next; - } - } - - int getNumberOfSlots() { - return mProcessRecordNodes.length; - } - - void moveAppTo(@NonNull ProcessRecord app, int prevSlot, int newSlot) { - final ProcessRecordNode node = app.mLinkedNodes[mType]; - if (prevSlot != ADJ_SLOT_INVALID) { - if (mLastNode[prevSlot] == node) { - mLastNode[prevSlot] = node.mPrev; - } - node.unlink(); - } - mProcessRecordNodes[newSlot].append(node); - } - - void moveAllNodesTo(int fromSlot, int toSlot) { - final LinkedProcessRecordList fromList = mProcessRecordNodes[fromSlot]; - final LinkedProcessRecordList toList = mProcessRecordNodes[toSlot]; - if (fromSlot != toSlot && fromList.HEAD.mNext != fromList.TAIL) { - fromList.moveTo(toList); - mLastNode[fromSlot] = fromList.getLastNodeBeforeTail(); - } - } - - void moveAppToTail(ProcessRecord app) { - final ProcessRecordNode node = app.mLinkedNodes[mType]; - int slot; - switch (mType) { - case ProcessRecordNode.NODE_TYPE_PROC_STATE: - slot = processStateToSlot(app.mState.getCurProcState()); - if (mLastNode[slot] == node) { - mLastNode[slot] = node.mPrev; - } - mProcessRecordNodes[slot].moveNodeToTail(node); - break; - case ProcessRecordNode.NODE_TYPE_ADJ: - slot = adjToSlot(app.mState.getCurRawAdj()); - if (mLastNode[slot] == node) { - mLastNode[slot] = node.mPrev; - } - mProcessRecordNodes[slot].moveNodeToTail(node); - break; - default: - return; - } - - } - - void reset(int slot) { - mProcessRecordNodes[slot].reset(); - } - - void unlink(@NonNull ProcessRecord app) { - final ProcessRecordNode node = app.mLinkedNodes[mType]; - final int slot = getCurrentSlot(app); - if (slot != ADJ_SLOT_INVALID) { - if (mLastNode[slot] == node) { - mLastNode[slot] = node.mPrev; - } - } - node.unlink(); - } - - void append(@NonNull ProcessRecord app) { - append(app, getCurrentSlot(app)); - } - - void append(@NonNull ProcessRecord app, int targetSlot) { - final ProcessRecordNode node = app.mLinkedNodes[mType]; - mProcessRecordNodes[targetSlot].append(node); - } - - private int getCurrentSlot(@NonNull ProcessRecord app) { - switch (mType) { - case ProcessRecordNode.NODE_TYPE_PROC_STATE: - return processStateToSlot(app.mState.getCurProcState()); - case ProcessRecordNode.NODE_TYPE_ADJ: - return adjToSlot(app.mState.getCurRawAdj()); - } - return ADJ_SLOT_INVALID; - } - - String toString(int slot, int logUid) { - return "lastNode=" + mLastNode[slot] + " " + mProcessRecordNodes[slot].toString(logUid); - } - - /** - * A simple version of {@link java.util.LinkedList}, as here we don't allocate new node - * while adding an object to it. - */ - private static class LinkedProcessRecordList { - // Sentinel head/tail, to make bookkeeping work easier. - final ProcessRecordNode HEAD = new ProcessRecordNode(null); - final ProcessRecordNode TAIL = new ProcessRecordNode(null); - final @ProcessRecordNode.NodeType int mNodeType; - - LinkedProcessRecordList(@ProcessRecordNode.NodeType int nodeType) { - HEAD.mNext = TAIL; - TAIL.mPrev = HEAD; - mNodeType = nodeType; - } - - void append(@NonNull ProcessRecordNode node) { - node.mNext = TAIL; - node.mPrev = TAIL.mPrev; - TAIL.mPrev.mNext = node; - TAIL.mPrev = node; - } - - void moveTo(@NonNull LinkedProcessRecordList toList) { - if (HEAD.mNext != TAIL) { - toList.TAIL.mPrev.mNext = HEAD.mNext; - HEAD.mNext.mPrev = toList.TAIL.mPrev; - toList.TAIL.mPrev = TAIL.mPrev; - TAIL.mPrev.mNext = toList.TAIL; - HEAD.mNext = TAIL; - TAIL.mPrev = HEAD; - } - } - - void moveNodeToTail(@NonNull ProcessRecordNode node) { - node.unlink(); - append(node); - } - - @NonNull ProcessRecordNode getLastNodeBeforeTail() { - return TAIL.mPrev; - } - - @VisibleForTesting - void reset() { - HEAD.mNext = TAIL; - TAIL.mPrev = HEAD; - } - - String toString(int logUid) { - final StringBuilder sb = new StringBuilder(); - sb.append("LinkedProcessRecordList{"); - sb.append(HEAD); - sb.append(' '); - sb.append(TAIL); - sb.append('['); - ProcessRecordNode node = HEAD.mNext; - while (node != TAIL) { - if (node.mApp != null && node.mApp.uid == logUid) { - sb.append(node); - sb.append(','); - } - node = node.mNext; - } - sb.append(']'); - sb.append('}'); - return sb.toString(); - } - } - } - - /** - * A data class for holding the parameters in computing oom adj. - */ - private class OomAdjusterArgs { - ProcessRecord mApp; - ProcessRecord mTopApp; - long mNow; - int mCachedAdj; - @OomAdjReason int mOomAdjReason; - @NonNull ActiveUids mUids; - boolean mFullUpdate; - - void update(ProcessRecord topApp, long now, int cachedAdj, - @OomAdjReason int oomAdjReason, @NonNull ActiveUids uids, boolean fullUpdate) { - mTopApp = topApp; - mNow = now; - mCachedAdj = cachedAdj; - mOomAdjReason = oomAdjReason; - mUids = uids; - mFullUpdate = fullUpdate; - } - } - - OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList, - ActiveUids activeUids) { - this(service, processList, activeUids, createAdjusterThread()); - } - - OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList, - ActiveUids activeUids, ServiceThread adjusterThread) { - super(service, processList, activeUids, adjusterThread); - } - - private final ProcessRecordNodes mProcessRecordProcStateNodes = new ProcessRecordNodes( - ProcessRecordNode.NODE_TYPE_PROC_STATE, PROC_STATE_SLOTS.length); - private final ProcessRecordNodes mProcessRecordAdjNodes = new ProcessRecordNodes( - ProcessRecordNode.NODE_TYPE_ADJ, ADJ_SLOT_VALUES.length); - private final OomAdjusterArgs mTmpOomAdjusterArgs = new OomAdjusterArgs(); - - void linkProcessRecordToList(@NonNull ProcessRecord app) { - mProcessRecordProcStateNodes.append(app); - mProcessRecordAdjNodes.append(app); - } - - void unlinkProcessRecordFromList(@NonNull ProcessRecord app) { - mProcessRecordProcStateNodes.unlink(app); - mProcessRecordAdjNodes.unlink(app); - } - - @Override - @VisibleForTesting - void resetInternal() { - mProcessRecordProcStateNodes.reset(); - mProcessRecordAdjNodes.reset(); - } - - @GuardedBy("mService") - @Override - void onProcessBeginLocked(@NonNull ProcessRecord app) { - // Check one type should be good enough. - if (app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE] == null) { - for (int i = 0; i < app.mLinkedNodes.length; i++) { - app.mLinkedNodes[i] = new ProcessRecordNode(app); - } - } - if (!app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE].isLinked()) { - linkProcessRecordToList(app); - } - } - - @GuardedBy("mService") - @Override - void onProcessEndLocked(@NonNull ProcessRecord app) { - if (app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE] != null - && app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE].isLinked()) { - unlinkProcessRecordFromList(app); - } - } - - @GuardedBy("mService") - @Override - void onProcessStateChanged(@NonNull ProcessRecord app, int prevProcState) { - updateProcStateSlotIfNecessary(app, prevProcState); - } - - @GuardedBy("mService") - void onProcessOomAdjChanged(@NonNull ProcessRecord app, int prevAdj) { - updateAdjSlotIfNecessary(app, prevAdj); - } - - @GuardedBy("mService") - @Override - protected int getInitialAdj(@NonNull ProcessRecord app) { - return UNKNOWN_ADJ; - } - - @GuardedBy("mService") - @Override - protected int getInitialProcState(@NonNull ProcessRecord app) { - return PROCESS_STATE_UNKNOWN; - } - - @GuardedBy("mService") - @Override - protected int getInitialCapability(@NonNull ProcessRecord app) { - return 0; - } - - @GuardedBy("mService") - @Override - protected boolean getInitialIsCurBoundByNonBgRestrictedApp(@NonNull ProcessRecord app) { - return false; - } - - private void updateAdjSlotIfNecessary(ProcessRecord app, int prevRawAdj) { - if (app.mState.getCurRawAdj() != prevRawAdj) { - final int slot = adjToSlot(app.mState.getCurRawAdj()); - final int prevSlot = adjToSlot(prevRawAdj); - if (slot != prevSlot && slot != ADJ_SLOT_INVALID) { - mProcessRecordAdjNodes.moveAppTo(app, prevSlot, slot); - } - } - } - - private void updateProcStateSlotIfNecessary(ProcessRecord app, int prevProcState) { - if (app.mState.getCurProcState() != prevProcState) { - final int slot = processStateToSlot(app.mState.getCurProcState()); - final int prevSlot = processStateToSlot(prevProcState); - if (slot != prevSlot) { - mProcessRecordProcStateNodes.moveAppTo(app, prevSlot, slot); - } - } - } - - @Override - protected boolean performUpdateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) { - final ProcessRecord topApp = mService.getTopApp(); - - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason)); - mService.mOomAdjProfiler.oomAdjStarted(); - mAdjSeq++; - - final ProcessStateRecord state = app.mState; - final int oldAdj = state.getCurRawAdj(); - final int cachedAdj = oldAdj >= CACHED_APP_MIN_ADJ - ? oldAdj : UNKNOWN_ADJ; - - final ActiveUids uids = mTmpUidRecords; - final ArraySet<ProcessRecord> targetProcesses = mTmpProcessSet; - final ArrayList<ProcessRecord> reachableProcesses = mTmpProcessList; - final long now = SystemClock.uptimeMillis(); - final long nowElapsed = SystemClock.elapsedRealtime(); - - uids.clear(); - targetProcesses.clear(); - targetProcesses.add(app); - reachableProcesses.clear(); - - // Find out all reachable processes from this app. - collectReachableProcessesLocked(targetProcesses, reachableProcesses, uids); - - // Copy all of the reachable processes into the target process set. - targetProcesses.addAll(reachableProcesses); - reachableProcesses.clear(); - - final boolean result = performNewUpdateOomAdjLSP(oomAdjReason, - topApp, targetProcesses, uids, false, now, cachedAdj); - - reachableProcesses.addAll(targetProcesses); - assignCachedAdjIfNecessary(reachableProcesses); - for (int i = uids.size() - 1; i >= 0; i--) { - final UidRecord uidRec = uids.valueAt(i); - uidRec.forEachProcess(this::updateAppUidRecIfNecessaryLSP); - } - updateUidsLSP(uids, nowElapsed); - for (int i = 0, size = targetProcesses.size(); i < size; i++) { - applyOomAdjLSP(targetProcesses.valueAt(i), false, now, nowElapsed, oomAdjReason); - } - targetProcesses.clear(); - reachableProcesses.clear(); - - mService.mOomAdjProfiler.oomAdjEnded(); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - return result; - } - - @GuardedBy({"mService", "mProcLock"}) - @Override - protected void updateOomAdjInnerLSP(@OomAdjReason int oomAdjReason, final ProcessRecord topApp, - ArrayList<ProcessRecord> processes, ActiveUids uids, boolean potentialCycles, - boolean startProfiling) { - final boolean fullUpdate = processes == null; - final ArrayList<ProcessRecord> activeProcesses = fullUpdate - ? mProcessList.getLruProcessesLOSP() : processes; - ActiveUids activeUids = uids; - if (activeUids == null) { - final int numUids = mActiveUids.size(); - activeUids = mTmpUidRecords; - activeUids.clear(); - for (int i = 0; i < numUids; i++) { - UidRecord uidRec = mActiveUids.valueAt(i); - activeUids.put(uidRec.getUid(), uidRec); - } - } - - if (startProfiling) { - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason)); - mService.mOomAdjProfiler.oomAdjStarted(); - } - final long now = SystemClock.uptimeMillis(); - final long nowElapsed = SystemClock.elapsedRealtime(); - final long oldTime = now - mConstants.mMaxEmptyTimeMillis; - final int numProc = activeProcesses.size(); - - mAdjSeq++; - if (fullUpdate) { - mNewNumServiceProcs = 0; - mNewNumAServiceProcs = 0; - } - - final ArraySet<ProcessRecord> targetProcesses = mTmpProcessSet; - targetProcesses.clear(); - if (!fullUpdate) { - targetProcesses.addAll(activeProcesses); - } - - performNewUpdateOomAdjLSP(oomAdjReason, topApp, targetProcesses, activeUids, - fullUpdate, now, UNKNOWN_ADJ); - - if (fullUpdate) { - assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP()); - postUpdateOomAdjInnerLSP(oomAdjReason, activeUids, now, nowElapsed, oldTime); - } else { - activeProcesses.clear(); - activeProcesses.addAll(targetProcesses); - assignCachedAdjIfNecessary(activeProcesses); - - for (int i = activeUids.size() - 1; i >= 0; i--) { - final UidRecord uidRec = activeUids.valueAt(i); - uidRec.forEachProcess(this::updateAppUidRecIfNecessaryLSP); - } - updateUidsLSP(activeUids, nowElapsed); - - for (int i = 0, size = targetProcesses.size(); i < size; i++) { - applyOomAdjLSP(targetProcesses.valueAt(i), false, now, nowElapsed, oomAdjReason); - } - - activeProcesses.clear(); - } - targetProcesses.clear(); - - if (startProfiling) { - mService.mOomAdjProfiler.oomAdjEnded(); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - } - return; - } - - /** - * Perform the oom adj update on the given {@code targetProcesses}. - * - * <p>Note: The expectation to the given {@code targetProcesses} is, the caller - * must have called {@link collectReachableProcessesLocked} on it. - */ - private boolean performNewUpdateOomAdjLSP(@OomAdjReason int oomAdjReason, - ProcessRecord topApp, ArraySet<ProcessRecord> targetProcesses, ActiveUids uids, - boolean fullUpdate, long now, int cachedAdj) { - - final ArrayList<ProcessRecord> clientProcesses = mTmpProcessList2; - clientProcesses.clear(); - - // We'll need to collect the upstream processes of the target apps here, because those - // processes would potentially impact the procstate/adj via bindings. - if (!fullUpdate) { - final boolean containsCycle = collectReversedReachableProcessesLocked(targetProcesses, - clientProcesses); - - // If any of its upstream processes are in a cycle, - // move them into the candidate targets. - if (containsCycle) { - // Add all client apps to the target process list. - for (int i = 0, size = clientProcesses.size(); i < size; i++) { - final ProcessRecord client = clientProcesses.get(i); - final UidRecord uidRec = client.getUidRecord(); - targetProcesses.add(client); - if (uidRec != null) { - uids.put(uidRec.getUid(), uidRec); - } - } - clientProcesses.clear(); - } - for (int i = 0, size = targetProcesses.size(); i < size; i++) { - final ProcessRecord app = targetProcesses.valueAt(i); - app.mState.resetCachedInfo(); - final UidRecord uidRec = app.getUidRecord(); - if (uidRec != null) { - if (DEBUG_UID_OBSERVERS) { - Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec); - } - uidRec.reset(); - } - } - } else { - final ArrayList<ProcessRecord> lru = mProcessList.getLruProcessesLOSP(); - for (int i = 0, size = lru.size(); i < size; i++) { - final ProcessRecord app = lru.get(i); - app.mState.resetCachedInfo(); - final UidRecord uidRec = app.getUidRecord(); - if (uidRec != null) { - if (DEBUG_UID_OBSERVERS) { - Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec); - } - uidRec.reset(); - } - } - } - - updateNewOomAdjInnerLSP(oomAdjReason, topApp, targetProcesses, clientProcesses, uids, - cachedAdj, now, fullUpdate); - - clientProcesses.clear(); - - return true; - } - - /** - * Collect the reversed reachable processes from the given {@code apps}, the result will be - * returned in the given {@code processes}, which will <em>NOT</em> include the processes from - * the given {@code apps}. - */ - @GuardedBy("mService") - private boolean collectReversedReachableProcessesLocked(ArraySet<ProcessRecord> apps, - ArrayList<ProcessRecord> clientProcesses) { - final ArrayDeque<ProcessRecord> queue = mTmpQueue; - queue.clear(); - clientProcesses.clear(); - for (int i = 0, size = apps.size(); i < size; i++) { - final ProcessRecord app = apps.valueAt(i); - app.mState.setReachable(true); - app.mState.setReversedReachable(true); - queue.offer(app); - } - - // Track if any of them reachables could include a cycle - boolean containsCycle = false; - - // Scan upstreams of the process record - for (ProcessRecord pr = queue.poll(); pr != null; pr = queue.poll()) { - if (!pr.mState.isReachable()) { - // If not in the given initial set of apps, add it. - clientProcesses.add(pr); - } - final ProcessServiceRecord psr = pr.mServices; - for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) { - final ServiceRecord s = psr.getRunningServiceAt(i); - final ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = - s.getConnections(); - for (int j = serviceConnections.size() - 1; j >= 0; j--) { - final ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(j); - for (int k = clist.size() - 1; k >= 0; k--) { - final ConnectionRecord cr = clist.get(k); - final ProcessRecord client = cr.binding.client; - containsCycle |= client.mState.isReversedReachable(); - if (client.mState.isReversedReachable()) { - continue; - } - queue.offer(client); - client.mState.setReversedReachable(true); - } - } - } - final ProcessProviderRecord ppr = pr.mProviders; - for (int i = ppr.numberOfProviders() - 1; i >= 0; i--) { - final ContentProviderRecord cpr = ppr.getProviderAt(i); - for (int j = cpr.connections.size() - 1; j >= 0; j--) { - final ContentProviderConnection conn = cpr.connections.get(j); - final ProcessRecord client = conn.client; - containsCycle |= client.mState.isReversedReachable(); - if (client.mState.isReversedReachable()) { - continue; - } - queue.offer(client); - client.mState.setReversedReachable(true); - } - } - // If this process is a sandbox itself, also add the app on whose behalf - // its running - if (pr.isSdkSandbox) { - for (int is = psr.numberOfRunningServices() - 1; is >= 0; is--) { - ServiceRecord s = psr.getRunningServiceAt(is); - ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = - s.getConnections(); - for (int conni = serviceConnections.size() - 1; conni >= 0; conni--) { - ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni); - for (int i = clist.size() - 1; i >= 0; i--) { - ConnectionRecord cr = clist.get(i); - ProcessRecord attributedApp = cr.binding.attributedClient; - if (attributedApp == null || attributedApp == pr) { - continue; - } - containsCycle |= attributedApp.mState.isReversedReachable(); - if (attributedApp.mState.isReversedReachable()) { - continue; - } - queue.offer(attributedApp); - attributedApp.mState.setReversedReachable(true); - } - } - } - } - } - - // Reset the temporary bits. - for (int i = clientProcesses.size() - 1; i >= 0; i--) { - clientProcesses.get(i).mState.setReversedReachable(false); - } - for (int i = 0, size = apps.size(); i < size; i++) { - final ProcessRecord app = apps.valueAt(i); - app.mState.setReachable(false); - app.mState.setReversedReachable(false); - } - return containsCycle; - } - - @GuardedBy({"mService", "mProcLock"}) - private void updateNewOomAdjInnerLSP(@OomAdjReason int oomAdjReason, final ProcessRecord topApp, - ArraySet<ProcessRecord> targetProcesses, ArrayList<ProcessRecord> clientProcesses, - ActiveUids uids, int cachedAdj, long now, boolean fullUpdate) { - mTmpOomAdjusterArgs.update(topApp, now, cachedAdj, oomAdjReason, uids, fullUpdate); - - mProcessRecordProcStateNodes.resetLastNodes(); - mProcessRecordAdjNodes.resetLastNodes(); - - final int procStateTarget = mProcessRecordProcStateNodes.size() - 1; - final int adjTarget = mProcessRecordAdjNodes.size() - 1; - - final int appUid = !fullUpdate && targetProcesses.size() > 0 - ? targetProcesses.valueAt(0).uid : -1; - final int logUid = mService.mCurOomAdjUid; - - mAdjSeq++; - // All apps to be updated will be moved to the lowest slot. - if (fullUpdate) { - // Move all the process record node to the lowest slot, we'll do recomputation on all of - // them. Use the processes from the lru list, because the scanning order matters here. - final ArrayList<ProcessRecord> lruList = mProcessList.getLruProcessesLOSP(); - for (int i = procStateTarget; i >= 0; i--) { - mProcessRecordProcStateNodes.reset(i); - // Force the last node to the head since we'll recompute all of them. - mProcessRecordProcStateNodes.setLastNodeToHead(i); - } - // enqueue the targets in the reverse order of the lru list. - for (int i = lruList.size() - 1; i >= 0; i--) { - mProcessRecordProcStateNodes.append(lruList.get(i), procStateTarget); - } - // Do the same to the adj nodes. - for (int i = adjTarget; i >= 0; i--) { - mProcessRecordAdjNodes.reset(i); - // Force the last node to the head since we'll recompute all of them. - mProcessRecordAdjNodes.setLastNodeToHead(i); - } - for (int i = lruList.size() - 1; i >= 0; i--) { - mProcessRecordAdjNodes.append(lruList.get(i), adjTarget); - } - } else { - // Move the target processes to the lowest slot. - for (int i = 0, size = targetProcesses.size(); i < size; i++) { - final ProcessRecord app = targetProcesses.valueAt(i); - final int procStateSlot = processStateToSlot(app.mState.getCurProcState()); - final int adjSlot = adjToSlot(app.mState.getCurRawAdj()); - mProcessRecordProcStateNodes.moveAppTo(app, procStateSlot, procStateTarget); - mProcessRecordAdjNodes.moveAppTo(app, adjSlot, adjTarget); - } - // Move the "lastNode" to head to make sure we scan all nodes in this slot. - mProcessRecordProcStateNodes.setLastNodeToHead(procStateTarget); - mProcessRecordAdjNodes.setLastNodeToHead(adjTarget); - } - - // All apps to be updated have been moved to the lowest slot. - // Do an initial pass of the computation. - mProcessRecordProcStateNodes.forEachNewNode(mProcessRecordProcStateNodes.size() - 1, - this::computeInitialOomAdjLSP); - - if (!fullUpdate) { - // We didn't update the client processes with the computeInitialOomAdjLSP - // because they don't need to do so. But they'll be playing vital roles in - // computing the bindings. So include them into the scan list below. - for (int i = 0, size = clientProcesses.size(); i < size; i++) { - mProcessRecordProcStateNodes.moveAppToTail(clientProcesses.get(i)); - } - // We don't update the adj list since we're resetting it below. - } - - // Now nodes are set into their slots, without facting in the bindings. - // The nodes between the `lastNode` pointer and the TAIL should be the new nodes. - // - // The whole rationale here is that, the bindings from client to host app, won't elevate - // the host app's procstate/adj higher than the client app's state (BIND_ABOVE_CLIENT - // is a special case here, but client app's raw adj is still no less than the host app's). - // Therefore, starting from the top to the bottom, for each slot, scan all of the new nodes, - // check its bindings, elevate its host app's slot if necessary. - // - // We'd have to do this in two passes: 1) scan procstate node list; 2) scan adj node list. - // Because the procstate and adj are not always in sync - there are cases where - // the processes with lower proc state could be getting a higher oom adj score. - // And because of this, the procstate and adj node lists are basically two priority heaps. - // - // As the 2nd pass with the adj node lists potentially includes a significant amount of - // duplicated scans as the 1st pass has done, we'll reset the last node pointers for - // the adj node list before the 1st pass; so during the 1st pass, if any app's adj slot - // gets bumped, we'll only scan those in 2nd pass. - - mProcessRecordAdjNodes.resetLastNodes(); - - // 1st pass, scan each slot in the procstate node list. - for (int i = 0, end = mProcessRecordProcStateNodes.size() - 1; i < end; i++) { - mProcessRecordProcStateNodes.forEachNewNode(i, this::computeHostOomAdjLSP); - } - - // 2nd pass, scan each slot in the adj node list. - for (int i = 0, end = mProcessRecordAdjNodes.size() - 1; i < end; i++) { - mProcessRecordAdjNodes.forEachNewNode(i, this::computeHostOomAdjLSP); - } - } - - @GuardedBy({"mService", "mProcLock"}) - private void computeInitialOomAdjLSP(OomAdjusterArgs args) { - final ProcessRecord app = args.mApp; - final int cachedAdj = args.mCachedAdj; - final ProcessRecord topApp = args.mTopApp; - final long now = args.mNow; - final int oomAdjReason = args.mOomAdjReason; - final ActiveUids uids = args.mUids; - final boolean fullUpdate = args.mFullUpdate; - - if (DEBUG_OOM_ADJ) { - Slog.i(TAG, "OOM ADJ initial args app=" + app - + " cachedAdj=" + cachedAdj - + " topApp=" + topApp - + " now=" + now - + " oomAdjReason=" + oomAdjReasonToString(oomAdjReason) - + " fullUpdate=" + fullUpdate); - } - - if (uids != null) { - final UidRecord uidRec = app.getUidRecord(); - - if (uidRec != null) { - uids.put(uidRec.getUid(), uidRec); - } - } - - computeOomAdjLSP(app, cachedAdj, topApp, fullUpdate, now, false, false, oomAdjReason, - false); - } - - /** - * @return The proposed change to the schedGroup. - */ - @GuardedBy({"mService", "mProcLock"}) - @Override - protected int setIntermediateAdjLSP(ProcessRecord app, int adj, int prevRawAppAdj, - int schedGroup) { - schedGroup = super.setIntermediateAdjLSP(app, adj, prevRawAppAdj, schedGroup); - - updateAdjSlotIfNecessary(app, prevRawAppAdj); - - return schedGroup; - } - - @GuardedBy({"mService", "mProcLock"}) - @Override - protected void setIntermediateProcStateLSP(ProcessRecord app, int procState, - int prevProcState) { - super.setIntermediateProcStateLSP(app, procState, prevProcState); - - updateProcStateSlotIfNecessary(app, prevProcState); - } - - @GuardedBy({"mService", "mProcLock"}) - private void computeHostOomAdjLSP(OomAdjusterArgs args) { - final ProcessRecord app = args.mApp; - final int cachedAdj = args.mCachedAdj; - final ProcessRecord topApp = args.mTopApp; - final long now = args.mNow; - final @OomAdjReason int oomAdjReason = args.mOomAdjReason; - final boolean fullUpdate = args.mFullUpdate; - final ActiveUids uids = args.mUids; - - final ProcessServiceRecord psr = app.mServices; - for (int i = psr.numberOfConnections() - 1; i >= 0; i--) { - ConnectionRecord cr = psr.getConnectionAt(i); - ProcessRecord service = cr.hasFlag(ServiceInfo.FLAG_ISOLATED_PROCESS) - ? cr.binding.service.isolationHostProc : cr.binding.service.app; - if (service == null || service == app - || (service.mState.getMaxAdj() >= SYSTEM_ADJ - && service.mState.getMaxAdj() < FOREGROUND_APP_ADJ) - || (service.mState.getCurAdj() <= FOREGROUND_APP_ADJ - && service.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND - && service.mState.getCurProcState() <= PROCESS_STATE_TOP)) { - continue; - } - - - computeServiceHostOomAdjLSP(cr, service, app, now, topApp, fullUpdate, false, false, - oomAdjReason, cachedAdj, false); - } - - for (int i = psr.numberOfSdkSandboxConnections() - 1; i >= 0; i--) { - final ConnectionRecord cr = psr.getSdkSandboxConnectionAt(i); - final ProcessRecord service = cr.binding.service.app; - if (service == null || service == app - || (service.mState.getMaxAdj() >= SYSTEM_ADJ - && service.mState.getMaxAdj() < FOREGROUND_APP_ADJ) - || (service.mState.getCurAdj() <= FOREGROUND_APP_ADJ - && service.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND - && service.mState.getCurProcState() <= PROCESS_STATE_TOP)) { - continue; - } - - computeServiceHostOomAdjLSP(cr, service, app, now, topApp, fullUpdate, false, false, - oomAdjReason, cachedAdj, false); - } - - final ProcessProviderRecord ppr = app.mProviders; - for (int i = ppr.numberOfProviderConnections() - 1; i >= 0; i--) { - ContentProviderConnection cpc = ppr.getProviderConnectionAt(i); - ProcessRecord provider = cpc.provider.proc; - if (provider == null || provider == app - || (provider.mState.getMaxAdj() >= ProcessList.SYSTEM_ADJ - && provider.mState.getMaxAdj() < FOREGROUND_APP_ADJ) - || (provider.mState.getCurAdj() <= FOREGROUND_APP_ADJ - && provider.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND - && provider.mState.getCurProcState() <= PROCESS_STATE_TOP)) { - continue; - } - - computeProviderHostOomAdjLSP(cpc, provider, app, now, topApp, fullUpdate, false, false, - oomAdjReason, cachedAdj, false); - } - } -} diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 7037fecb2713..f532122c10d9 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -22,7 +22,6 @@ import static com.android.internal.util.Preconditions.checkArgument; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityManagerService.MY_PID; -import static com.android.server.am.OomAdjusterModernImpl.ProcessRecordNode.NUM_NODE_TYPE; import static java.util.Objects.requireNonNull; @@ -64,7 +63,6 @@ import com.android.internal.app.procstats.ProcessState; import com.android.internal.app.procstats.ProcessStats; import com.android.internal.os.Zygote; import com.android.server.FgThread; -import com.android.server.am.OomAdjusterModernImpl.ProcessRecordNode; import com.android.server.wm.WindowProcessController; import com.android.server.wm.WindowProcessListener; @@ -436,8 +434,6 @@ class ProcessRecord implements WindowProcessListener { */ volatile boolean mSkipProcessGroupCreation; - final ProcessRecordNode[] mLinkedNodes = new ProcessRecordNode[NUM_NODE_TYPE]; - void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo, long startUptime, long startElapsedTime) { this.mStartUid = startUid; @@ -1118,7 +1114,6 @@ class ProcessRecord implements WindowProcessListener { mState.onCleanupApplicationRecordLSP(); mServices.onCleanupApplicationRecordLocked(); mReceivers.onCleanupApplicationRecordLocked(); - mService.mOomAdjuster.onProcessEndLocked(this); return mProviders.onCleanupApplicationRecordLocked(allowRestart); } diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java index a165e8897aa4..7ff6d116baaf 100644 --- a/services/core/java/com/android/server/am/ProcessServiceRecord.java +++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java @@ -19,7 +19,6 @@ package com.android.server.am; import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_BOUND_SERVICE; import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_FOREGROUND_SERVICE; -import android.annotation.Nullable; import android.app.ActivityManager; import android.content.Context; import android.content.pm.ServiceInfo; @@ -135,11 +134,6 @@ final class ProcessServiceRecord { private final ArraySet<ConnectionRecord> mConnections = new ArraySet<>(); /** - * All ConnectionRecord this process holds indirectly to SDK sandbox processes. - */ - private @Nullable ArraySet<ConnectionRecord> mSdkSandboxConnections; - - /** * A set of UIDs of all bound clients. */ private ArraySet<Integer> mBoundClientUids = new ArraySet<>(); @@ -496,18 +490,13 @@ final class ProcessServiceRecord { void addConnection(ConnectionRecord connection) { mConnections.add(connection); - addSdkSandboxConnectionIfNecessary(connection); } void removeConnection(ConnectionRecord connection) { mConnections.remove(connection); - removeSdkSandboxConnectionIfNecessary(connection); } void removeAllConnections() { - for (int i = 0, size = mConnections.size(); i < size; i++) { - removeSdkSandboxConnectionIfNecessary(mConnections.valueAt(i)); - } mConnections.clear(); } @@ -519,39 +508,6 @@ final class ProcessServiceRecord { return mConnections.size(); } - private void addSdkSandboxConnectionIfNecessary(ConnectionRecord connection) { - final ProcessRecord attributedClient = connection.binding.attributedClient; - if (attributedClient != null && connection.binding.service.isSdkSandbox) { - if (attributedClient.mServices.mSdkSandboxConnections == null) { - attributedClient.mServices.mSdkSandboxConnections = new ArraySet<>(); - } - attributedClient.mServices.mSdkSandboxConnections.add(connection); - } - } - - private void removeSdkSandboxConnectionIfNecessary(ConnectionRecord connection) { - final ProcessRecord attributedClient = connection.binding.attributedClient; - if (attributedClient != null && connection.binding.service.isSdkSandbox) { - if (attributedClient.mServices.mSdkSandboxConnections == null) { - attributedClient.mServices.mSdkSandboxConnections.remove(connection); - } - } - } - - void removeAllSdkSandboxConnections() { - if (mSdkSandboxConnections != null) { - mSdkSandboxConnections.clear(); - } - } - - ConnectionRecord getSdkSandboxConnectionAt(int index) { - return mSdkSandboxConnections != null ? mSdkSandboxConnections.valueAt(index) : null; - } - - int numberOfSdkSandboxConnections() { - return mSdkSandboxConnections != null ? mSdkSandboxConnections.size() : 0; - } - void addBoundClientUid(int clientUid, String clientPackageName, long bindFlags) { mBoundClientUids.add(clientUid); mApp.getWindowProcessController() diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java index a9c388c232ed..db341d253818 100644 --- a/services/core/java/com/android/server/am/ProcessStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessStateRecord.java @@ -378,12 +378,6 @@ final class ProcessStateRecord { private boolean mReachable; /** - * Whether or not this process is reversed reachable from given process. - */ - @GuardedBy("mService") - private boolean mReversedReachable; - - /** * The most recent time when the last visible activity within this process became invisible. * * <p> It'll be set to 0 if there is never a visible activity, or Long.MAX_VALUE if there is @@ -460,9 +454,6 @@ final class ProcessStateRecord { @GuardedBy("mService") private int mCachedSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND; - @GuardedBy("mService") - private boolean mScheduleLikeTopApp = false; - ProcessStateRecord(ProcessRecord app) { mApp = app; mService = app.mService; @@ -623,11 +614,9 @@ final class ProcessStateRecord { void forceProcessStateUpTo(int newState) { if (mRepProcState > newState) { synchronized (mProcLock) { - final int prevProcState = mRepProcState; setReportedProcState(newState); setCurProcState(newState); setCurRawProcState(newState); - mService.mOomAdjuster.onProcessStateChanged(mApp, prevProcState); } } } @@ -996,16 +985,6 @@ final class ProcessStateRecord { } @GuardedBy("mService") - boolean isReversedReachable() { - return mReversedReachable; - } - - @GuardedBy("mService") - void setReversedReachable(boolean reversedReachable) { - mReversedReachable = reversedReachable; - } - - @GuardedBy("mService") void resetCachedInfo() { mCachedHasActivities = VALUE_INVALID; mCachedIsHeavyWeight = VALUE_INVALID; @@ -1155,16 +1134,6 @@ final class ProcessStateRecord { return mCachedSchedGroup; } - @GuardedBy("mService") - boolean shouldScheduleLikeTopApp() { - return mScheduleLikeTopApp; - } - - @GuardedBy("mService") - void setScheduleLikeTopApp(boolean scheduleLikeTopApp) { - mScheduleLikeTopApp = scheduleLikeTopApp; - } - @GuardedBy(anyOf = {"mService", "mProcLock"}) public String makeAdjReason() { if (mAdjSource != null || mAdjTarget != null) { diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java index 976e74083849..1f4563fb2682 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -105,7 +105,6 @@ import com.android.server.wm.ActivityServiceConnectionsHolder; import com.android.server.wm.ActivityTaskManagerService; import com.android.server.wm.WindowProcessController; -import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -207,10 +206,8 @@ public class MockingOomAdjusterTests { setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object()); doReturn(new ActivityManagerService.ProcessChangeItem()).when(pr) .enqueueProcessChangeItemLocked(anyInt(), anyInt()); - sService.mOomAdjuster = sService.mConstants.ENABLE_NEW_OOMADJ - ? new OomAdjusterModernImpl(sService, sService.mProcessList, - new ActiveUids(sService, false)) - : new OomAdjuster(sService, sService.mProcessList, new ActiveUids(sService, false)); + sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList, + new ActiveUids(sService, false)); sService.mOomAdjuster.mAdjSeq = 10000; sService.mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE); if (sService.mConstants.USE_TIERED_CACHED_ADJ) { @@ -223,11 +220,6 @@ public class MockingOomAdjusterTests { LocalServices.removeServiceForTest(PackageManagerInternal.class); } - @After - public void tearDown() { - sService.mOomAdjuster.resetInternal(); - } - private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) { try { Field field = clazz.getDeclaredField(fieldName); @@ -257,9 +249,6 @@ public class MockingOomAdjusterTests { ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP(); lru.clear(); Collections.addAll(lru, apps); - for (ProcessRecord app : apps) { - sService.mOomAdjuster.onProcessBeginLocked(app); - } } /** @@ -270,7 +259,6 @@ public class MockingOomAdjusterTests { @SuppressWarnings("GuardedBy") private void updateOomAdj(ProcessRecord... apps) { if (apps.length == 1) { - sService.mOomAdjuster.onProcessBeginLocked(apps[0]); sService.mOomAdjuster.updateOomAdjLocked(apps[0], OOM_ADJ_REASON_NONE); } else { setProcessesToLru(apps); @@ -612,13 +600,10 @@ public class MockingOomAdjusterTests { s.lastTopAlmostPerceptibleBindRequestUptimeMs = nowUptime; s.getConnections().clear(); app.mServices.updateHasTopStartedAlmostPerceptibleServices(); - sService.mOomAdjuster.onProcessBeginLocked(system); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); updateOomAdj(app); assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj()); - - sService.mOomAdjuster.resetInternal(); } // Out of grace period but valid binding allows the adjustment. @@ -635,13 +620,10 @@ public class MockingOomAdjusterTests { s.lastTopAlmostPerceptibleBindRequestUptimeMs = nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs; app.mServices.updateHasTopStartedAlmostPerceptibleServices(); - sService.mOomAdjuster.onProcessBeginLocked(system); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); updateOomAdj(app); assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj()); - - sService.mOomAdjuster.resetInternal(); } // Out of grace period and no valid binding so no adjustment. @@ -659,13 +641,10 @@ public class MockingOomAdjusterTests { nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs; s.getConnections().clear(); app.mServices.updateHasTopStartedAlmostPerceptibleServices(); - sService.mOomAdjuster.onProcessBeginLocked(system); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); updateOomAdj(app); assertNotEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj()); - - sService.mOomAdjuster.resetInternal(); } } @@ -678,12 +657,11 @@ public class MockingOomAdjusterTests { MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true)); system.mState.setMaxAdj(PERSISTENT_PROC_ADJ); system.mState.setHasTopUi(true); - sService.mOomAdjuster.onProcessBeginLocked(system); // Simulate the system starting and binding to a service in the app. ServiceRecord s = bindService(app, system, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class)); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - updateOomAdj(system, app); + sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE); assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ + 1, SCHED_GROUP_DEFAULT); @@ -872,7 +850,6 @@ public class MockingOomAdjusterTests { MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); - client.mServices.setTreatLikeActivity(true); bindService(app, client, null, Context.BIND_WAIVE_PRIORITY | Context.BIND_TREAT_LIKE_ACTIVITY, mock(IBinder.class)); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); @@ -1029,7 +1006,7 @@ public class MockingOomAdjusterTests { bindService(app, client, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class)); client.mState.setMaxAdj(PERSISTENT_PROC_ADJ); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - updateOomAdj(client, app); + updateOomAdj(app); assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, app.mState.getSetProcState()); assertNoBfsl(app); @@ -1155,7 +1132,7 @@ public class MockingOomAdjusterTests { assertNoBfsl(app); client.mState.setMaxAdj(PERSISTENT_PROC_ADJ); - updateOomAdj(client, app); + updateOomAdj(app); assertEquals(PERSISTENT_SERVICE_ADJ, app.mState.getSetAdj()); assertBfsl(app); @@ -1171,7 +1148,7 @@ public class MockingOomAdjusterTests { bindService(app, client, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class)); client.mState.setRunningRemoteAnimation(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - updateOomAdj(client, app); + updateOomAdj(app); assertEquals(PERCEPTIBLE_LOW_APP_ADJ, app.mState.getSetAdj()); } @@ -1222,8 +1199,6 @@ public class MockingOomAdjusterTests { updateOomAdj(client, app); assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj()); - - sService.mOomAdjuster.resetInternal(); } { @@ -1242,8 +1217,6 @@ public class MockingOomAdjusterTests { doReturn(false).when(wpc).isHeavyWeightProcess(); assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj()); - - sService.mOomAdjuster.resetInternal(); } { @@ -1256,11 +1229,9 @@ public class MockingOomAdjusterTests { mock(IBinder.class)); client.mState.setMaxAdj(PERSISTENT_PROC_ADJ); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - updateOomAdj(client, app); + sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE); assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj()); - - sService.mOomAdjuster.resetInternal(); } { @@ -1275,12 +1246,10 @@ public class MockingOomAdjusterTests { mock(IBinder.class)); client.mState.setMaxAdj(PERSISTENT_PROC_ADJ); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - updateOomAdj(client, app); + sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE); doReturn(false).when(wpc).isHeavyWeightProcess(); assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj()); - - sService.mOomAdjuster.resetInternal(); } } @@ -1880,7 +1849,7 @@ public class MockingOomAdjusterTests { bindService(app1, client1, null, Context.BIND_SCHEDULE_LIKE_TOP_APP, mock(IBinder.class)); bindService(app2, client2, null, Context.BIND_SCHEDULE_LIKE_TOP_APP, mock(IBinder.class)); - updateOomAdj(client1, client2, app1, app2); + updateOomAdj(app1, app2); assertProcStates(app1, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ, SCHED_GROUP_TOP_APP); @@ -1930,8 +1899,6 @@ public class MockingOomAdjusterTests { s1.getConnections().clear(); s2.getConnections().clear(); - client1.mServices.removeAllConnections(); - client2.mServices.removeAllConnections(); client1.mState.setMaxAdj(UNKNOWN_ADJ); client2.mState.setMaxAdj(UNKNOWN_ADJ); client1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true); @@ -1942,7 +1909,7 @@ public class MockingOomAdjusterTests { bindService(app2, client2, s2, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE, mock(IBinder.class)); - updateOomAdj(client1, client2, app1, app2); + updateOomAdj(app1, app2); // VISIBLE_APP_ADJ is the max oom-adj for BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE. assertProcStates(app1, PROCESS_STATE_FOREGROUND_SERVICE, VISIBLE_APP_ADJ, @@ -1955,7 +1922,7 @@ public class MockingOomAdjusterTests { doReturn(client2).when(sService).getTopApp(); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - updateOomAdj(client2, app2); + sService.mOomAdjuster.updateOomAdjLocked(app2, OOM_ADJ_REASON_NONE); assertProcStates(app2, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ, SCHED_GROUP_DEFAULT); } @@ -2010,7 +1977,6 @@ public class MockingOomAdjusterTests { app.setPendingFinishAttach(true); app.mState.setHasForegroundActivities(false); - sService.mOomAdjuster.onProcessBeginLocked(app); sService.mOomAdjuster.setAttachingProcessStatesLSP(app); updateOomAdj(app); @@ -2025,9 +1991,7 @@ public class MockingOomAdjusterTests { MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); app.setPendingFinishAttach(true); app.mState.setHasForegroundActivities(true); - doReturn(app).when(sService).getTopApp(); - sService.mOomAdjuster.onProcessBeginLocked(app); sService.mOomAdjuster.setAttachingProcessStatesLSP(app); updateOomAdj(app); @@ -2124,7 +2088,7 @@ public class MockingOomAdjusterTests { anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); doNothing().when(sService.mServices) .scheduleServiceTimeoutLocked(any(ProcessRecord.class)); - updateOomAdj(client1, client2, app1, app2, app3); + sService.mOomAdjuster.updateOomAdjLocked(client1, OOM_ADJ_REASON_NONE); assertEquals(PROCESS_STATE_CACHED_EMPTY, client1.mState.getSetProcState()); assertEquals(PROCESS_STATE_SERVICE, app1.mState.getSetProcState()); @@ -2462,8 +2426,6 @@ public class MockingOomAdjusterTests { lru.clear(); lru.add(app2); lru.add(app); - sService.mOomAdjuster.onProcessBeginLocked(app2); - sService.mOomAdjuster.onProcessBeginLocked(app); final ComponentName cn = ComponentName.unflattenFromString( MOCKAPP_PACKAGENAME + "/.TestService"); @@ -2566,7 +2528,7 @@ public class MockingOomAdjusterTests { doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState(); doReturn(app).when(sService).getTopApp(); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - updateOomAdj(app); + sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE); assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj()); |