Fix issue #2619247: Music sometimes stops playing when navigation talks

When a service transitions from foreground to background, we now push it
to the top of the LRU list.  Also fix the activity manager to take care
of killing processes if we go beyond a reasonable number of background
process to keep around.

Change-Id: Ic9f44c02af7a111ee6f1d06142386b301948bafe
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 7e095b5..436bd17 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -315,6 +315,11 @@
     // without empty apps being able to push them out of memory.
     static final int MIN_HIDDEN_APPS = 2;
     
+    // The maximum number of hidden processes we will keep around before
+    // killing them; this is just a control to not let us go too crazy with
+    // keeping around processes on devices with large amounts of RAM.
+    static final int MAX_HIDDEN_APPS = 15;
+    
     // We put empty content processes after any hidden processes that have
     // been idle for less than 30 seconds.
     static final long CONTENT_APP_IDLE_OFFSET = 30*1000;
@@ -8488,8 +8493,7 @@
                 }
                 int adj = proc.setAdj;
                 if (adj >= worstType) {
-                    Slog.w(TAG, "Killing " + reason + " : " + proc + " (adj "
-                            + adj + ")");
+                    Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
                     EventLog.writeEvent(EventLogTags.AM_KILL, proc.pid,
                             proc.processName, adj, reason);
                     killed = true;
@@ -8904,9 +8908,10 @@
             }
             if (app.pid > 0 && app.pid != MY_PID) {
                 handleAppCrashLocked(app);
-                Slog.i(ActivityManagerService.TAG, "Killing process "
-                        + app.processName
-                        + " (pid=" + app.pid + ") at user's request");
+                Slog.i(ActivityManagerService.TAG, "Killing "
+                        + app.processName + " (pid=" + app.pid + "): user's request");
+                EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                        app.processName, app.setAdj, "user's request after error");
                 Process.killProcess(app.pid);
             }
         }
@@ -10434,10 +10439,11 @@
             if (!capp.persistent && capp.thread != null
                     && capp.pid != 0
                     && capp.pid != MY_PID) {
-                Slog.i(TAG, "Killing app " + capp.processName
-                        + " (pid " + capp.pid
-                        + ") because provider " + cpr.info.name
-                        + " is in dying process " + proc.processName);
+                Slog.i(TAG, "Kill " + capp.processName
+                        + " (pid " + capp.pid + "): provider " + cpr.info.name
+                        + " in dying process " + proc.processName);
+                EventLog.writeEvent(EventLogTags.AM_KILL, capp.pid,
+                        capp.processName, capp.setAdj, "dying provider " + proc.processName);
                 Process.killProcess(capp.pid);
             }
         }
@@ -11522,6 +11528,7 @@
                     if (r.isForeground) {
                         r.isForeground = false;
                         if (r.app != null) {
+                            updateLruProcessLocked(r.app, false, true);
                             updateServiceForegroundLocked(r.app, true);
                         }
                     }
@@ -14244,6 +14251,7 @@
         int factor = (mLruProcesses.size()-4)/numSlots;
         if (factor < 1) factor = 1;
         int step = 0;
+        int numHidden = 0;
         
         // First try updating the OOM adjustment for each of the
         // application processes based on their current state.
@@ -14262,6 +14270,17 @@
                         curHiddenAdj++;
                     }
                 }
+                if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
+                    numHidden++;
+                    if (numHidden > MAX_HIDDEN_APPS) {
+                        Slog.i(TAG, "Kill " + app.processName
+                                + " (pid " + app.pid + "): hidden #" + numHidden
+                                + " beyond limit " + MAX_HIDDEN_APPS);
+                        EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                                app.processName, app.setAdj, "too many background");
+                        Process.killProcess(app.pid);
+                    }
+                }
             } else {
                 didOomAdj = false;
             }