diff options
author | 2023-02-15 13:24:17 +0000 | |
---|---|---|
committer | 2023-02-15 21:49:27 +0000 | |
commit | 17981fdc140ddf285c8988510335eb49b74b50e7 (patch) | |
tree | b74df9bb85dc88930c24520198bfba51f2ab66e2 | |
parent | fa618d8f1205e604afd244911b65d8831ec0cf60 (diff) |
Add a new RestrictionsManager API to get app restrictions per admin
And deprecated the existing API in UM that returns restrictions set for
a single admin
Bug: 232918480
Test: btest android.devicepolicy.cts.ApplicationRestrictionsTest#getApplicationRestrictionsPerAdmin_*
Change-Id: I133ac8d53b651e171dbe46871691fb13e2addb3f
9 files changed, 135 insertions, 19 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index bc8907e25e63..6d38bf0cdc21 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -11356,7 +11356,8 @@ package android.content { public class RestrictionsManager { method public static android.os.Bundle convertRestrictionsToBundle(java.util.List<android.content.RestrictionEntry>); method public android.content.Intent createLocalApprovalIntent(); - method public android.os.Bundle getApplicationRestrictions(); + method @Deprecated public android.os.Bundle getApplicationRestrictions(); + method @NonNull @WorkerThread public java.util.List<android.os.Bundle> getApplicationRestrictionsPerAdmin(); method public java.util.List<android.content.RestrictionEntry> getManifestRestrictions(String); method public boolean hasRestrictionsProvider(); method public void notifyPermissionResponse(String, android.os.PersistableBundle); @@ -33752,7 +33753,7 @@ package android.os { public class UserManager { method public static android.content.Intent createUserCreationIntent(@Nullable String, @Nullable String, @Nullable String, @Nullable android.os.PersistableBundle); - method @WorkerThread public android.os.Bundle getApplicationRestrictions(String); + method @Deprecated @WorkerThread public android.os.Bundle getApplicationRestrictions(String); method public long getSerialNumberForUser(android.os.UserHandle); method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.CREATE_USERS"}) public int getUserCount(); method public long getUserCreationTime(android.os.UserHandle); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index f9f06130b0f6..56f8351a5d64 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -9983,6 +9983,11 @@ public class DevicePolicyManager { * owner, and the application restrictions managing package via * {@link #getApplicationRestrictions}. * + * <p>Starting from Android Version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, + * multiple admins can set app restrictions for the same application, the target application can + * get the list of app restrictions set by each admin via + * {@link android.content.RestrictionsManager#getApplicationRestrictionsPerAdmin}. + * * <p>NOTE: The method performs disk I/O and shouldn't be called on the main thread * * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java index eefadeafda93..eb38146a58be 100644 --- a/core/java/android/app/admin/DevicePolicyManagerInternal.java +++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java @@ -25,7 +25,6 @@ import android.os.Bundle; import android.os.UserHandle; import java.util.List; -import java.util.Map; import java.util.Set; /** @@ -318,8 +317,9 @@ public abstract class DevicePolicyManagerInternal { public abstract boolean isApplicationExemptionsFlagEnabled(); /** - * Returns the application restrictions set by each admin for the given {@code packageName}. + * Returns a map of admin to {@link Bundle} map of restrictions set by the admins for the + * provided {@code packageName} in the provided {@code userId} */ - public abstract Map<String, Bundle> getApplicationRestrictionsPerAdmin( - String packageName, int userId); + public abstract List<Bundle> getApplicationRestrictionsPerAdminForUser( + String packageName, @UserIdInt int userId); } diff --git a/core/java/android/content/IRestrictionsManager.aidl b/core/java/android/content/IRestrictionsManager.aidl index db9146ffbae1..0fcd63fbfc94 100644 --- a/core/java/android/content/IRestrictionsManager.aidl +++ b/core/java/android/content/IRestrictionsManager.aidl @@ -26,6 +26,7 @@ import android.os.PersistableBundle; */ interface IRestrictionsManager { Bundle getApplicationRestrictions(in String packageName); + List<Bundle> getApplicationRestrictionsPerAdminForUser(int userId, in String packageName); boolean hasRestrictionsProvider(); void requestPermission(in String packageName, in String requestType, in String requestId, in PersistableBundle requestData); diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java index ffd80eabf6ca..8115292e5885 100644 --- a/core/java/android/content/RestrictionsManager.java +++ b/core/java/android/content/RestrictionsManager.java @@ -18,7 +18,10 @@ package android.content; import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM; +import android.annotation.NonNull; import android.annotation.SystemService; +import android.annotation.UserHandleAware; +import android.annotation.WorkerThread; import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.compat.annotation.UnsupportedAppUsage; @@ -31,6 +34,7 @@ import android.os.Build; import android.os.Bundle; import android.os.PersistableBundle; import android.os.RemoteException; +import android.os.UserManager; import android.service.restrictions.RestrictionsReceiver; import android.util.AttributeSet; import android.util.Log; @@ -422,6 +426,14 @@ public class RestrictionsManager { * to this application. * @return the application restrictions as a Bundle. Returns null if there * are no restrictions. + * + * @deprecated Use {@link #getApplicationRestrictionsPerAdmin} instead. + * Starting from Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, it is + * possible for there to be multiple managing agents on the device with the ability to set + * restrictions. This API will only to return the restrictions set by device policy controllers + * (DPCs) + * + * @see DevicePolicyManager */ public Bundle getApplicationRestrictions() { try { @@ -435,6 +447,46 @@ public class RestrictionsManager { } /** + * Returns a {@link List} containing a {@link Bundle} for each managing agent that has set + * restrictions for the current application, the bundle contains any application restrictions + * set for the current package. The order of the items in the list is not guaranteed to remain + * stable between multiple calls. + * + * <p>Starting from Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, + * it is possible for there to be multiple managing agents on the device with the ability to set + * restrictions, e.g. an Enterprise DPC and a Supervision admin. + * + * <p>Each {@link Bundle} consists of key-value pairs, as defined by the application, + * where the types of values may be: + * <ul> + * <li>{@code boolean} + * <li>{@code int} + * <li>{@code String} or {@code String[]} + * <li>From {@link android.os.Build.VERSION_CODES#M}, {@code Bundle} or {@code Bundle[]} + * </ul> + * + * <p>NOTE: The method performs disk I/O and shouldn't be called on the main thread + * + * @return a {@link List} of {@link Bundle} containing the restrictions set by admins for that + * package. Returns an empty {@link List} if there are no saved restrictions. + * + * @see UserManager#KEY_RESTRICTIONS_PENDING + */ + @WorkerThread + @UserHandleAware + public @NonNull List<Bundle> getApplicationRestrictionsPerAdmin() { + try { + if (mService != null) { + return mService.getApplicationRestrictionsPerAdminForUser( + mContext.getUserId(), mContext.getPackageName()); + } + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + return null; + } + + /** * Called by an application to check if there is an active Restrictions Provider. If * there isn't, {@link #requestPermission(String, String, PersistableBundle)} is not available. * diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index c3531bdd7d4c..9c55ad692f42 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -5587,7 +5587,17 @@ public class UserManager { * if there are no saved restrictions. * * @see #KEY_RESTRICTIONS_PENDING + * + * @deprecated Use + * {@link android.content.RestrictionsManager#getApplicationRestrictionsPerAdmin} instead. + * Starting from Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, it is + * possible for there to be multiple managing agents on the device with the ability to set + * restrictions. This API will only to return the restrictions set by device policy controllers + * (DPCs) + * + * @see DevicePolicyManager */ + @Deprecated @WorkerThread @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.TIRAMISU) public Bundle getApplicationRestrictions(String packageName) { @@ -5600,8 +5610,12 @@ public class UserManager { } /** + * @deprecated Use + * {@link android.content.RestrictionsManager#getApplicationRestrictionsPerAdmin} instead. + * * @hide */ + @Deprecated @WorkerThread public Bundle getApplicationRestrictions(String packageName, UserHandle user) { try { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 2ffae7fd865d..19a0e03a9329 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -5928,11 +5928,21 @@ public class UserManagerService extends IUserManager.Stub { /* receiverPermission= */null); } + /** + * @deprecated Use {@link + * android.content.RestrictionsManager#getApplicationRestrictionsPerAdmin} instead. + */ + @Deprecated @Override public Bundle getApplicationRestrictions(String packageName) { return getApplicationRestrictionsForUser(packageName, UserHandle.getCallingUserId()); } + /** + * @deprecated Use {@link + * android.content.RestrictionsManager#getApplicationRestrictionsPerAdmin} instead. + */ + @Deprecated @Override public Bundle getApplicationRestrictionsForUser(String packageName, @UserIdInt int userId) { if (UserHandle.getCallingUserId() != userId diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index a44815ec7313..05876a1ea8cc 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -11021,6 +11021,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ? null : policies.entrySet().stream().findAny().get().getValue().getValue(); } + private int getUidForPackage(String packageName, int userId) { + return mInjector.binderWithCleanCallingIdentity(() -> { + try { + return mContext.getPackageManager().getApplicationInfoAsUser( + packageName, /* flags= */ 0, userId).uid; + } catch (NameNotFoundException exception) { + return -1; + } + }); + } + @Override public void setTrustAgentConfiguration( ComponentName admin, String callerPackageName, ComponentName agent, @@ -15010,33 +15021,38 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public Map<String, Bundle> getApplicationRestrictionsPerAdmin( - String packageName, int userId) { + public List<Bundle> getApplicationRestrictionsPerAdminForUser( + String packageName, @UserIdInt int userId) { + if (UserHandle.getCallingUserId() != userId + || !UserHandle.isSameApp( + Binder.getCallingUid(), getUidForPackage(packageName, userId))) { + final int uid = Binder.getCallingUid(); + if (!UserHandle.isSameApp(uid, Process.SYSTEM_UID) && uid != Process.ROOT_UID) { + throw new SecurityException("Only system may: get application restrictions for " + + "other user/app " + packageName); + } + } LinkedHashMap<EnforcingAdmin, PolicyValue<Bundle>> policies = mDevicePolicyEngine.getLocalPoliciesSetByAdmins( PolicyDefinition.APPLICATION_RESTRICTIONS(packageName), userId); - Map<String, Bundle> restrictions = new HashMap<>(); + List<Bundle> restrictions = new ArrayList<>(); for (EnforcingAdmin admin : policies.keySet()) { - restrictions.put(admin.getPackageName(), policies.get(admin).getValue()); + restrictions.add(policies.get(admin).getValue()); } if (!restrictions.isEmpty()) { return restrictions; } return mInjector.binderWithCleanCallingIdentity(() -> { - // Could be a device that hasn't migrated yet, so just return any restrictions saved - // in userManager. + // Could be a device that has a DPC that hasn't migrated yet, so just return any + // restrictions saved in userManager. Bundle bundle = mUserManager.getApplicationRestrictions( packageName, UserHandle.of(userId)); if (bundle == null || bundle.isEmpty()) { - return new HashMap<>(); - } - ActiveAdmin admin = getMostProbableDPCAdminForLocalPolicy(userId); - if (admin == null) { - return new HashMap<>(); + return new ArrayList<>(); } - return Map.of(admin.info.getPackageName(), bundle); + return List.of(bundle); }); } } diff --git a/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java b/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java index 62dbd89c48cb..9f0e2f561582 100644 --- a/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java +++ b/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java @@ -16,12 +16,14 @@ package com.android.server.restrictions; +import android.annotation.UserIdInt; import android.app.AppGlobals; +import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.IDevicePolicyManager; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.IRestrictionsManager; +import android.content.Intent; import android.content.RestrictionsManager; import android.content.pm.ResolveInfo; import android.os.Binder; @@ -35,6 +37,9 @@ import android.util.Log; import com.android.internal.util.ArrayUtils; import com.android.server.SystemService; +import java.util.ArrayList; +import java.util.List; + /** * SystemService wrapper for the RestrictionsManager implementation. Publishes the * Context.RESTRICTIONS_SERVICE. @@ -60,19 +65,31 @@ public final class RestrictionsManagerService extends SystemService { final Context mContext; private final IUserManager mUm; private final IDevicePolicyManager mDpm; + private final DevicePolicyManagerInternal mDpmInternal; public RestrictionsManagerImpl(Context context) { mContext = context; mUm = (IUserManager) getBinderService(Context.USER_SERVICE); mDpm = (IDevicePolicyManager) getBinderService(Context.DEVICE_POLICY_SERVICE); + mDpmInternal = getLocalService(DevicePolicyManagerInternal.class); } @Override + @Deprecated public Bundle getApplicationRestrictions(String packageName) throws RemoteException { return mUm.getApplicationRestrictions(packageName); } @Override + public List<Bundle> getApplicationRestrictionsPerAdminForUser( + @UserIdInt int userId, String packageName) throws RemoteException { + if (mDpmInternal != null) { + return mDpmInternal.getApplicationRestrictionsPerAdminForUser(packageName, userId); + } + return new ArrayList<>(); + } + + @Override public boolean hasRestrictionsProvider() throws RemoteException { int userHandle = UserHandle.getCallingUserId(); if (mDpm != null) { |