diff options
3 files changed, 31 insertions, 6 deletions
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java index 93afb4376cf2..4bdb92bcafc8 100644 --- a/core/java/android/os/UserManagerInternal.java +++ b/core/java/android/os/UserManagerInternal.java @@ -128,6 +128,13 @@ public abstract class UserManagerInternal { public abstract UserInfo createUserEvenWhenDisallowed(String name, int flags); /** + * Same as {@link UserManager#removeUser(int userHandle)}, but bypasses the check for + * {@link UserManager#DISALLOW_REMOVE_USER} and does not require the + * {@link android.Manifest.permission#MANAGE_USERS} permission. + */ + public abstract boolean removeUserEvenWhenDisallowed(int userId); + + /** * Return whether the given user is running in an * {@code UserState.STATE_RUNNING_UNLOCKING} or * {@code UserState.STATE_RUNNING_UNLOCKED} state. diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index d0baaf056cb0..a15af3ca9849 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -2490,7 +2490,10 @@ public class UserManagerService extends IUserManager.Stub { Log.w(LOG_TAG, "Cannot remove user. DISALLOW_REMOVE_USER is enabled."); return false; } + return removeUserUnchecked(userHandle); + } + private boolean removeUserUnchecked(int userHandle) { long ident = Binder.clearCallingIdentity(); try { final UserData userData; @@ -3568,6 +3571,11 @@ public class UserManagerService extends IUserManager.Stub { } @Override + public boolean removeUserEvenWhenDisallowed(int userId) { + return removeUserUnchecked(userId); + } + + @Override public boolean isUserRunning(int userId) { synchronized (mUserStates) { return mUserStates.get(userId, -1) >= 0; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index eb85e899dcd8..270488c707b2 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -7340,15 +7340,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean removeUser(ComponentName who, UserHandle userHandle) { Preconditions.checkNotNull(who, "ComponentName is null"); + UserHandle callingUserHandle = mInjector.binderGetCallingUserHandle(); synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - - long id = mInjector.binderClearCallingIdentity(); - try { - return mUserManager.removeUser(userHandle.getIdentifier()); - } finally { - mInjector.binderRestoreCallingIdentity(id); + } + final long id = mInjector.binderClearCallingIdentity(); + try { + int restrictionSource = mUserManager.getUserRestrictionSource( + UserManager.DISALLOW_REMOVE_USER, callingUserHandle); + if (restrictionSource != UserManager.RESTRICTION_NOT_SET + && restrictionSource != UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) { + Log.w(LOG_TAG, "The device owner cannot remove a user because " + + "DISALLOW_REMOVE_USER is enabled, and was not set by the device " + + "owner"); + return false; } + return mUserManagerInternal.removeUserEvenWhenDisallowed( + userHandle.getIdentifier()); + } finally { + mInjector.binderRestoreCallingIdentity(id); } } |