Don't allow more than 3 actively running users at a time.

Change-Id: Ic047c62b518a0faaa7b507343909330044ec290b
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index ce5424b..b77eb59 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -253,6 +253,9 @@
     // giving up on them and unfreezing the screen.
     static final int USER_SWITCH_TIMEOUT = 2*1000;
 
+    // Maximum number of users we allow to be running at a time.
+    static final int MAX_RUNNING_USERS = 3;
+
     static final int MY_PID = Process.myPid();
     
     static final String[] EMPTY_STRING_ARRAY = new String[0];
@@ -14123,6 +14126,33 @@
                         android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
                         false, false, MY_PID, Process.SYSTEM_UID, userId);
             }
+            int num = mUserLru.size();
+            int i = 0;
+            while (num > MAX_RUNNING_USERS && i < mUserLru.size()) {
+                Integer oldUserId = mUserLru.get(i);
+                UserStartedState oldUss = mStartedUsers.get(oldUserId);
+                if (oldUss == null) {
+                    // Shouldn't happen, but be sane if it does.
+                    mUserLru.remove(i);
+                    num--;
+                    continue;
+                }
+                if (oldUss.mState == UserStartedState.STATE_STOPPING) {
+                    // This user is already stopping, doesn't count.
+                    num--;
+                    i++;
+                    continue;
+                }
+                if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId) {
+                    // Owner and current can't be stopped, but count as running.
+                    i++;
+                    continue;
+                }
+                // This is a user to be stopped.
+                stopUserLocked(oldUserId, null);
+                num--;
+                i++;
+            }
         }
     }
 
@@ -14141,52 +14171,56 @@
             throw new IllegalArgumentException("Can't stop primary user " + userId);
         }
         synchronized (this) {
-            if (mCurrentUserId == userId) {
-                return ActivityManager.USER_OP_IS_CURRENT;
-            }
+            return stopUserLocked(userId, callback);
+        }
+    }
 
-            final UserStartedState uss = mStartedUsers.get(userId);
-            if (uss == null) {
-                // User is not started, nothing to do...  but we do need to
-                // callback if requested.
-                if (callback != null) {
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            try {
-                                callback.userStopped(userId);
-                            } catch (RemoteException e) {
-                            }
-                        }
-                    });
-                }
-                return ActivityManager.USER_OP_SUCCESS;
-            }
+    private int stopUserLocked(final int userId, final IStopUserCallback callback) {
+        if (mCurrentUserId == userId) {
+            return ActivityManager.USER_OP_IS_CURRENT;
+        }
 
+        final UserStartedState uss = mStartedUsers.get(userId);
+        if (uss == null) {
+            // User is not started, nothing to do...  but we do need to
+            // callback if requested.
             if (callback != null) {
-                uss.mStopCallbacks.add(callback);
-            }
-
-            if (uss.mState != UserStartedState.STATE_STOPPING) {
-                uss.mState = UserStartedState.STATE_STOPPING;
-
-                long ident = Binder.clearCallingIdentity();
-                try {
-                    // Inform of user switch
-                    Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
-                    final IIntentReceiver resultReceiver = new IIntentReceiver.Stub() {
-                        @Override
-                        public void performReceive(Intent intent, int resultCode, String data,
-                                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
-                            finishUserStop(uss);
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            callback.userStopped(userId);
+                        } catch (RemoteException e) {
                         }
-                    };
-                    broadcastIntentLocked(null, null, intent,
-                            null, resultReceiver, 0, null, null, null,
-                            true, false, MY_PID, Process.SYSTEM_UID, userId);
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
+                    }
+                });
+            }
+            return ActivityManager.USER_OP_SUCCESS;
+        }
+
+        if (callback != null) {
+            uss.mStopCallbacks.add(callback);
+        }
+
+        if (uss.mState != UserStartedState.STATE_STOPPING) {
+            uss.mState = UserStartedState.STATE_STOPPING;
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                // Inform of user switch
+                Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
+                final IIntentReceiver resultReceiver = new IIntentReceiver.Stub() {
+                    @Override
+                    public void performReceive(Intent intent, int resultCode, String data,
+                            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
+                        finishUserStop(uss);
+                    }
+                };
+                broadcastIntentLocked(null, null, intent,
+                        null, resultReceiver, 0, null, null, null,
+                        true, false, MY_PID, Process.SYSTEM_UID, userId);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
         }
 
@@ -14206,6 +14240,7 @@
                 stopped = true;
                 // User can no longer run.
                 mStartedUsers.remove(userId);
+                mUserLru.remove(Integer.valueOf(userId));
 
                 // Clean up all state and processes associated with the user.
                 // Kill all the processes for the user.