diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 30674db484d5c..0591704a05021 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -306,7 +306,7 @@ public final class OomAdjuster { @GuardedBy("mService") void updateOomAdjLocked(String oomAdjReason) { final ProcessRecord topApp = mService.getTopAppLocked(); - updateOomAdjLockedInner(oomAdjReason, topApp , null, null, true); + updateOomAdjLockedInner(oomAdjReason, topApp , null, null, true, true); } /** @@ -361,8 +361,10 @@ public final class OomAdjuster { uids.clear(); queue.clear(); - // borrow the "containsCycle" flag to mark it being scanned - app.containsCycle = true; + // Track if any of them reachables could include a cycle + boolean containsCycle = false; + // Scan downstreams of the process record + app.mReachable = true; for (ProcessRecord pr = app; pr != null; pr = queue.poll()) { if (pr != app) { processes.add(pr); @@ -374,7 +376,7 @@ public final class OomAdjuster { ConnectionRecord cr = pr.connections.valueAt(i); ProcessRecord service = (cr.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0 ? cr.binding.service.isolatedProc : cr.binding.service.app; - if (service == null || service.containsCycle) { + if (service == null || service == pr || (containsCycle |= service.mReachable)) { continue; } if ((cr.flags & (Context.BIND_WAIVE_PRIORITY @@ -384,21 +386,21 @@ public final class OomAdjuster { continue; } queue.offer(service); - service.containsCycle = true; + service.mReachable = true; } for (int i = pr.conProviders.size() - 1; i >= 0; i--) { ContentProviderConnection cpc = pr.conProviders.get(i); ProcessRecord provider = cpc.provider.proc; - if (provider == null || provider.containsCycle) { + if (provider == null || provider == pr || (containsCycle |= provider.mReachable)) { continue; } queue.offer(provider); - provider.containsCycle = true; + provider.mReachable = true; } } // Reset the flag - app.containsCycle = false; + app.mReachable = false; int size = processes.size(); if (size > 0) { // Reverse the process list, since the updateOomAdjLockedInner scans from the end of it. @@ -409,7 +411,7 @@ public final class OomAdjuster { } mAdjSeq--; // Update these reachable processes - updateOomAdjLockedInner(oomAdjReason, topApp, processes, uids, false); + updateOomAdjLockedInner(oomAdjReason, topApp, processes, uids, containsCycle, false); } else if (app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ) { // In case the app goes from non-cached to cached but it doesn't have other reachable // processes, its adj could be still unknown as of now, assign one. @@ -430,7 +432,8 @@ public final class OomAdjuster { */ @GuardedBy("mService") private void updateOomAdjLockedInner(String oomAdjReason, final ProcessRecord topApp, - ArrayList processes, ActiveUids uids, boolean startProfiling) { + ArrayList processes, ActiveUids uids, boolean potentialCycles, + boolean startProfiling) { if (startProfiling) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason); mService.mOomAdjProfiler.oomAdjStarted(); @@ -474,11 +477,13 @@ public final class OomAdjuster { } boolean retryCycles = false; + boolean computeClients = fullUpdate || potentialCycles; // need to reset cycle state before calling computeOomAdjLocked because of service conns for (int i = numProc - 1; i >= 0; i--) { ProcessRecord app = activeProcesses.get(i); app.containsCycle = false; + app.mReachable = false; app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY); app.setCurRawAdj(ProcessList.UNKNOWN_ADJ); app.setCapability = PROCESS_CAPABILITY_NONE; @@ -489,7 +494,7 @@ public final class OomAdjuster { if (!app.killedByAm && app.thread != null) { app.procStateChanged = false; computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, topApp, fullUpdate, now, false, - fullUpdate); // It won't enter cycle if not computing clients. + 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 |= app.containsCycle; // Keep the completedAdjSeq to up to date. @@ -499,7 +504,7 @@ public final class OomAdjuster { assignCachedAdjIfNecessary(mProcessList.mLruProcesses); - if (fullUpdate) { // There won't be cycles if we didn't compute clients above. + if (computeClients) { // There won't be cycles if we didn't compute clients above. // Cycle strategy: // - Retry computing any process that has encountered a cycle. // - Continue retrying until no process was promoted. diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 1e0693f365e7a..5db6ff79b00f0 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -327,6 +327,8 @@ class ProcessRecord implements WindowProcessListener { int mCachedProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; int mCachedSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND; + boolean mReachable; // Whether or not this process is reachable from given process + void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo, long startTime) { this.startUid = startUid; 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 e7f6a7484881c..6c09239251bd9 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -1027,11 +1027,28 @@ public class MockingOomAdjusterTests { bindService(client, client2, null, 0, mock(IBinder.class)); client2.setHasForegroundServices(true, 0); bindService(client2, app, null, 0, mock(IBinder.class)); + ArrayList lru = sService.mProcessList.mLruProcesses; + lru.clear(); + lru.add(app); + lru.add(client); + lru.add(client2); sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE; - sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(app, true, OomAdjuster.OOM_ADJ_REASON_NONE); assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ, SCHED_GROUP_DEFAULT); + assertProcStates(client, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ, + SCHED_GROUP_DEFAULT); + assertProcStates(client2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ, + SCHED_GROUP_DEFAULT); + + client2.setHasForegroundServices(false, 0); + sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE; + sService.mOomAdjuster.updateOomAdjLocked(client2, true, OomAdjuster.OOM_ADJ_REASON_NONE); + + assertEquals(PROCESS_STATE_CACHED_EMPTY, client2.setProcState); + assertEquals(PROCESS_STATE_CACHED_EMPTY, client.setProcState); + assertEquals(PROCESS_STATE_CACHED_EMPTY, app.setProcState); } @SuppressWarnings("GuardedBy")