diff --git a/api/current.txt b/api/current.txt index ec38436deb3df..d7493e9c0aeac 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5740,6 +5740,7 @@ package android.app.admin { method public java.lang.String[] getAccountTypesWithManagementDisabled(); method public java.util.List getActiveAdmins(); method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String); + method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName); method public boolean getAutoTimeRequired(); method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName); method public boolean getCameraDisabled(android.content.ComponentName); @@ -5783,6 +5784,7 @@ package android.app.admin { method public boolean isActivePasswordSufficient(); method public boolean isAdminActive(android.content.ComponentName); method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String); + method public boolean isCallerApplicationRestrictionsManagingPackage(); method public boolean isDeviceOwnerApp(java.lang.String); method public boolean isLockTaskPermitted(java.lang.String); method public boolean isMasterVolumeMuted(android.content.ComponentName); @@ -5798,6 +5800,7 @@ package android.app.admin { method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean); method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean); method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle); + method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String); method public void setAutoTimeRequired(android.content.ComponentName, boolean); method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean); method public void setCameraDisabled(android.content.ComponentName, boolean); diff --git a/api/system-current.txt b/api/system-current.txt index d89e2ca5aaf56..f6e427aeb6cfd 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5865,6 +5865,7 @@ package android.app.admin { method public java.lang.String[] getAccountTypesWithManagementDisabled(); method public java.util.List getActiveAdmins(); method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String); + method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName); method public boolean getAutoTimeRequired(); method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName); method public boolean getCameraDisabled(android.content.ComponentName); @@ -5915,6 +5916,7 @@ package android.app.admin { method public boolean isActivePasswordSufficient(); method public boolean isAdminActive(android.content.ComponentName); method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String); + method public boolean isCallerApplicationRestrictionsManagingPackage(); method public boolean isDeviceOwnerApp(java.lang.String); method public boolean isLockTaskPermitted(java.lang.String); method public boolean isMasterVolumeMuted(android.content.ComponentName); @@ -5932,6 +5934,7 @@ package android.app.admin { method public deprecated boolean setActiveProfileOwner(android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException; method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean); method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle); + method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String); method public void setAutoTimeRequired(android.content.ComponentName, boolean); method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean); method public void setCameraDisabled(android.content.ComponentName, boolean); diff --git a/api/test-current.txt b/api/test-current.txt index 7cc7cb6bb370b..25bd3ad4f53f2 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5740,6 +5740,7 @@ package android.app.admin { method public java.lang.String[] getAccountTypesWithManagementDisabled(); method public java.util.List getActiveAdmins(); method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String); + method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName); method public boolean getAutoTimeRequired(); method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName); method public boolean getCameraDisabled(android.content.ComponentName); @@ -5783,6 +5784,7 @@ package android.app.admin { method public boolean isActivePasswordSufficient(); method public boolean isAdminActive(android.content.ComponentName); method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String); + method public boolean isCallerApplicationRestrictionsManagingPackage(); method public boolean isDeviceOwnerApp(java.lang.String); method public boolean isLockTaskPermitted(java.lang.String); method public boolean isMasterVolumeMuted(android.content.ComponentName); @@ -5798,6 +5800,7 @@ package android.app.admin { method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean); method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean); method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle); + method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String); method public void setAutoTimeRequired(android.content.ComponentName, boolean); method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean); method public void setCameraDisabled(android.content.ComponentName, boolean); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 660ce3bd0a445..d9cd3ccaa7934 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -3312,8 +3312,69 @@ public class DevicePolicyManager { } /** - * Called by a profile or device owner to set the application restrictions for a given target - * application running in the profile. + * Called by a profile owner or device owner to grant permission to a package to manage + * application restrictions for the calling user via {@link #setApplicationRestrictions} and + * {@link #getApplicationRestrictions}. + *

+ * This permission is persistent until it is later cleared by calling this method with a + * {@code null} value or uninstalling the managing package. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param packageName The package name which will be given access to application restrictions + * APIs. If {@code null} is given the current package will be cleared. + */ + public void setApplicationRestrictionsManagingPackage(@NonNull ComponentName admin, + @Nullable String packageName) { + if (mService != null) { + try { + mService.setApplicationRestrictionsManagingPackage(admin, packageName); + } catch (RemoteException e) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); + } + } + } + + /** + * Called by a profile owner or device owner to retrieve the application restrictions managing + * package for the current user, or {@code null} if none is set. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return The package name allowed to manage application restrictions on the current user, or + * {@code null} if none is set. + */ + public String getApplicationRestrictionsManagingPackage(@NonNull ComponentName admin) { + if (mService != null) { + try { + return mService.getApplicationRestrictionsManagingPackage(admin); + } catch (RemoteException e) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); + } + } + return null; + } + + /** + * Returns {@code true} if the calling package has been granted permission via + * {@link #setApplicationRestrictionsManagingPackage} to manage application + * restrictions for the calling user. + */ + public boolean isCallerApplicationRestrictionsManagingPackage() { + if (mService != null) { + try { + return mService.isCallerApplicationRestrictionsManagingPackage(); + } catch (RemoteException e) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); + } + } + return false; + } + + /** + * Sets the application restrictions for a given target application running in the calling user. + * + *

The caller must be a profile or device owner on that user, or the package allowed to + * manage application restrictions via {@link #setApplicationRestrictionsManagingPackage}; + * otherwise a security exception will be thrown. * *

The provided {@link Bundle} consists of key-value pairs, where the types of values may be: *

    @@ -3323,24 +3384,25 @@ public class DevicePolicyManager { *
  • From {@link android.os.Build.VERSION_CODES#M}, {@code Bundle} or {@code Bundle[]} *
* - *

The application restrictions are only made visible to the target application and the - * profile or device owner. - * *

If the restrictions are not available yet, but may be applied in the near future, - * the admin can notify the target application of that by adding + * the caller can notify the target application of that by adding * {@link UserManager#KEY_RESTRICTIONS_PENDING} to the settings parameter. * - *

The calling device admin must be a profile or device owner; if it is not, a security - * exception will be thrown. + *

The application restrictions are only made visible to the target application via + * {@link UserManager#getApplicationRestrictions(String)}, in addition to the profile or + * device owner, and the application restrictions managing package via + * {@link #getApplicationRestrictions}. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if called by the application restrictions managing package. * @param packageName The name of the package to update restricted settings for. * @param settings A {@link Bundle} to be parsed by the receiving application, conveying a new * set of active restrictions. * + * @see #setApplicationRestrictionsManagingPackage * @see UserManager#KEY_RESTRICTIONS_PENDING */ - public void setApplicationRestrictions(@NonNull ComponentName admin, String packageName, + public void setApplicationRestrictions(@Nullable ComponentName admin, String packageName, Bundle settings) { if (mService != null) { try { @@ -3896,19 +3958,23 @@ public class DevicePolicyManager { } /** - * Called by a profile or device owner to get the application restrictions for a given target - * application running in the profile. + * Retrieves the application restrictions for a given target application running in the calling + * user. * - *

The calling device admin must be a profile or device owner; if it is not, a security - * exception will be thrown. + *

The caller must be a profile or device owner on that user, or the package allowed to + * manage application restrictions via {@link #setApplicationRestrictionsManagingPackage}; + * otherwise a security exception will be thrown. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if called by the application restrictions managing package. * @param packageName The name of the package to fetch restricted settings of. * @return {@link Bundle} of settings corresponding to what was set last time * {@link DevicePolicyManager#setApplicationRestrictions} was called, or an empty {@link Bundle} * if no restrictions have been set. + * + * @see {@link #setApplicationRestrictionsManagingPackage} */ - public Bundle getApplicationRestrictions(@NonNull ComponentName admin, String packageName) { + public Bundle getApplicationRestrictions(@Nullable ComponentName admin, String packageName) { if (mService != null) { try { return mService.getApplicationRestrictions(admin, packageName); diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index d8cc2eaf280d3..ac5a3030ad218 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -149,6 +149,9 @@ interface IDevicePolicyManager { void setApplicationRestrictions(in ComponentName who, in String packageName, in Bundle settings); Bundle getApplicationRestrictions(in ComponentName who, in String packageName); + void setApplicationRestrictionsManagingPackage(in ComponentName admin, in String packageName); + String getApplicationRestrictionsManagingPackage(in ComponentName admin); + boolean isCallerApplicationRestrictionsManagingPackage(); void setRestrictionsProvider(in ComponentName who, in ComponentName provider); ComponentName getRestrictionsProvider(int userHandle); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 810ee6bcd5989..c9810fc4496dd 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -193,6 +193,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String ATTR_PERMISSION_POLICY = "permission-policy"; private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer"; + private static final String ATTR_APPLICATION_RESTRICTIONS_MANAGER + = "application-restrictions-manager"; private static final int STATUS_BAR_DISABLE_MASK = StatusBarManager.DISABLE_EXPAND | @@ -322,6 +324,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { boolean doNotAskCredentialsOnBoot = false; + String mApplicationRestrictionsManagingPackage; + public DevicePolicyData(int userHandle) { mUserHandle = userHandle; } @@ -1035,19 +1039,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { saveSettingsLocked(policy.mUserHandle); } - if (policy.mDelegatedCertInstallerPackage != null && - (packageName == null - || packageName.equals(policy.mDelegatedCertInstallerPackage))) { - try { - // Check if delegated cert installer package is removed. - if (mIPackageManager.getPackageInfo( - policy.mDelegatedCertInstallerPackage, 0, userHandle) == null) { - policy.mDelegatedCertInstallerPackage = null; - saveSettingsLocked(policy.mUserHandle); - } - } catch (RemoteException e) { - // Shouldn't happen - } + // Check if delegated cert installer or app restrictions managing packages are removed. + if (isRemovedPackage(packageName, policy.mDelegatedCertInstallerPackage, userHandle)) { + policy.mDelegatedCertInstallerPackage = null; + saveSettingsLocked(policy.mUserHandle); + } + if (isRemovedPackage( + packageName, policy.mApplicationRestrictionsManagingPackage, userHandle)) { + policy.mApplicationRestrictionsManagingPackage = null; + saveSettingsLocked(policy.mUserHandle); } } if (removed) { @@ -1056,6 +1056,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private boolean isRemovedPackage(String changedPackage, String targetPackage, int userHandle) { + try { + return targetPackage != null + && (changedPackage == null || changedPackage.equals(targetPackage)) + && mIPackageManager.getPackageInfo(targetPackage, 0, userHandle) == null; + } catch (RemoteException e) { + // Shouldn't happen + } + + return false; + } + /** * Unit test will subclass it to inject mocks. */ @@ -1795,6 +1807,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.attribute(null, ATTR_DELEGATED_CERT_INSTALLER, policy.mDelegatedCertInstallerPackage); } + if (policy.mApplicationRestrictionsManagingPackage != null) { + out.attribute(null, ATTR_APPLICATION_RESTRICTIONS_MANAGER, + policy.mApplicationRestrictionsManagingPackage); + } final int N = policy.mAdminList.size(); for (int i=0; i