Allow DO to access DevicePolicyManager.isDeviceManaged()

This CL makes DPM.isDeviceManaged() accessible to the DO so that it
can be CTS-tested.

Bug: 32692748
Test: Device policy manager unit test + CTS & GTS in separate CLs

Change-Id: I5326e86b0ffee81d04bd48f0267044463a899b78
diff --git a/api/system-current.txt b/api/system-current.txt
index a71c0d3..9d8cfb8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6250,6 +6250,7 @@
     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 b44715b..73ea0ac 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6089,6 +6089,7 @@
     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 866a551..4df97d93 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3844,14 +3844,22 @@
     }
 
     /**
-     * @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.
      *
-     * <p>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 3bc8cd0..02049ea 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -132,6 +132,7 @@
 
     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 e6b1fac..e971ed9 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 @@
         }
     }
 
+    @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 350be51..46d93b2 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 @@
         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);