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

Commit ec6c3d35 authored by Alex Johnston's avatar Alex Johnston
Browse files

Changed how user restrictions are pushed to UM

* Sort the user restrictions to local restriction
  set and global bundle in DPMS instead of User
  Manager.
* Simplify pushUserRestrictions.
* Split the list of user restrictions the profile
  owner of an organization-owned device can set into
  a global and local list. The user restrictions in
  the local list will only be applied to the personal
  profile as opposed to the whole device.

Bug: 149743941
     148453838
Test: atest com.android.cts.devicepolicy.UserRestrictionsTest
      atest com.android.server.devicepolicy.DevicePolicyManagerTest
      atest com.android.server.pm.UserRestrictionsUtilsTest
      atest com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testUserRestrictionSetOnParentLogged
      atest com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testUserRestrictionsSetOnParentAreNotPersisted
Change-Id: I1faa1f4776deb98e38595a358c01c3fbabfb1840
parent 1ad1f993
Loading
Loading
Loading
Loading
+12 −13
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import android.content.Context;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;

import com.android.server.pm.RestrictionsSet;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@@ -57,21 +59,18 @@ public abstract class UserManagerInternal {
     * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to set
     * restrictions enforced by the user.
     *
     * @param originatingUserId user id of the user where the restriction originated.
     * @param restrictions a bundle of user restrictions.
     * @param restrictionOwnerType determines which admin {@code userId} corresponds to.
     *             The admin can be either
     *             {@link UserManagerInternal#OWNER_TYPE_DEVICE_OWNER},
     *             {@link UserManagerInternal#OWNER_TYPE_PROFILE_OWNER},
     *             {@link UserManagerInternal#OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE}
     *             or {@link UserManagerInternal#OWNER_TYPE_NO_OWNER}.
     *             If the admin is a DEVICE_OWNER or a PROFILE_OWNER_ORG_OWNED_DEVICE then
     *             a restriction may be applied globally depending on which restriction it is,
     *             otherwise it will be applied just on the current user.
     * @see OwnerType
     * @param originatingUserId user id of the user where the restrictions originated.
     * @param global            a bundle of global user restrictions. Global restrictions are
     *                          restrictions that apply device-wide: to the managed profile,
     *                          primary profile and secondary users and any profile created in
     *                          any secondary user.
     * @param local             a restriction set of local user restrictions. The key is the user
     *                          id of the user whom the restrictions are targeting.
     * @param isDeviceOwner     whether {@code originatingUserId} corresponds to device owner
     *                          user id.
     */
    public abstract void setDevicePolicyUserRestrictions(int originatingUserId,
            @Nullable Bundle restrictions, @OwnerType int restrictionOwnerType);
            @Nullable Bundle global, @Nullable RestrictionsSet local, boolean isDeviceOwner);

    /**
     * Returns the "base" user restrictions.
+3 −24
Original line number Diff line number Diff line
@@ -1716,27 +1716,6 @@ public class UserManagerService extends IUserManager.Stub {
        }
    }

    private void setDevicePolicyUserRestrictionsInner(@UserIdInt int originatingUserId,
            @Nullable Bundle restrictions,
            @UserManagerInternal.OwnerType int restrictionOwnerType) {
        final Bundle global = new Bundle();
        final Bundle local = new Bundle();

        // Sort restrictions into local and global ensuring they don't overlap.
        UserRestrictionsUtils.sortToGlobalAndLocal(restrictions, restrictionOwnerType, global,
                local);
        boolean isDeviceOwner = restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER;

        RestrictionsSet localRestrictionsSet;
        if (UserRestrictionsUtils.isEmpty(local)) {
            localRestrictionsSet = new RestrictionsSet();
        } else {
            localRestrictionsSet = new RestrictionsSet(originatingUserId, local);
        }
        setDevicePolicyUserRestrictionsInner(originatingUserId, global, localRestrictionsSet,
                isDeviceOwner);
    }

    /**
     * See {@link UserManagerInternal#setDevicePolicyUserRestrictions}
     */
@@ -4752,10 +4731,10 @@ public class UserManagerService extends IUserManager.Stub {
    private class LocalService extends UserManagerInternal {
        @Override
        public void setDevicePolicyUserRestrictions(@UserIdInt int originatingUserId,
                @Nullable Bundle restrictions,
                @OwnerType int restrictionOwnerType) {
                @NonNull Bundle global, @NonNull RestrictionsSet local,
                boolean isDeviceOwner) {
            UserManagerService.this.setDevicePolicyUserRestrictionsInner(originatingUserId,
                    restrictions, restrictionOwnerType);
                    global, local, isDeviceOwner);
        }

        @Override
+18 −24
Original line number Diff line number Diff line
@@ -232,6 +232,13 @@ public class UserRestrictionsUtils {
                    UserManager.DISALLOW_UNMUTE_MICROPHONE
    );

    /**
     * Special user restrictions that profile owner of an organization-owned managed profile can
     * set on the parent profile instance to apply them on the personal profile.
     */
    private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_LOCAL_RESTRICTIONS =
            Sets.newArraySet();

    /**
     * User restrictions that default to {@code true} for managed profile owners.
     *
@@ -416,7 +423,8 @@ public class UserRestrictionsUtils {
     * @return true if a restriction is settable by profile owner of an organization owned device.
     */
    public static boolean canProfileOwnerOfOrganizationOwnedDeviceChange(String restriction) {
        return PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS.contains(restriction);
        return PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS.contains(restriction)
                || PROFILE_OWNER_ORGANIZATION_OWNED_LOCAL_RESTRICTIONS.contains(restriction);
    }

    /**
@@ -426,32 +434,10 @@ public class UserRestrictionsUtils {
        return DEFAULT_ENABLED_FOR_MANAGED_PROFILES;
    }

    /**
     * Takes restrictions that can be set by device owner, and sort them into what should be applied
     * globally and what should be applied only on the current user.
     */
    public static void sortToGlobalAndLocal(@Nullable Bundle in,
            @UserManagerInternal.OwnerType int restrictionOwnerType, @NonNull Bundle global,
            @NonNull Bundle local) {
        if (in == null || in.size() == 0) {
            return;
        }
        for (String key : in.keySet()) {
            if (!in.getBoolean(key)) {
                continue;
            }
            if (isGlobal(restrictionOwnerType, key)) {
                global.putBoolean(key, true);
            } else {
                local.putBoolean(key, true);
            }
        }
    }

    /**
     * Whether given user restriction should be enforced globally.
     */
    private static boolean isGlobal(@UserManagerInternal.OwnerType int restrictionOwnerType,
    public static boolean isGlobal(@UserManagerInternal.OwnerType int restrictionOwnerType,
            String key) {
        return ((restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER) && (
                PRIMARY_USER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)))
@@ -462,6 +448,14 @@ public class UserRestrictionsUtils {
                || DEVICE_OWNER_ONLY_RESTRICTIONS.contains(key);
    }

    /**
     * Whether given user restriction should be enforced locally.
     */
    public static boolean isLocal(@UserManagerInternal.OwnerType int restrictionOwnerType,
            String key) {
        return !isGlobal(restrictionOwnerType, key);
    }

    /**
     * @return true if two Bundles contain the same user restriction.
     * A null bundle and an empty bundle are considered to be equal.
+109 −82
Original line number Diff line number Diff line
@@ -87,6 +87,9 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.UserManagerInternal.OWNER_TYPE_DEVICE_OWNER;
import static android.os.UserManagerInternal.OWNER_TYPE_PROFILE_OWNER;
import static android.os.UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE;
import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import static android.provider.Telephony.Carriers.DPC_URI;
@@ -284,6 +287,7 @@ import com.android.server.SystemService;
import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.RestrictionsSet;
import com.android.server.pm.UserRestrictionsUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -322,6 +326,7 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.Predicate;
/**
 * Implementation of the device policy APIs.
@@ -1828,6 +1833,50 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            info = deviceAdminInfo;
        }
        Bundle addSyntheticRestrictions(Bundle restrictions) {
            if (disableCamera) {
                restrictions.putBoolean(UserManager.DISALLOW_CAMERA, true);
            } else {
                restrictions.remove(UserManager.DISALLOW_CAMERA);
            }
            return restrictions;
        }
        static Bundle removeDeprecatedRestrictions(Bundle restrictions) {
            for (String deprecatedRestriction: DEPRECATED_USER_RESTRICTIONS) {
                restrictions.remove(deprecatedRestriction);
            }
            return restrictions;
        }
        static Bundle filterRestrictions(Bundle restrictions, Predicate<String> filter) {
            Bundle result = new Bundle();
            for (String key : restrictions.keySet()) {
                if (!restrictions.getBoolean(key)) {
                    continue;
                }
                if (filter.test(key)) {
                    result.putBoolean(key, true);
                }
            }
            return result;
        }
        Bundle getEffectiveRestrictions() {
            return addSyntheticRestrictions(
                    removeDeprecatedRestrictions(ensureUserRestrictions()));
        }
        Bundle getLocalUserRestrictions(int adminType) {
            return filterRestrictions(getEffectiveRestrictions(),
                    key -> UserRestrictionsUtils.isLocal(adminType, key));
        }
        Bundle getGlobalUserRestrictions(int adminType) {
            return filterRestrictions(getEffectiveRestrictions(),
                    key -> UserRestrictionsUtils.isGlobal(adminType, key));
        }
        void dump(IndentingPrintWriter pw) {
            pw.print("uid="); pw.println(getUid());
            pw.print("testOnlyAdmin=");
@@ -2772,7 +2821,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId) != 0) {
            profileOwner.ensureUserRestrictions().putBoolean(
                    UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
            saveUserRestrictionsLocked(userId, /* parent = */ false);
            saveUserRestrictionsLocked(userId);
            mInjector.settingsSecurePutIntForUser(
                    Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId);
        }
@@ -2803,7 +2852,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            }
            admin.defaultEnabledRestrictionsAlreadySet.addAll(restrictionsToSet);
            Slog.i(LOG_TAG, "Enabled the following restrictions by default: " + restrictionsToSet);
            saveUserRestrictionsLocked(userId, /* parent = */ false);
            saveUserRestrictionsLocked(userId);
        }
    }
@@ -8222,9 +8271,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            }
        }
        // Tell the user manager that the restrictions have changed.
        final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
        pushUserRestrictions(affectedUserId);
        pushUserRestrictions(userHandle);
        final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
        if (SecurityLog.isLoggingEnabled()) {
            SecurityLog.writeEvent(SecurityLog.TAG_CAMERA_POLICY_SET,
                    who.getPackageName(), userHandle, affectedUserId, disabled ? 1 : 0);
@@ -10781,10 +10830,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                            "Cannot use the parent instance in Device Owner mode");
                }
            } else {
                if (!(UserRestrictionsUtils.canProfileOwnerChange(key, userHandle) || (
                        isProfileOwnerOfOrganizationOwnedDevice(activeAdmin) && parent
                        && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(
                                key)))) {
                boolean profileOwnerCanChangeOnItself = !parent
                        && UserRestrictionsUtils.canProfileOwnerChange(key, userHandle);
                boolean orgOwnedProfileOwnerCanChangesGlobally = parent
                        && isProfileOwnerOfOrganizationOwnedDevice(activeAdmin)
                        && UserRestrictionsUtils
                                .canProfileOwnerOfOrganizationOwnedDeviceChange(key);
                if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangesGlobally) {
                    throw new SecurityException("Profile owner cannot set user restriction " + key);
                }
            }
