Add new OOM adjustment for the "previous" process.

This is the process that you had previously been interacting with
in the UI before the current one.  Treating it specially should
allow us to improve the scenario of switching back and forth
between two apps.

Also add API constent for ICS MR1.

Change-Id: Ib3fe4df36b270be11dfd6b7e8d107c9994058a4d
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index f8a7d6a..310ace0 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -408,6 +408,12 @@
     ProcessRecord mHomeProcess;
     
     /**
+     * This is the process holding the activity the user last visited that
+     * is in a different process from the one they are currently in.
+     */
+    ProcessRecord mPreviousProcess;
+    
+    /**
      * Packages that the user has asked to have run in screen size
      * compatibility mode instead of filling the screen.
      */
@@ -8114,6 +8120,7 @@
 
         pw.println();
         pw.println("  mHomeProcess: " + mHomeProcess);
+        pw.println("  mPreviousProcess: " + mPreviousProcess);
         if (mHeavyWeightProcess != null) {
             pw.println("  mHeavyWeightProcess: " + mHeavyWeightProcess);
         }
@@ -8212,6 +8219,7 @@
             pw.print("    BACKUP_APP_ADJ: "); pw.println(ProcessList.BACKUP_APP_ADJ);
             pw.print("    SERVICE_ADJ: "); pw.println(ProcessList.SERVICE_ADJ);
             pw.print("    HOME_APP_ADJ: "); pw.println(ProcessList.HOME_APP_ADJ);
+            pw.print("    PREVIOUS_APP_ADJ: "); pw.println(ProcessList.PREVIOUS_APP_ADJ);
             pw.print("    SERVICE_B_ADJ: "); pw.println(ProcessList.SERVICE_B_ADJ);
             pw.print("    HIDDEN_APP_MIN_ADJ: "); pw.println(ProcessList.HIDDEN_APP_MIN_ADJ);
             pw.print("    HIDDEN_APP_MAX_ADJ: "); pw.println(ProcessList.HIDDEN_APP_MAX_ADJ);
@@ -8228,6 +8236,7 @@
 
         pw.println();
         pw.println("  mHomeProcess: " + mHomeProcess);
+        pw.println("  mPreviousProcess: " + mPreviousProcess);
         if (mHeavyWeightProcess != null) {
             pw.println("  mHeavyWeightProcess: " + mHeavyWeightProcess);
         }
@@ -9009,6 +9018,8 @@
                 oomAdj = buildOomTag("bak", "  ", r.setAdj, ProcessList.HIDDEN_APP_MIN_ADJ);
             } else if (r.setAdj >= ProcessList.SERVICE_B_ADJ) {
                 oomAdj = buildOomTag("svcb ", null, r.setAdj, ProcessList.SERVICE_B_ADJ);
+            } else if (r.setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
+                oomAdj = buildOomTag("prev ", null, r.setAdj, ProcessList.PREVIOUS_APP_ADJ);
             } else if (r.setAdj >= ProcessList.HOME_APP_ADJ) {
                 oomAdj = buildOomTag("home ", null, r.setAdj, ProcessList.HOME_APP_ADJ);
             } else if (r.setAdj >= ProcessList.SERVICE_ADJ) {
@@ -9287,12 +9298,13 @@
             ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.FOREGROUND_APP_ADJ,
             ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
             ProcessList.BACKUP_APP_ADJ, ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
-            ProcessList.SERVICE_B_ADJ, ProcessList.HIDDEN_APP_MAX_ADJ
+            ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.HIDDEN_APP_MAX_ADJ
         };
         final String[] oomLabel = new String[] {
                 "System", "Persistent", "Foreground",
                 "Visible", "Perceptible", "Heavy Weight",
-                "Backup", "A Services", "Home", "B Services", "Background"
+                "Backup", "A Services", "Home", "Previous",
+                "B Services", "Background"
         };
         long oomPss[] = new long[oomLabel.length];
         ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])new ArrayList[oomLabel.length];
@@ -9714,7 +9726,10 @@
         if (app == mHomeProcess) {
             mHomeProcess = null;
         }
-        
+        if (app == mPreviousProcess) {
+            mPreviousProcess = null;
+        }
+
         if (restart) {
             // We have components that still need to be running in the
             // process, so re-launch it.
@@ -13112,6 +13127,17 @@
             app.adjType = "home";
         }
 
+        if (adj > ProcessList.PREVIOUS_APP_ADJ && app == mPreviousProcess
+                && app.activities.size() > 0) {
+            // This was the previous process that showed UI to the user.
+            // We want to try to keep it around more aggressively, to give
+            // a good experience around switching between two apps.
+            adj = ProcessList.PREVIOUS_APP_ADJ;
+            schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+            app.hidden = false;
+            app.adjType = "previous";
+        }
+
         if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj
                 + " reason=" + app.adjType);
 
@@ -13841,7 +13867,8 @@
                     } else {
                         numBg++;
                     }
-                } else if (app.curAdj >= ProcessList.HOME_APP_ADJ) {
+                } else if (app.curAdj >= ProcessList.HOME_APP_ADJ
+                        && app.curAdj != ProcessList.SERVICE_B_ADJ) {
                     numBg++;
                 }
             }