Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d37c4a99 authored by Nicolas Prevot's avatar Nicolas Prevot
Browse files

Allow DO to provision even if it has set disallow remove mp.

If the device owner has set DISALLOW_REMOVE_MANAGED_PROFILE,
and there is already a managed profile:
it should be allowed to provision a new managed profile by
deleting the old one.
Test: adb shell am instrument -e class
com.android.server.devicepolicy.DevicePolicyManagerTest
-w
com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
BUG:34116228

Change-Id: I9e6f39924107aee40b57d22e638487a1ea3132de
parent 45d29078
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ interface IUserManager {
    void setUserEnabled(int userHandle);
    void evictCredentialEncryptionKey(int userHandle);
    boolean removeUser(int userHandle);
    boolean removeUserEvenWhenDisallowed(int userHandle);
    void setUserName(int userHandle, String name);
    void setUserIcon(int userHandle, in Bitmap icon);
    ParcelFileDescriptor getUserIcon(int userHandle);
+16 −0
Original line number Diff line number Diff line
@@ -2081,6 +2081,22 @@ public class UserManager {
        }
    }

    /**
     * Similar to {@link #removeUser(int)} except bypassing the checking of
     * {@link UserManager#DISALLOW_REMOVE_USER}
     * or {@link UserManager#DISALLOW_REMOVE_MANAGED_PROFILE}.
     *
     * @see {@link #removeUser(int)}
     * @hide
     */
    public boolean removeUserEvenWhenDisallowed(@UserIdInt int userHandle) {
        try {
            return mService.removeUserEvenWhenDisallowed(userHandle);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

    /**
     * Updates the user's name.
     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+6 −0
Original line number Diff line number Diff line
@@ -2346,6 +2346,12 @@ public class UserManagerService extends IUserManager.Stub {
        return createUserInternalUnchecked(name, flags, userId, disallowedPackages);
    }

    @Override
    public boolean removeUserEvenWhenDisallowed(@UserIdInt int userHandle) {
        checkManageOrCreateUsersPermission("Only the system can remove users");
        return removeUserUnchecked(userHandle);
    }

    @Override
    public UserInfo createUser(String name, int flags) {
        checkManageOrCreateUsersPermission(flags);
+33 −12
Original line number Diff line number Diff line
@@ -6146,6 +6146,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
    }

    private boolean isProfileOwnerPackage(String packageName, int userId) {
        synchronized (this) {
            return mOwners.hasProfileOwner(userId)
                    && mOwners.getProfileOwnerPackage(userId).equals(packageName);
        }
    }

    public boolean isProfileOwner(ComponentName who, int userId) {
        final ComponentName profileOwner = getProfileOwner(userId);
        return who != null && who.equals(profileOwner);
@@ -9119,21 +9126,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        final long ident = mInjector.binderClearCallingIdentity();
        try {
            final UserHandle callingUserHandle = UserHandle.of(callingUserId);
            if (mUserManager.hasUserRestriction(
                    UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserHandle)) {
                // The DO can initiate provisioning if the restriction was set by the DO.
                if (!isDeviceOwnerPackage(packageName, callingUserId)
                        || isAdminAffectedByRestriction(mOwners.getDeviceOwnerComponent(),
            final ComponentName ownerAdmin = getOwnerComponent(packageName, callingUserId);
            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
                    callingUserHandle)) {
                // An admin can initiate provisioning if it has set the restriction.
                if (ownerAdmin == null || isAdminAffectedByRestriction(ownerAdmin,
                        UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserId)) {
                    // Caller is not DO or the restriction was set by the system.
                    return CODE_ADD_MANAGED_PROFILE_DISALLOWED;
                }
            }

            // TODO: Allow it if the caller is the DO? DO could just call removeUser() before
            // provisioning, so not strictly required...
            boolean canRemoveProfile = !mUserManager.hasUserRestriction(
                        UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, callingUserHandle);
            boolean canRemoveProfile = true;
            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
                    callingUserHandle)) {
                // We can remove a profile if the admin itself has set the restriction.
                if (ownerAdmin == null || isAdminAffectedByRestriction(ownerAdmin,
                        UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
                        callingUserId)) {
                    canRemoveProfile = false;
                }
            }
            if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) {
                return CODE_CANNOT_ADD_MANAGED_PROFILE;
            }
@@ -9143,6 +9154,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        return CODE_OK;
    }

    private ComponentName getOwnerComponent(String packageName, int userId) {
        if (isDeviceOwnerPackage(packageName, userId)) {
            return mOwners.getDeviceOwnerComponent();
        }
        if (isProfileOwnerPackage(packageName, userId)) {
            return mOwners.getProfileOwnerComponent(userId);
        }
        return null;
    }

    private int checkManagedUserProvisioningPreCondition(int callingUserId) {
        if (!hasFeatureManagedUsers()) {
            return CODE_MANAGED_USERS_NOT_SUPPORTED;
+9 −4
Original line number Diff line number Diff line
@@ -2505,18 +2505,23 @@ public class DevicePolicyManagerTest extends DpmTestBase {
                eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE),
                eq(UserHandle.SYSTEM)))
                .thenReturn(true);
        when(mContext.userManager.getUserRestrictionSource(
                eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE),
                eq(UserHandle.SYSTEM)))
                .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);

        // We can't remove the profile to create a new one.
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);

        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DpmMockContext.ANOTHER_PACKAGE_NAME,
                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false,
                DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);

        // But the device owner can still do it because it has set the restriction itself.
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_OK);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
    }

    private void setup_splitUser_firstBoot_systemUser() throws Exception {