Merge "Special handling of processes with recent tasks."
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 064e978..02b7f8c 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -519,11 +519,15 @@
* process that contains activities. */
public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 16;
+ /** @hide Process is being cached for later use and has an activity that corresponds
+ * to an existing recent task. */
+ public static final int PROCESS_STATE_CACHED_RECENT = 17;
+
/** @hide Process is being cached for later use and is empty. */
- public static final int PROCESS_STATE_CACHED_EMPTY = 17;
+ public static final int PROCESS_STATE_CACHED_EMPTY = 18;
/** @hide Process does not exist. */
- public static final int PROCESS_STATE_NONEXISTENT = 18;
+ public static final int PROCESS_STATE_NONEXISTENT = 19;
// NOTE: If PROCESS_STATEs are added or changed, then new fields must be added
// to frameworks/base/core/proto/android/app/activitymanager.proto and the following method must
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index 7519fce..fbdf17d 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -102,6 +102,7 @@
STATE_LAST_ACTIVITY, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
STATE_CACHED_ACTIVITY, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
STATE_CACHED_ACTIVITY_CLIENT, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+ STATE_CACHED_ACTIVITY, // ActivityManager.PROCESS_STATE_CACHED_RECENT
STATE_CACHED_EMPTY, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
};
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 26d871f..0a6f976 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3325,7 +3325,7 @@
String what, Object obj, ProcessRecord srcApp) {
app.lastActivityTime = now;
- if (app.activities.size() > 0) {
+ if (app.activities.size() > 0 || app.recentTasks.size() > 0) {
// Don't want to touch dependent processes that are hosting activities.
return index;
}
@@ -3389,7 +3389,7 @@
final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
ProcessRecord client) {
final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities
- || app.treatLikeActivity;
+ || app.treatLikeActivity || app.recentTasks.size() > 0;
final boolean hasService = false; // not impl yet. app.services.size() > 0;
if (!activityChange && hasActivity) {
// The process has activities, so we are only allowing activity-based adjustments
@@ -3493,7 +3493,8 @@
int nextIndex;
if (hasActivity) {
final int N = mLruProcesses.size();
- if (app.activities.size() == 0 && mLruProcessActivityStart < (N - 1)) {
+ if ((app.activities.size() == 0 || app.recentTasks.size() > 0)
+ && mLruProcessActivityStart < (N - 1)) {
// Process doesn't have activities, but has clients with
// activities... move it up, but one below the top (the top
// should always have a real activity).
@@ -5330,6 +5331,8 @@
// Remove this application's activities from active lists.
boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);
+ app.clearRecentTasks();
+
app.activities.clear();
if (app.instr != null) {
@@ -21022,7 +21025,7 @@
+ " instead of expected " + app);
if (r.app == null || (r.app.uid == app.uid)) {
// Only fix things up when they look sane
- r.app = app;
+ r.setProcess(app);
} else {
continue;
}
@@ -21101,6 +21104,11 @@
adj += minLayer;
}
}
+ if (procState > ActivityManager.PROCESS_STATE_CACHED_RECENT && app.recentTasks.size() > 0) {
+ procState = ActivityManager.PROCESS_STATE_CACHED_RECENT;
+ app.adjType = "cch-rec";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to cached recent: " + app);
+ }
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
|| procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
@@ -22661,6 +22669,7 @@
switch (app.curProcState) {
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ case ActivityManager.PROCESS_STATE_CACHED_RECENT:
// This process is a cached process holding activities...
// assign it the next cached value for that type, and then
// step that cached level.
@@ -23385,7 +23394,7 @@
// has been removed.
for (i=mRemovedProcesses.size()-1; i>=0; i--) {
final ProcessRecord app = mRemovedProcesses.get(i);
- if (app.activities.size() == 0
+ if (app.activities.size() == 0 && app.recentTasks.size() == 0
&& app.curReceivers.isEmpty() && app.services.size() == 0) {
Slog.i(
TAG, "Exiting empty application process "
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 9a16745..2e76471 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -934,6 +934,14 @@
}
}
+ void setProcess(ProcessRecord proc) {
+ app = proc;
+ final ActivityRecord root = task != null ? task.getRootActivity() : null;
+ if (root == this) {
+ task.setRootProcess(proc);
+ }
+ }
+
AppWindowContainerController getWindowContainerController() {
return mWindowContainerController;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 745e9fb..b015bcf 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1270,7 +1270,7 @@
// schedule launch ticks to collect information about slow apps.
r.startLaunchTickingLocked();
- r.app = app;
+ r.setProcess(app);
if (mKeyguardController.isKeyguardLocked()) {
r.notifyUnknownVisibilityLaunched();
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 7810c5e..1a19601 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -400,6 +400,9 @@
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
procState = "CACC";
break;
+ case ActivityManager.PROCESS_STATE_CACHED_RECENT:
+ procState = "CRE ";
+ break;
case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
procState = "CEM ";
break;
@@ -494,6 +497,7 @@
PROC_MEM_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
PROC_MEM_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
PROC_MEM_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+ PROC_MEM_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
PROC_MEM_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
};
@@ -515,6 +519,7 @@
PSS_FIRST_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
PSS_FIRST_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
PSS_FIRST_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+ PSS_FIRST_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_RECENT
PSS_FIRST_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
};
@@ -536,6 +541,7 @@
PSS_SAME_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
PSS_SAME_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
PSS_SAME_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+ PSS_SAME_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_RECENT
PSS_SAME_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
};
@@ -557,6 +563,7 @@
PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+ PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_RECENT
PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
};
@@ -578,6 +585,7 @@
PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+ PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_RECENT
PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
};
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index e847723..9d3c2ae 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -164,6 +164,8 @@
// all activities running in the process
final ArrayList<ActivityRecord> activities = new ArrayList<>();
+ // any tasks this process had run root activities in
+ final ArrayList<TaskRecord> recentTasks = new ArrayList<>();
// all ServiceRecord running in this process
final ArraySet<ServiceRecord> services = new ArraySet<>();
// services that are currently executing code (need to remain foreground).
@@ -396,6 +398,12 @@
pw.print(prefix); pw.print(" - "); pw.println(activities.get(i));
}
}
+ if (recentTasks.size() > 0) {
+ pw.print(prefix); pw.println("Recent Tasks:");
+ for (int i=0; i<recentTasks.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(recentTasks.get(i));
+ }
+ }
if (services.size() > 0) {
pw.print(prefix); pw.println("Services:");
for (int i=0; i<services.size(); i++) {
@@ -512,6 +520,13 @@
}
}
+ public void clearRecentTasks() {
+ for (int i = recentTasks.size() - 1; i >= 0; i--) {
+ recentTasks.get(i).clearRootProcess();
+ }
+ recentTasks.clear();
+ }
+
/**
* This method returns true if any of the activities within the process record are interesting
* to the user. See HistoryRecord.isInterestingToUserLocked()
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 949f51f..a9c6eee 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -257,6 +257,11 @@
/** Current stack. Setter must always be used to update the value. */
private ActivityStack mStack;
+ /** The process that had previously hosted the root activity of this task.
+ * Used to know that we should try harder to keep this process around, in case the
+ * user wants to return to it. */
+ private ProcessRecord mRootProcess;
+
/** Takes on same value as first root activity */
boolean isPersistable = false;
int maxRecents;
@@ -962,6 +967,8 @@
mService.notifyTaskPersisterLocked(this, false);
}
+ clearRootProcess();
+
// TODO: Use window container controller once tasks are better synced between AM and WM
mService.mWindowManager.notifyTaskRemovedFromRecents(taskId, userId);
}
@@ -2114,6 +2121,22 @@
}
}
+ void setRootProcess(ProcessRecord proc) {
+ clearRootProcess();
+ if (intent != null &&
+ (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
+ mRootProcess = proc;
+ proc.recentTasks.add(this);
+ }
+ }
+
+ void clearRootProcess() {
+ if (mRootProcess != null) {
+ mRootProcess.recentTasks.remove(this);
+ mRootProcess = null;
+ }
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("userId="); pw.print(userId);
pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
@@ -2198,6 +2221,9 @@
if (lastDescription != null) {
pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
}
+ if (mRootProcess != null) {
+ pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess);
+ }
pw.print(prefix); pw.print("stackId="); pw.println(getStackId());
pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));