Allow DO to remove user even if DISALLOW_REMOVE_USER is set.

BUG:32300784
Test: create user in TestDPC, set DISALLOW_REMOVE_USER restriction,
and remove this user.
Change-Id: I96ab02d594cd1a8ab14420e12357f2083da1ce63
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 93afb43..4bdb92b 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -128,6 +128,13 @@
     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 efd6f46..23a26ab 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2489,7 +2489,10 @@
             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;
@@ -3567,6 +3570,11 @@
         }
 
         @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 eb85e89..270488c 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 @@
     @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);
         }
     }