summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java58
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl1
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java33
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java73
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();
}