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

Commit 1d8f20b0 authored by BK Choi's avatar BK Choi Committed by Android (Google) Code Review
Browse files

Merge "Implement System Authority EnforcingAdmin." into main

parents 2d09bcdb 2074b25a
Loading
Loading
Loading
Loading
+57 −1
Original line number Diff line number Diff line
@@ -11963,6 +11963,34 @@ public class DevicePolicyManager {
        }
    }
    /**
     * Adds a user restriction on {@code targetUser}, specified by the {@code key}.
     *
     * <p>Called by a system service only, meaning that the caller's UID must be equal to
     * {@link Process#SYSTEM_UID}.
     *
     * @param systemEntity  The service entity that adds the restriction. A user restriction set by
     *                       a service entity can only be cleared by the same entity. This can be
     *                       just the calling package name, or any string of the caller's choice
     *                       can be used.
     * @param key  The key of the restriction.
     * @param targetUser  The user to add the restriction on.
     * @throws SecurityException if the caller is not a system service
     *
     * @hide
     */
    public void addUserRestriction(@NonNull String systemEntity,
            @NonNull @UserManager.UserRestrictionKey String key, @UserIdInt int targetUser) {
        if (mService != null) {
            try {
                mService.setUserRestrictionForUser(
                        systemEntity, key, /* enable= */ true, targetUser);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }
    /**
     * Called by a profile owner, device owner or a holder of any permission that is associated with
     *  a user restriction to set a user restriction specified by the provided {@code key} globally
@@ -11971,7 +11999,7 @@ public class DevicePolicyManager {
     * <p>For a given user, a restriction will be set if it was applied globally or locally by any
     * admin.
     *
     * <p> The calling device admin must be a profile owner, device owner or or a holder of any
     * <p> The calling device admin must be a profile owner, device owner or a holder of any
     * permission that is associated with a user restriction; if it is not, a security
     * exception will be thrown.
     *
@@ -12071,6 +12099,34 @@ public class DevicePolicyManager {
        }
    }
    /**
     * Clears a user restriction from {@code targetUser}, specified by the {@code key}.
     *
     * <p>Called by a system service only, meaning that the caller's UID must be equal to
     * {@link Process#SYSTEM_UID}.
     *
     * @param systemEntity  The system entity that clears the restriction. A user restriction
     *                         set by a system entity can only be cleared by the same entity. This
     *                         can be just the calling package name, or any string of the caller's
     *                         choice can be used.
     * @param key  The key of the restriction.
     * @param targetUser  The user to clear the restriction from.
     * @throws SecurityException if the caller is not a system service
     *
     * @hide
     */
    public void clearUserRestriction(@NonNull String systemEntity,
            @NonNull @UserManager.UserRestrictionKey String key, @UserIdInt int targetUser) {
        if (mService != null) {
            try {
                mService.setUserRestrictionForUser(
                        systemEntity, key, /* enable= */ false, targetUser);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }
    /**
     * Called by an admin to get user restrictions set by themselves with
     * {@link #addUserRestriction(ComponentName, String)}.
+1 −0
Original line number Diff line number Diff line
@@ -255,6 +255,7 @@ interface IDevicePolicyManager {
    ComponentName getRestrictionsProvider(int userHandle);

    void setUserRestriction(in ComponentName who, in String callerPackage, in String key, boolean enable, boolean parent);
    void setUserRestrictionForUser(in String systemEntity, in String key, boolean enable, int targetUser);
    void setUserRestrictionGlobally(in String callerPackage, in String key);
    Bundle getUserRestrictions(in ComponentName who, in String callerPackage, boolean parent);
    Bundle getUserRestrictionsGlobally(in String callerPackage);
+28 −5
Original line number Diff line number Diff line
@@ -13634,7 +13634,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            setBackwardCompatibleUserRestriction(
                    caller, admin, key, enabledFromThisOwner, parent);
        }
        logUserRestrictionCall(key, enabledFromThisOwner, parent, caller);
        logUserRestrictionCall(key, enabledFromThisOwner, parent, caller, affectedUserId);
    }
    @Override
    public void setUserRestrictionForUser(
            @NonNull String systemEntity, String key, boolean enabled, @UserIdInt int targetUser) {
        Objects.requireNonNull(systemEntity);
        CallerIdentity caller = getCallerIdentity();
        if (caller.getUid() != Process.SYSTEM_UID) {
            throw new SecurityException("Only system services can call setUserRestrictionForUser"
                    + " on a target user: " + targetUser);
        }
        if (VERBOSE_LOG) {
            Slogf.v(LOG_TAG, "Creating SystemEnforcingAdmin %s for calling package %s",
                    systemEntity, caller.getPackageName());
        }
        EnforcingAdmin admin = EnforcingAdmin.createSystemEnforcingAdmin(systemEntity);
        setLocalUserRestrictionInternal(admin, key, enabled, targetUser);
        logUserRestrictionCall(key, enabled, /* parent= */ false, caller, targetUser);
    }
    private void checkAdminCanSetRestriction(CallerIdentity caller, boolean parent, String key) {
@@ -13755,7 +13776,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        setGlobalUserRestrictionInternal(admin, key, /* enabled= */ true);
        logUserRestrictionCall(key, /* enabled= */ true, /* parent= */ false, caller);
        logUserRestrictionCall(key, /* enabled= */ true, /* parent= */ false, caller,
                UserHandle.USER_ALL);
    }
    private void setLocalUserRestrictionInternal(
            EnforcingAdmin admin, String key, boolean enabled, int userId) {
@@ -13791,7 +13813,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    }
    private void logUserRestrictionCall(
            String key, boolean enabled, boolean parent, CallerIdentity caller) {
            String key, boolean enabled, boolean parent, CallerIdentity caller, int targetUserId) {
        final int eventId = enabled
                ? DevicePolicyEnums.ADD_USER_RESTRICTION
                : DevicePolicyEnums.REMOVE_USER_RESTRICTION;
@@ -13807,8 +13829,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            SecurityLog.writeEvent(eventTag, caller.getPackageName(), caller.getUserId(), key);
        }
        Slogf.i(LOG_TAG, "Changing user restriction %s to: %b caller: %s",
                key, enabled, caller.toString());
        Slogf.i(LOG_TAG, "Changing user restriction %s on %s to: %b caller: %s",
                key, (targetUserId == UserHandle.USER_ALL ? "all users" : ("user " + targetUserId)),
                enabled, caller.toString());
    }
    @Override
+70 −3
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.annotation.Nullable;
import android.app.admin.Authority;
import android.app.admin.DeviceAdminAuthority;
import android.app.admin.DpcAuthority;
import android.app.admin.PackagePermissionPolicyKey;
import android.app.admin.RoleAuthority;
import android.app.admin.UnknownAuthority;
import android.content.ComponentName;
@@ -57,23 +56,29 @@ final class EnforcingAdmin {
    static final String TAG = "EnforcingAdmin";

    static final String ROLE_AUTHORITY_PREFIX = "role:";
    static final String SYSTEM_AUTHORITY_PREFIX = "system:";
    static final String DPC_AUTHORITY = "enterprise";
    static final String DEVICE_ADMIN_AUTHORITY = "device_admin";
    static final String DEFAULT_AUTHORITY = "default";

    private static final String ATTR_PACKAGE_NAME = "package-name";
    private static final String ATTR_SYSTEM_ENTITY = "system-entity";
    private static final String ATTR_CLASS_NAME = "class-name";
    private static final String ATTR_AUTHORITIES = "authorities";
    private static final String ATTR_AUTHORITIES_SEPARATOR = ";";
    private static final String ATTR_USER_ID = "user-id";
    private static final String ATTR_IS_ROLE = "is-role";
    private static final String ATTR_IS_SYSTEM = "is-system";

    private final String mPackageName;
    // Name of the system entity. Only used when mIsSystemAuthority is true.
    private final String mSystemEntity;
    // This is needed for DPCs and active admins
    private final ComponentName mComponentName;
    private Set<String> mAuthorities;
    private final int mUserId;
    private final boolean mIsRoleAuthority;
    private final boolean mIsSystemAuthority;
    private final ActiveAdmin mActiveAdmin;

    static EnforcingAdmin createEnforcingAdmin(@NonNull String packageName, int userId,
@@ -106,6 +111,11 @@ final class EnforcingAdmin {
                userId, activeAdmin);
    }

    static EnforcingAdmin createSystemEnforcingAdmin(@NonNull String systemEntity) {
        Objects.requireNonNull(systemEntity);
        return new EnforcingAdmin(systemEntity);
    }

    static EnforcingAdmin createEnforcingAdmin(android.app.admin.EnforcingAdmin admin) {
        Objects.requireNonNull(admin);
        Authority authority = admin.getAuthority();
@@ -127,6 +137,7 @@ final class EnforcingAdmin {
                    /* activeAdmin = */ null,
                    /* isRoleAuthority = */ true);
        }
        // TODO(b/324899199): Consider supporting android.app.admin.SystemAuthority.
        return new EnforcingAdmin(admin.getPackageName(), admin.getComponentName(),
                Set.of(), admin.getUserHandle().getIdentifier(),
                /* activeAdmin = */ null);
@@ -159,9 +170,11 @@ final class EnforcingAdmin {
        Objects.requireNonNull(packageName);
        Objects.requireNonNull(authorities);

        // Role authorities should not be using this constructor
        // Role/System authorities should not be using this constructor
        mIsRoleAuthority = false;
        mIsSystemAuthority = false;
        mPackageName = packageName;
        mSystemEntity = null;
        mComponentName = componentName;
        mAuthorities = new HashSet<>(authorities);
        mUserId = userId;
@@ -173,7 +186,9 @@ final class EnforcingAdmin {

        // Only role authorities use this constructor.
        mIsRoleAuthority = true;
        mIsSystemAuthority = false;
        mPackageName = packageName;
        mSystemEntity = null;
        mUserId = userId;
        mComponentName = null;
        // authorities will be loaded when needed
@@ -181,6 +196,21 @@ final class EnforcingAdmin {
        mActiveAdmin = activeAdmin;
    }

    /** Constructor for System authorities. */
    private EnforcingAdmin(@NonNull String systemEntity) {
        Objects.requireNonNull(systemEntity);

        // Only system authorities use this constructor.
        mIsSystemAuthority = true;
        mIsRoleAuthority = false;
        mPackageName = null;
        mSystemEntity = systemEntity;
        mUserId = UserHandle.USER_SYSTEM;
        mComponentName = null;
        mAuthorities = getSystemAuthority(systemEntity);
        mActiveAdmin = null;
    }

    private EnforcingAdmin(
            String packageName, @Nullable ComponentName componentName, Set<String> authorities,
            int userId, @Nullable ActiveAdmin activeAdmin, boolean isRoleAuthority) {
@@ -188,7 +218,9 @@ final class EnforcingAdmin {
        Objects.requireNonNull(authorities);

        mIsRoleAuthority = isRoleAuthority;
        mIsSystemAuthority = false;
        mPackageName = packageName;
        mSystemEntity = null;
        mComponentName = componentName;
        mAuthorities = new HashSet<>(authorities);
        mUserId = userId;
@@ -204,6 +236,18 @@ final class EnforcingAdmin {
        return authorities.isEmpty() ? Set.of(DEFAULT_AUTHORITY) : authorities;
    }

    /**
     * Returns a set of authorities for system authority.
     *
     * <p>Note that a system authority enforcing admin has only one authority that has the package
     * name of the calling system service. Therefore, the returned set always contains one element.
     */
    private static Set<String> getSystemAuthority(String systemEntity) {
        Set<String> authorities = new HashSet<>();
        authorities.add(SYSTEM_AUTHORITY_PREFIX + systemEntity);
        return authorities;
    }

    // TODO(b/259042794): move this logic to RoleManagerLocal
    private static Set<String> getRoles(String packageName, int userId) {
        RoleManagerLocal roleManagerLocal = LocalManagerRegistry.getManager(
@@ -264,6 +308,7 @@ final class EnforcingAdmin {
        } else if (mAuthorities.contains(DEVICE_ADMIN_AUTHORITY)) {
            authority = DeviceAdminAuthority.DEVICE_ADMIN_AUTHORITY;
        } else {
            // For now, System Authority returns UNKNOWN_AUTHORITY.
            authority = UnknownAuthority.UNKNOWN_AUTHORITY;
        }
        return new android.app.admin.EnforcingAdmin(
@@ -291,8 +336,10 @@ final class EnforcingAdmin {
        if (o == null || getClass() != o.getClass()) return false;
        EnforcingAdmin other = (EnforcingAdmin) o;
        return Objects.equals(mPackageName, other.mPackageName)
                && Objects.equals(mSystemEntity, other.mSystemEntity)
                && Objects.equals(mComponentName, other.mComponentName)
                && Objects.equals(mIsRoleAuthority, other.mIsRoleAuthority)
                && (mIsSystemAuthority == other.mIsSystemAuthority)
                && hasMatchingAuthorities(this, other);
    }

@@ -307,6 +354,8 @@ final class EnforcingAdmin {
    public int hashCode() {
        if (mIsRoleAuthority) {
            return Objects.hash(mPackageName, mUserId);
        } else if (mIsSystemAuthority) {
            return Objects.hash(mSystemEntity);
        } else {
            return Objects.hash(
                    mComponentName == null ? mPackageName : mComponentName,
@@ -318,8 +367,12 @@ final class EnforcingAdmin {
    void saveToXml(TypedXmlSerializer serializer) throws IOException {
        serializer.attribute(/* namespace= */ null, ATTR_PACKAGE_NAME, mPackageName);
        serializer.attributeBoolean(/* namespace= */ null, ATTR_IS_ROLE, mIsRoleAuthority);
        serializer.attributeBoolean(/* namespace= */ null, ATTR_IS_SYSTEM, mIsSystemAuthority);
        serializer.attributeInt(/* namespace= */ null, ATTR_USER_ID, mUserId);
        if (!mIsRoleAuthority) {
        if (mIsSystemAuthority) {
            serializer.attribute(/* namespace= */ null, ATTR_SYSTEM_ENTITY, mSystemEntity);
        }
        if (!mIsRoleAuthority && !mIsSystemAuthority) {
            if (mComponentName != null) {
                serializer.attribute(
                        /* namespace= */ null, ATTR_CLASS_NAME, mComponentName.getClassName());
@@ -336,7 +389,10 @@ final class EnforcingAdmin {
    static EnforcingAdmin readFromXml(TypedXmlPullParser parser)
            throws XmlPullParserException {
        String packageName = parser.getAttributeValue(/* namespace= */ null, ATTR_PACKAGE_NAME);
        String systemEntity = parser.getAttributeValue(/* namespace= */ null, ATTR_SYSTEM_ENTITY);
        boolean isRoleAuthority = parser.getAttributeBoolean(/* namespace= */ null, ATTR_IS_ROLE);
        boolean isSystemAuthority = parser.getAttributeBoolean(
                /* namespace= */ null, ATTR_IS_SYSTEM, /* defaultValue= */ false);
        String authoritiesStr = parser.getAttributeValue(/* namespace= */ null, ATTR_AUTHORITIES);
        int userId = parser.getAttributeInt(/* namespace= */ null, ATTR_USER_ID);

@@ -348,6 +404,13 @@ final class EnforcingAdmin {
            }
            // TODO(b/281697976): load active admin
            return new EnforcingAdmin(packageName, userId, null);
        } else if (isSystemAuthority) {
            if (systemEntity == null) {
                Slogf.wtf(TAG, "Error parsing EnforcingAdmin with SystemAuthority, "
                        + "systemEntity is null.");
                return null;
            }
            return new EnforcingAdmin(systemEntity);
        } else {
            if (packageName == null || authoritiesStr == null) {
                Slogf.wtf(TAG, "Error parsing EnforcingAdmin, packageName is "
@@ -381,6 +444,10 @@ final class EnforcingAdmin {
        sb.append(mUserId);
        sb.append(", mIsRoleAuthority= ");
        sb.append(mIsRoleAuthority);
        sb.append(", mIsSystemAuthority= ");
        sb.append(mIsSystemAuthority);
        sb.append(", mSystemEntity = ");
        sb.append(mSystemEntity);
        sb.append(" }");
        return sb.toString();
    }