Loading core/java/android/app/admin/DevicePolicyManagerInternal.java +14 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,10 @@ import java.util.List; /** * Device policy manager local system service interface. * * Maintenance note: if you need to expose information from DPMS to lower level services such as * PM/UM/AM/etc, then exposing it from DevicePolicyManagerInternal is not safe because it may cause * lock order inversion. Consider using {@link DevicePolicyCache} instead. * * @hide Only for use within the system server. */ public abstract class DevicePolicyManagerInternal { Loading Loading @@ -80,6 +84,16 @@ public abstract class DevicePolicyManagerInternal { */ public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy); /** * Checks if an app with given uid is the active supervision admin. * * <p>This takes the DPMS lock. DO NOT call from PM/UM/AM with their lock held. * * @param uid App uid. * @return true if the uid is the active supervision app. */ public abstract boolean isActiveSupervisionApp(int uid); /** * Creates an intent to show the admin support dialog to say that an action is disallowed by * the device/profile owner. Loading core/java/android/app/usage/UsageStatsManager.java +4 −4 Original line number Diff line number Diff line Loading @@ -801,8 +801,8 @@ public final class UsageStatsManager { * {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is * being registered with a {@code timeUsed} equal to or greater than * {@code timeLimit}. * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE * permissions. * @throws SecurityException if the caller is neither the active supervision app nor does it * have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions. * @hide */ @SystemApi Loading @@ -827,8 +827,8 @@ public final class UsageStatsManager { * an observer that was already unregistered or never registered will have no effect. * * @param observerId The id of the observer that was previously registered. * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE * permissions. * @throws SecurityException if the caller is neither the active supervision app nor does it * have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions. * @hide */ @SystemApi Loading services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +22 −0 Original line number Diff line number Diff line Loading @@ -11320,6 +11320,28 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } @Override public boolean isActiveSupervisionApp(int uid) { synchronized (getLockObject()) { final ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked( null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, uid); if (admin == null) { return false; } final String supervisionString = mContext.getResources().getString( com.android.internal.R.string .config_defaultSupervisionProfileOwnerComponent); if (supervisionString == null) { return false; } final ComponentName supervisorComponent = ComponentName.unflattenFromString( supervisionString); return admin.info.getComponent().equals(supervisorComponent); } } private void notifyCrossProfileProvidersChanged(int userId, List<String> packages) { final List<OnCrossProfileWidgetProvidersChangeListener> listeners; synchronized (getLockObject()) { Loading services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +15 −0 Original line number Diff line number Diff line Loading @@ -2650,6 +2650,21 @@ public class DevicePolicyManagerTest extends DpmTestBase { verifyStayOnWhilePluggedCleared(false); } public void testIsActiveSupervisionApp() throws Exception { when(mServiceContext.resources .getString(R.string.config_defaultSupervisionProfileOwnerComponent)) .thenReturn(admin1.flattenToString()); final int PROFILE_USER = 15; final int PROFILE_ADMIN = UserHandle.getUid(PROFILE_USER, 19436); addManagedProfile(admin1, PROFILE_ADMIN, admin1); mContext.binder.callingUid = PROFILE_ADMIN; final DevicePolicyManagerInternal dpmi = LocalServices.getService(DevicePolicyManagerInternal.class); assertTrue(dpmi.isActiveSupervisionApp(PROFILE_ADMIN)); } // Test if lock timeout on managed profile is handled correctly depending on whether profile // uses separate challenge. public void testSetMaximumTimeToLockProfile() throws Exception { Loading services/usage/java/com/android/server/usage/UsageStatsService.java +12 −8 Original line number Diff line number Diff line Loading @@ -1733,10 +1733,13 @@ public class UsageStatsService extends SystemService implements public void registerAppUsageLimitObserver(int observerId, String[] packages, long timeLimitMs, long timeUsedMs, PendingIntent callbackIntent, String callingPackage) { final int callingUid = Binder.getCallingUid(); final DevicePolicyManagerInternal dpmInternal = getDpmInternal(); if (!hasPermissions(callingPackage, Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)) { throw new SecurityException("Caller doesn't have both SUSPEND_APPS and " + "OBSERVE_APP_USAGE permissions"); Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE) && (dpmInternal != null && !dpmInternal.isActiveSupervisionApp(callingUid))) { throw new SecurityException("Caller must be the active supervision app or " + "it must have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions"); } if (packages == null || packages.length == 0) { Loading @@ -1745,7 +1748,6 @@ public class UsageStatsService extends SystemService implements if (callbackIntent == null && timeUsedMs < timeLimitMs) { throw new NullPointerException("callbackIntent can't be null"); } final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getUserId(callingUid); final long token = Binder.clearCallingIdentity(); try { Loading @@ -1758,13 +1760,15 @@ public class UsageStatsService extends SystemService implements @Override public void unregisterAppUsageLimitObserver(int observerId, String callingPackage) { final int callingUid = Binder.getCallingUid(); final DevicePolicyManagerInternal dpmInternal = getDpmInternal(); if (!hasPermissions(callingPackage, Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)) { throw new SecurityException("Caller doesn't have both SUSPEND_APPS and " + "OBSERVE_APP_USAGE permissions"); Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE) && (dpmInternal != null && !dpmInternal.isActiveSupervisionApp(callingUid))) { throw new SecurityException("Caller must be the active supervision app or " + "it must have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions"); } final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getUserId(callingUid); final long token = Binder.clearCallingIdentity(); try { Loading Loading
core/java/android/app/admin/DevicePolicyManagerInternal.java +14 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,10 @@ import java.util.List; /** * Device policy manager local system service interface. * * Maintenance note: if you need to expose information from DPMS to lower level services such as * PM/UM/AM/etc, then exposing it from DevicePolicyManagerInternal is not safe because it may cause * lock order inversion. Consider using {@link DevicePolicyCache} instead. * * @hide Only for use within the system server. */ public abstract class DevicePolicyManagerInternal { Loading Loading @@ -80,6 +84,16 @@ public abstract class DevicePolicyManagerInternal { */ public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy); /** * Checks if an app with given uid is the active supervision admin. * * <p>This takes the DPMS lock. DO NOT call from PM/UM/AM with their lock held. * * @param uid App uid. * @return true if the uid is the active supervision app. */ public abstract boolean isActiveSupervisionApp(int uid); /** * Creates an intent to show the admin support dialog to say that an action is disallowed by * the device/profile owner. Loading
core/java/android/app/usage/UsageStatsManager.java +4 −4 Original line number Diff line number Diff line Loading @@ -801,8 +801,8 @@ public final class UsageStatsManager { * {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is * being registered with a {@code timeUsed} equal to or greater than * {@code timeLimit}. * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE * permissions. * @throws SecurityException if the caller is neither the active supervision app nor does it * have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions. * @hide */ @SystemApi Loading @@ -827,8 +827,8 @@ public final class UsageStatsManager { * an observer that was already unregistered or never registered will have no effect. * * @param observerId The id of the observer that was previously registered. * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE * permissions. * @throws SecurityException if the caller is neither the active supervision app nor does it * have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions. * @hide */ @SystemApi Loading
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +22 −0 Original line number Diff line number Diff line Loading @@ -11320,6 +11320,28 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } @Override public boolean isActiveSupervisionApp(int uid) { synchronized (getLockObject()) { final ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked( null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, uid); if (admin == null) { return false; } final String supervisionString = mContext.getResources().getString( com.android.internal.R.string .config_defaultSupervisionProfileOwnerComponent); if (supervisionString == null) { return false; } final ComponentName supervisorComponent = ComponentName.unflattenFromString( supervisionString); return admin.info.getComponent().equals(supervisorComponent); } } private void notifyCrossProfileProvidersChanged(int userId, List<String> packages) { final List<OnCrossProfileWidgetProvidersChangeListener> listeners; synchronized (getLockObject()) { Loading
services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +15 −0 Original line number Diff line number Diff line Loading @@ -2650,6 +2650,21 @@ public class DevicePolicyManagerTest extends DpmTestBase { verifyStayOnWhilePluggedCleared(false); } public void testIsActiveSupervisionApp() throws Exception { when(mServiceContext.resources .getString(R.string.config_defaultSupervisionProfileOwnerComponent)) .thenReturn(admin1.flattenToString()); final int PROFILE_USER = 15; final int PROFILE_ADMIN = UserHandle.getUid(PROFILE_USER, 19436); addManagedProfile(admin1, PROFILE_ADMIN, admin1); mContext.binder.callingUid = PROFILE_ADMIN; final DevicePolicyManagerInternal dpmi = LocalServices.getService(DevicePolicyManagerInternal.class); assertTrue(dpmi.isActiveSupervisionApp(PROFILE_ADMIN)); } // Test if lock timeout on managed profile is handled correctly depending on whether profile // uses separate challenge. public void testSetMaximumTimeToLockProfile() throws Exception { Loading
services/usage/java/com/android/server/usage/UsageStatsService.java +12 −8 Original line number Diff line number Diff line Loading @@ -1733,10 +1733,13 @@ public class UsageStatsService extends SystemService implements public void registerAppUsageLimitObserver(int observerId, String[] packages, long timeLimitMs, long timeUsedMs, PendingIntent callbackIntent, String callingPackage) { final int callingUid = Binder.getCallingUid(); final DevicePolicyManagerInternal dpmInternal = getDpmInternal(); if (!hasPermissions(callingPackage, Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)) { throw new SecurityException("Caller doesn't have both SUSPEND_APPS and " + "OBSERVE_APP_USAGE permissions"); Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE) && (dpmInternal != null && !dpmInternal.isActiveSupervisionApp(callingUid))) { throw new SecurityException("Caller must be the active supervision app or " + "it must have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions"); } if (packages == null || packages.length == 0) { Loading @@ -1745,7 +1748,6 @@ public class UsageStatsService extends SystemService implements if (callbackIntent == null && timeUsedMs < timeLimitMs) { throw new NullPointerException("callbackIntent can't be null"); } final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getUserId(callingUid); final long token = Binder.clearCallingIdentity(); try { Loading @@ -1758,13 +1760,15 @@ public class UsageStatsService extends SystemService implements @Override public void unregisterAppUsageLimitObserver(int observerId, String callingPackage) { final int callingUid = Binder.getCallingUid(); final DevicePolicyManagerInternal dpmInternal = getDpmInternal(); if (!hasPermissions(callingPackage, Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)) { throw new SecurityException("Caller doesn't have both SUSPEND_APPS and " + "OBSERVE_APP_USAGE permissions"); Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE) && (dpmInternal != null && !dpmInternal.isActiveSupervisionApp(callingUid))) { throw new SecurityException("Caller must be the active supervision app or " + "it must have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions"); } final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getUserId(callingUid); final long token = Binder.clearCallingIdentity(); try { Loading