Make it possible to remove current user

Due to the async nature of switching users, it's not possible to
switch and remove immediately. So mark the switch target user as
soon as the user switch is requested, so that a remove will proceed
without failing at stopUserLocked().

Also, fix a similar problem with deleting the current guest and
switching to a new guest. It was attempting to remove the current
user which will result in a failed stopping of the user.
Added a way to mark the current guest
for deletion so that a new one can be created, switched to and the
old one deleted. If runtime fails, old guest is already marked for
deletion and will be cleaned up on restart.

Bug: 17321533
Change-Id: I4be0fb956227e0bb95588b5b1f2867fb1e655c0d
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 2929939..4a2cece 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -519,7 +519,7 @@
         for (int i = 0; i < totalUserCount; i++) {
             UserInfo user = mUsers.valueAt(i);
             if (!mRemovingUserIds.get(user.id)
-                    && !user.isGuest()) {
+                    && !user.isGuest() && !user.partial) {
                 aliveUserCount++;
             }
         }
@@ -1180,6 +1180,47 @@
     }
 
     /**
+     * Mark this guest user for deletion to allow us to create another guest
+     * and switch to that user before actually removing this guest.
+     * @param userHandle the userid of the current guest
+     * @return whether the user could be marked for deletion
+     */
+    public boolean markGuestForDeletion(int userHandle) {
+        checkManageUsersPermission("Only the system can remove users");
+        if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(
+                UserManager.DISALLOW_REMOVE_USER, false)) {
+            Log.w(LOG_TAG, "Cannot remove user. DISALLOW_REMOVE_USER is enabled.");
+            return false;
+        }
+
+        long ident = Binder.clearCallingIdentity();
+        try {
+            final UserInfo user;
+            synchronized (mPackagesLock) {
+                user = mUsers.get(userHandle);
+                if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {
+                    return false;
+                }
+                if (!user.isGuest()) {
+                    return false;
+                }
+                // Set this to a partially created user, so that the user will be purged
+                // on next startup, in case the runtime stops now before stopping and
+                // removing the user completely.
+                user.partial = true;
+                // Mark it as disabled, so that it isn't returned any more when
+                // profiles are queried.
+                user.flags |= UserInfo.FLAG_DISABLED;
+                user.flags &= ~UserInfo.FLAG_GUEST;
+                writeUserLocked(user);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+        return true;
+    }
+
+    /**
      * Removes a user and all data directories created for that user. This method should be called
      * after the user's processes have been terminated.
      * @param userHandle the user's id