@@ -10796,7 +10849,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            } else {
                restrictions.remove(key);
            }
            saveUserRestrictionsLocked(userHandle, parent);
            saveUserRestrictionsLocked(userHandle);
        }
        final int eventId = enabledFromThisOwner
                ? DevicePolicyEnums.ADD_USER_RESTRICTION
@@ -10814,91 +10867,65 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
    }
    private void saveUserRestrictionsLocked(int userId, boolean parent) {
    private void saveUserRestrictionsLocked(int userId) {
        saveSettingsLocked(userId);
        pushUserRestrictions(parent ? getProfileParentId(userId) : userId);
        pushUserRestrictions(userId);
        sendChangedNotification(userId);
    }
    private void pushUserRestrictions(int userId) {
    /**
     * Pushes the user restrictions originating from a specific user.
     *
     * If called by the profile owner of an organization-owned device, the global and local
     * user restrictions will be an accumulation of the global user restrictions from the profile
     * owner active admin and its parent active admin. The key of the local user restrictions set
     * will be the target user id.
     */
    private void pushUserRestrictions(int originatingUserId) {
        final Bundle global;
        final RestrictionsSet local = new RestrictionsSet();
        final boolean isDeviceOwner;
        synchronized (getLockObject()) {
            final boolean isDeviceOwner = mOwners.isDeviceOwnerUserId(userId);
            Bundle userRestrictions = null;
            final int restrictionOwnerType;
            final int originatingUserId;
            isDeviceOwner = mOwners.isDeviceOwnerUserId(originatingUserId);
            if (isDeviceOwner) {
                final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
                if (deviceOwner == null) {
                    return; // Shouldn't happen.
                }
                userRestrictions = addOrRemoveDisableCameraRestriction(
                        deviceOwner.userRestrictions, deviceOwner);
                restrictionOwnerType = UserManagerInternal.OWNER_TYPE_DEVICE_OWNER;
                originatingUserId = deviceOwner.getUserHandle().getIdentifier();
                global = deviceOwner.getGlobalUserRestrictions(OWNER_TYPE_DEVICE_OWNER);
                local.updateRestrictions(originatingUserId, deviceOwner.getLocalUserRestrictions(
                        OWNER_TYPE_DEVICE_OWNER));
            } else {
                final ActiveAdmin profileOwnerOfOrganizationOwnedDevice =
                        getProfileOwnerOfOrganizationOwnedDeviceLocked(userId);
                // If profile owner of an organization owned device, the restrictions will be
                // pushed to the parent instance.
                if (profileOwnerOfOrganizationOwnedDevice != null && !isManagedProfile(userId)) {
                    restrictionOwnerType =
                          UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE;
                    final ActiveAdmin parent = profileOwnerOfOrganizationOwnedDevice
                            .getParentActiveAdmin();
                    userRestrictions = parent.userRestrictions;
                    userRestrictions = addOrRemoveDisableCameraRestriction(userRestrictions,
                            parent);
                    originatingUserId =
                            profileOwnerOfOrganizationOwnedDevice.getUserHandle().getIdentifier();
                } else {
                    final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
                    if (profileOwner != null) {
                        userRestrictions = profileOwner.userRestrictions;
                        restrictionOwnerType = UserManagerInternal.OWNER_TYPE_PROFILE_OWNER;
                        originatingUserId = profileOwner.getUserHandle().getIdentifier();
                    } else {
                        restrictionOwnerType = UserManagerInternal.OWNER_TYPE_NO_OWNER;
                        originatingUserId = userId;
                    }
                    userRestrictions = addOrRemoveDisableCameraRestriction(
                            userRestrictions, userId);
                }
            }
            // Remove deprecated restrictions.
            for (String deprecatedRestriction: DEPRECATED_USER_RESTRICTIONS) {
                userRestrictions.remove(deprecatedRestriction);
            }
            mUserManagerInternal.setDevicePolicyUserRestrictions(originatingUserId,
                    userRestrictions, restrictionOwnerType);
        }
    }
    private Bundle addOrRemoveDisableCameraRestriction(Bundle userRestrictions, ActiveAdmin admin) {
        if (userRestrictions == null) {
            userRestrictions = new Bundle();
        }
        if (admin.disableCamera) {
            userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true);
        } else {
            userRestrictions.remove(UserManager.DISALLOW_CAMERA);
        }
        return userRestrictions;
    }
    private Bundle addOrRemoveDisableCameraRestriction(Bundle userRestrictions, int userId) {
        if (userRestrictions == null) {
            userRestrictions = new Bundle();
        }
        if (getCameraDisabled(/* who= */ null, userId, /* mergeDeviceOwnerRestriction= */
                false)) {
            userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true);
        } else {
            userRestrictions.remove(UserManager.DISALLOW_CAMERA);
                final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(originatingUserId);
                if (profileOwner == null) {
                    return;
                }
        return userRestrictions;
                global = profileOwner.getGlobalUserRestrictions(OWNER_TYPE_PROFILE_OWNER);
                local.updateRestrictions(originatingUserId, profileOwner.getLocalUserRestrictions(
                        OWNER_TYPE_PROFILE_OWNER));
                // Global (device-wide) and local user restrictions set by the profile owner of an
                // organization-owned device are stored in the parent ActiveAdmin instance.
                if (isProfileOwnerOfOrganizationOwnedDevice(
                        profileOwner.getUserHandle().getIdentifier())) {
                    // The global restrictions set on the parent ActiveAdmin instance need to be
                    // merged with the global restrictions set on the profile owner ActiveAdmin
                    // instance, since both are to be applied device-wide.
                    UserRestrictionsUtils.merge(global,
                            profileOwner.getParentActiveAdmin().getGlobalUserRestrictions(
                                    OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
                    // The local restrictions set on the parent ActiveAdmin instance are only to be
                    // applied to the primary user. They therefore need to be added the local
                    // restriction set with the primary user id as the key, in this case the
                    // primary user id is the target user.
                    local.updateRestrictions(
                            getProfileParentId(profileOwner.getUserHandle().getIdentifier()),
                            profileOwner.getParentActiveAdmin().getLocalUserRestrictions(
                                    OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
                }
            }
        }
        mUserManagerInternal.setDevicePolicyUserRestrictions(originatingUserId, global, local,
                isDeviceOwner);
    }
    @Override
+55 −46

File changed.

Preview size limit exceeded, changes collapsed.

Loading