Merge "Fix issue in proc state ranking in a cycle"
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d114397..3bfd363 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -25,6 +25,7 @@
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
@@ -15711,7 +15712,7 @@
}
private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
- boolean doingAll, long now) {
+ boolean doingAll, long now, boolean cycleReEval) {
if (mAdjSeq == app.adjSeq) {
if (app.adjSeq == app.completedAdjSeq) {
// This adjustment has already been computed successfully.
@@ -15777,20 +15778,21 @@
app.systemNoUi = false;
}
if (!app.systemNoUi) {
- if (mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
- // screen on, promote UI
- app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
- app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
- } else {
- // screen off, restrict UI scheduling
- app.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
- app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
- }
+ if (mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
+ // screen on, promote UI
+ app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
+ app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
+ } else {
+ // screen off, restrict UI scheduling
+ app.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
+ app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
+ }
}
+ app.setCurRawProcState(app.getCurProcState());
app.curAdj = app.maxAdj;
app.completedAdjSeq = app.adjSeq;
// if curAdj is less than prevAppAdj, then this process was promoted
- return app.curAdj < prevAppAdj;
+ return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
}
app.systemNoUi = false;
@@ -16032,8 +16034,13 @@
// By default, we use the computed adjustment. It may be changed if
// there are applications dependent on our services or providers, but
// this gives us a baseline and makes sure we don't get into an
- // infinite recursion.
- app.setCurRawAdj(adj);
+ // infinite recursion. If we're re-evaluating due to cycles, use the previously computed
+ // values.
+ app.setCurRawAdj(!cycleReEval ? adj : Math.min(adj, app.getCurRawAdj()));
+ app.setCurRawProcState(!cycleReEval
+ ? procState
+ : Math.min(procState, app.getCurRawProcState()));
+
app.hasStartedServices = false;
app.adjSeq = mAdjSeq;
@@ -16135,21 +16142,15 @@
boolean trackedProcState = false;
if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
ProcessRecord client = cr.binding.client;
- computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
- if (client.containsCycle) {
- // We've detected a cycle. We should retry computeOomAdjLocked later in
- // case a later-checked connection from a client would raise its
- // priority legitimately.
- app.containsCycle = true;
- // If the client has not been completely evaluated, skip using its
- // priority. Else use the conservative value for now and look for a
- // better state in the next iteration.
- if (client.completedAdjSeq < mAdjSeq) {
- continue;
- }
+ computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now, cycleReEval);
+
+ if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
+ continue;
}
+
int clientAdj = client.getCurRawAdj();
- int clientProcState = client.getCurProcState();
+ int clientProcState = client.getCurRawProcState();
+
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
@@ -16234,6 +16235,7 @@
}
if (adj > newAdj) {
adj = newAdj;
+ app.setCurRawAdj(adj);
adjType = "service";
}
}
@@ -16305,6 +16307,7 @@
}
if (procState > clientProcState) {
procState = clientProcState;
+ app.setCurRawProcState(procState);
if (adjType == null) {
adjType = "service";
}
@@ -16336,6 +16339,7 @@
if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ
&& a.isActivityVisible()) {
adj = ProcessList.FOREGROUND_APP_ADJ;
+ app.setCurRawAdj(adj);
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
schedGroup = ProcessList.SCHED_GROUP_TOP_APP_BOUND;
@@ -16377,21 +16381,15 @@
// Being our own client is not interesting.
continue;
}
- computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
- if (client.containsCycle) {
- // We've detected a cycle. We should retry computeOomAdjLocked later in
- // case a later-checked connection from a client would raise its
- // priority legitimately.
- app.containsCycle = true;
- // If the client has not been completely evaluated, skip using its
- // priority. Else use the conservative value for now and look for a
- // better state in the next iteration.
- if (client.completedAdjSeq < mAdjSeq) {
- continue;
- }
+ computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now, cycleReEval);
+
+ if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
+ continue;
}
+
int clientAdj = client.getCurRawAdj();
- int clientProcState = client.getCurProcState();
+ int clientProcState = client.getCurRawProcState();
+
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.
@@ -16405,6 +16403,7 @@
} else {
adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
+ app.setCurRawAdj(adj);
adjType = "provider";
}
app.cached &= client.cached;
@@ -16440,6 +16439,7 @@
conn.trackProcState(clientProcState, mAdjSeq, now);
if (procState > clientProcState) {
procState = clientProcState;
+ app.setCurRawProcState(procState);
}
if (client.getCurrentSchedulingGroup() > schedGroup) {
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
@@ -16465,6 +16465,7 @@
if (cpr.hasExternalProcessHandles()) {
if (adj > ProcessList.FOREGROUND_APP_ADJ) {
adj = ProcessList.FOREGROUND_APP_ADJ;
+ app.setCurRawAdj(adj);
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.cached = false;
app.adjType = "ext-provider";
@@ -16476,6 +16477,7 @@
}
if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+ app.setCurRawProcState(procState);
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise procstate to external provider: " + app);
@@ -16620,6 +16622,7 @@
app.curAdj = app.modifyRawOomAdj(adj);
app.setCurrentSchedulingGroup(schedGroup);
app.setCurProcState(procState);
+ app.setCurRawProcState(procState);
app.setHasForegroundActivities(foregroundActivities);
app.completedAdjSeq = mAdjSeq;
@@ -16627,6 +16630,44 @@
return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
}
+ /**
+ * Checks if for the given app and client, there's a cycle that should skip over the client
+ * for now or use partial values to evaluate the effect of the client binding.
+ * @param app
+ * @param client
+ * @param procState procstate evaluated so far for this app
+ * @param adj oom_adj evaluated so far for this app
+ * @param cycleReEval whether we're currently re-evaluating due to a cycle, and not the first
+ * evaluation.
+ * @return whether to skip using the client connection at this time
+ */
+ private boolean shouldSkipDueToCycle(ProcessRecord app, ProcessRecord client,
+ int procState, int adj, boolean cycleReEval) {
+ if (client.containsCycle) {
+ // We've detected a cycle. We should retry computeOomAdjLocked later in
+ // case a later-checked connection from a client would raise its
+ // priority legitimately.
+ app.containsCycle = true;
+ // If the client has not been completely evaluated, check if it's worth
+ // using the partial values.
+ if (client.completedAdjSeq < mAdjSeq) {
+ if (cycleReEval) {
+ // If the partial values are no better, skip until the next
+ // attempt
+ if (client.getCurRawProcState() >= procState
+ && client.getCurRawAdj() >= adj) {
+ return true;
+ }
+ // Else use the client's partial procstate and adj to adjust the
+ // effect of the binding
+ } else {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
private static final class RecordPssRunnable implements Runnable {
private final ActivityManagerService mService;
private final ProcessRecord mProc;
@@ -17493,7 +17534,7 @@
return false;
}
- computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now);
+ computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now, false);
return applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
}
@@ -17868,12 +17909,14 @@
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mProcessList.mLruProcesses.get(i);
app.containsCycle = false;
+ app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY);
+ app.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
}
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (!app.killedByAm && app.thread != null) {
app.procStateChanged = false;
- computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
+ computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now, false);
// if any app encountered a cycle, we need to perform an additional loop later
retryCycles |= app.containsCycle;
@@ -17976,8 +18019,8 @@
for (int i=0; i<N; i++) {
ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
-
- if (computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now)) {
+ if (computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now,
+ true)) {
retryCycles = true;
}
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index c4b7150..c15b7c7 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -153,6 +153,7 @@
int trimMemoryLevel; // Last selected memory trimming level
private int mCurProcState = PROCESS_STATE_NONEXISTENT; // Currently computed process state
private int mRepProcState = PROCESS_STATE_NONEXISTENT; // Last reported process state
+ private int mCurRawProcState = PROCESS_STATE_NONEXISTENT; // Temp state during computation
int setProcState = PROCESS_STATE_NONEXISTENT; // Last set process state in process tracker
int pssProcState = PROCESS_STATE_NONEXISTENT; // Currently requesting pss for
int pssStatType; // The type of stat collection that we are currently requesting
@@ -902,6 +903,7 @@
if (mRepProcState > newState) {
mRepProcState = newState;
setCurProcState(newState);
+ setCurRawProcState(newState);
for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
StatsLog.write(StatsLog.PROCESS_STATE_CHANGED,
uid, processName, pkgList.keyAt(ipkg),
@@ -984,6 +986,14 @@
return mCurProcState;
}
+ void setCurRawProcState(int curRawProcState) {
+ mCurRawProcState = curRawProcState;
+ }
+
+ int getCurRawProcState() {
+ return mCurRawProcState;
+ }
+
void setReportedProcState(int repProcState) {
mRepProcState = repProcState;
for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {