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) {