diff --git a/api/system-current.txt b/api/system-current.txt index a71c0d3410e6d..9d8cfb836d9d1 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6250,6 +6250,7 @@ package android.app.admin { method public boolean isAdminActive(android.content.ComponentName); method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String); method public boolean isCallerApplicationRestrictionsManagingPackage(); + method public boolean isDeviceManaged(); method public boolean isDeviceOwnerApp(java.lang.String); method public boolean isLockTaskPermitted(java.lang.String); method public boolean isManagedProfile(android.content.ComponentName); diff --git a/api/test-current.txt b/api/test-current.txt index b44715b6d6946..73ea0acb1b618 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -6089,6 +6089,7 @@ package android.app.admin { method public boolean isAdminActive(android.content.ComponentName); method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String); method public boolean isCallerApplicationRestrictionsManagingPackage(); + method public boolean isDeviceManaged(); method public boolean isDeviceOwnerApp(java.lang.String); method public boolean isLockTaskPermitted(java.lang.String); method public boolean isManagedProfile(android.content.ComponentName); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 866a551a561c8..4df97d93e7466 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -3844,14 +3844,22 @@ public class DevicePolicyManager { } /** - * @return true if the device is managed by any device owner. + * Called by the system to find out whether the device is managed by a Device Owner. * - *

Requires the MANAGE_USERS permission. + * @return whether the device is managed by a Device Owner. + * @throws SecurityException if the caller is not the device owner, does not hold the + * MANAGE_USERS permission and is not the system. * * @hide */ + @SystemApi + @TestApi public boolean isDeviceManaged() { - return getDeviceOwnerComponentOnAnyUser() != null; + try { + return mService.hasDeviceOwner(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } } /** diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 3bc8cd015e702..02049ead3f335 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -132,6 +132,7 @@ interface IDevicePolicyManager { boolean setDeviceOwner(in ComponentName who, String ownerName, int userId); ComponentName getDeviceOwnerComponent(boolean callingUserOnly); + boolean hasDeviceOwner(); String getDeviceOwnerName(); void clearDeviceOwner(String packageName); int getDeviceOwnerUserId(); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index e6b1fac675720..e971ed90f2c7d 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -5979,6 +5979,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + @Override + public boolean hasDeviceOwner() { + enforceDeviceOwnerOrManageUsers(); + return mOwners.hasDeviceOwner(); + } + boolean isDeviceOwner(ActiveAdmin admin) { return isDeviceOwner(admin.info.getComponent(), admin.getUserHandle().getIdentifier()); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 350be51210f91..46d93b2427224 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -2506,6 +2506,32 @@ public class DevicePolicyManagerTest extends DpmTestBase { MoreAsserts.assertEmpty(targetUsers); } + public void testIsDeviceManaged() throws Exception { + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + setupDeviceOwner(); + + // The device owner itself, any uid holding MANAGE_USERS permission and the system can + // find out that the device has a device owner. + assertTrue(dpm.isDeviceManaged()); + mContext.binder.callingUid = 1234567; + mContext.callerPermissions.add(permission.MANAGE_USERS); + assertTrue(dpm.isDeviceManaged()); + mContext.callerPermissions.remove(permission.MANAGE_USERS); + mContext.binder.clearCallingIdentity(); + assertTrue(dpm.isDeviceManaged()); + + clearDeviceOwner(); + + // Any uid holding MANAGE_USERS permission and the system can find out that the device does + // not have a device owner. + mContext.binder.callingUid = 1234567; + mContext.callerPermissions.add(permission.MANAGE_USERS); + assertFalse(dpm.isDeviceManaged()); + mContext.callerPermissions.remove(permission.MANAGE_USERS); + mContext.binder.clearCallingIdentity(); + assertFalse(dpm.isDeviceManaged()); + } + private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) { when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);