diff options
4 files changed, 156 insertions, 9 deletions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index a7070b910f17..965e3c43cca1 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -11964,6 +11964,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 * on all users. To clear the restriction use {@link #clearUserRestriction}. @@ -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. * @@ -12072,6 +12100,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)}. * <p> diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 381f9963789b..c393a9eeae30 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -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); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 8cc7383b9bf6..ad281f2eecdf 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -13618,7 +13618,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) { @@ -13739,7 +13760,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) { @@ -13775,7 +13797,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; @@ -13791,8 +13813,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 diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java index 02590f97ab6b..e65e513af55c 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java @@ -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(); } |