More thorough cleansing of expired users

If any /data/system_[c|d]e folders were not erased
when the user was removed (maybe due to a reboot),
make sure they're cleaned up on restart as well
as when the userId is recycled later.

Mark the users' system folders with the correct
serial number for later verification.

AccountManager shouldn't be querying accounts of
partially created/destroyed users.

Change-Id: I4313756b7464f34cd5ce4fb296d61daa50b41fcb
Fixes: 29285673
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a8cf110..a85064b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -65,6 +65,8 @@
 import android.os.UserManagerInternal;
 import android.os.UserManagerInternal.UserRestrictionsListener;
 import android.os.storage.StorageManager;
+import android.security.GateKeeper;
+import android.service.gatekeeper.IGateKeeperService;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
@@ -87,6 +89,7 @@
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
+import com.android.server.SystemService;
 import com.android.server.am.UserState;
 
 import libcore.io.IoUtils;
@@ -119,6 +122,7 @@
  * </ul>
  */
 public class UserManagerService extends IUserManager.Stub {
+
     private static final String LOG_TAG = "UserManagerService";
     static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
     private static final boolean DBG_WITH_STACKTRACE = false; // DO NOT SUBMIT WITH TRUE
@@ -367,6 +371,31 @@
         }
     }
 
+    public static class LifeCycle extends SystemService {
+
+        private UserManagerService mUms;
+
+        /**
+         * @param context
+         */
+        public LifeCycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mUms = UserManagerService.getInstance();
+            publishBinderService(Context.USER_SERVICE, mUms);
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+                mUms.cleanupPartialUsers();
+            }
+        }
+    }
+
     @VisibleForTesting
     UserManagerService(File dataDir) {
         this(null, null, new Object(), dataDir);
@@ -408,25 +437,6 @@
     }
 
     void systemReady() {
-        // Prune out any partially created, partially removed and ephemeral users.
-        ArrayList<UserInfo> partials = new ArrayList<>();
-        synchronized (mUsersLock) {
-            final int userSize = mUsers.size();
-            for (int i = 0; i < userSize; i++) {
-                UserInfo ui = mUsers.valueAt(i).info;
-                if ((ui.partial || ui.guestToRemove || ui.isEphemeral()) && i != 0) {
-                    partials.add(ui);
-                }
-            }
-        }
-        final int partialsSize = partials.size();
-        for (int i = 0; i < partialsSize; i++) {
-            UserInfo ui = partials.get(i);
-            Slog.w(LOG_TAG, "Removing partially created user " + ui.id
-                    + " (name=" + ui.name + ")");
-            removeUserState(ui.id);
-        }
-
         mAppOpsService = IAppOpsService.Stub.asInterface(
                 ServiceManager.getService(Context.APP_OPS_SERVICE));
 
@@ -447,6 +457,27 @@
                 null, mHandler);
     }
 
+    void cleanupPartialUsers() {
+        // Prune out any partially created, partially removed and ephemeral users.
+        ArrayList<UserInfo> partials = new ArrayList<>();
+        synchronized (mUsersLock) {
+            final int userSize = mUsers.size();
+            for (int i = 0; i < userSize; i++) {
+                UserInfo ui = mUsers.valueAt(i).info;
+                if ((ui.partial || ui.guestToRemove || ui.isEphemeral()) && i != 0) {
+                    partials.add(ui);
+                }
+            }
+        }
+        final int partialsSize = partials.size();
+        for (int i = 0; i < partialsSize; i++) {
+            UserInfo ui = partials.get(i);
+            Slog.w(LOG_TAG, "Removing partially created user " + ui.id
+                    + " (name=" + ui.name + ")");
+            removeUserState(ui.id);
+        }
+    }
+
     @Override
     public String getUserAccount(int userId) {
         checkManageUserAndAcrossUsersFullPermission("get user account");
@@ -2472,8 +2503,23 @@
                 "Destroying key for user " + userHandle + " failed, continuing anyway", e);
         }
 
+        // Cleanup gatekeeper secure user id
+        try {
+            final IGateKeeperService gk = GateKeeper.getService();
+            if (gk != null) {
+                gk.clearSecureUserId(userHandle);
+            }
+        } catch (Exception ex) {
+            Slog.w(LOG_TAG, "unable to clear GK secure user id");
+        }
+
         // Cleanup package manager settings
         mPm.cleanUpUser(this, userHandle);
+
+        // Clean up all data before removing metadata
+        mPm.destroyUserData(userHandle,
+                StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
+
         // Remove this user from the list
         synchronized (mUsersLock) {
             mUsers.remove(userHandle);
@@ -2496,12 +2542,6 @@
         AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
         userFile.delete();
         updateUserIds();
-
-        // Now that we've purged all the metadata above, destroy the actual data
-        // on disk; if we battery pull in here we'll finish cleaning up when
-        // reconciling after reboot.
-        mPm.destroyUserData(userHandle,
-                StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
     }
 
     private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) {