DPM.isDeviceOwnerApp() and getDeviceOwner() now check calling user

- Previously on MNC, they would return the same result regardless who
the calling user is.

- Now they properly take DO user-id into account.  Meaning, they'll
always return false and null respectively, if the calling user doesn't
run device owner.

- Note isDeviceOwnerApp() is a public API and getDeviceOwner() is
a system API.  Meaning we're changing the behavior or non-private
APIs.

- Also cleaned up hidden APIs, and gave them explicit suffixes
to avoid confusion.  Bundled code should prefer them for clarity.

Now we have:

* APIs that work cross-users: They all require MANAGE_USERS.
boolean isDeviceOwnerAppOnAnyUser(String packageName)
ComponentName getDeviceOwnerComponentOnAnyUser()

int getDeviceOwnerUserId()
boolean isDeviceOwnedByDeviceOwner()

String getDeviceOwnerNameOnAnyUser()

* APIs that work within user.  No permissions are required.

boolean isDeviceOwnerAppOnCallingUser(String packageName)
ComponentName getDeviceOwnerComponentOnCallingUser()

Bug 24676413

Change-Id: I751a907c7aaf7b019335d67065d183236effaa80
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 1c65c94..9aac170 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -89,6 +89,10 @@
     private final Context mContext;
     private final IDevicePolicyManager mService;
 
+    // TODO Use it everywhere.
+    private static final String REMOTE_EXCEPTION_MESSAGE =
+            "Failed to talk with device policy manager service";
+
     private DevicePolicyManager(Context context) {
         this(context, IDevicePolicyManager.Stub.asInterface(
                         ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)));
@@ -686,7 +690,7 @@
      * extra field. This will invoke a UI to bring the user through adding the profile owner admin
      * to remotely control restrictions on the user.
      *
-     * <p>The intent must be invoked via {@link Activity#startActivityForResult()} to receive the
+     * <p>The intent must be invoked via {@link Activity#startActivityForResult} to receive the
      * result of whether or not the user approved the action. If approved, the result will
      * be {@link Activity#RESULT_OK} and the component will be set as an active admin as well
      * as a profile owner.
@@ -2765,37 +2769,94 @@
      * the setup process.
      * @param packageName the package name of the app, to compare with the registered device owner
      * app, if any.
-     * @return whether or not the package is registered as the device owner app.  Note this method
-     * does *not* check weather the device owner is actually running on the current user.
+     * @return whether or not the package is registered as the device owner app.
      */
     public boolean isDeviceOwnerApp(String packageName) {
+        return isDeviceOwnerAppOnCallingUser(packageName);
+    }
+
+    /**
+     * @return true if a package is registered as device owner, only when it's running on the
+     * calling user.
+     *
+     * <p>Same as {@link #isDeviceOwnerApp}, but bundled code should use it for clarity.
+     * @hide
+     */
+    public boolean isDeviceOwnerAppOnCallingUser(String packageName) {
+        return isDeviceOwnerAppOnAnyUserInner(packageName, /* callingUserOnly =*/ true);
+    }
+
+    /**
+     * @return true if a package is registered as device owner, even if it's running on a different
+     * user.
+     *
+     * <p>Requires the MANAGE_USERS permission.
+     *
+     * @hide
+     */
+    public boolean isDeviceOwnerAppOnAnyUser(String packageName) {
+        return isDeviceOwnerAppOnAnyUserInner(packageName, /* callingUserOnly =*/ false);
+    }
+
+    /**
+     * @return device owner component name, only when it's running on the calling user.
+     *
+     * @hide
+     */
+    public ComponentName getDeviceOwnerComponentOnCallingUser() {
+        return getDeviceOwnerComponentInner(/* callingUserOnly =*/ true);
+    }
+
+    /**
+     * @return device owner component name, even if it's running on a different user.
+     *
+     * <p>Requires the MANAGE_USERS permission.
+     *
+     * @hide
+     */
+    public ComponentName getDeviceOwnerComponentOnAnyUser() {
+        return getDeviceOwnerComponentInner(/* callingUserOnly =*/ false);
+    }
+
+    private boolean isDeviceOwnerAppOnAnyUserInner(String packageName, boolean callingUserOnly) {
         if (packageName == null) {
             return false;
         }
-        final ComponentName deviceOwner = getDeviceOwnerComponent();
+        final ComponentName deviceOwner = getDeviceOwnerComponentInner(callingUserOnly);
         if (deviceOwner == null) {
             return false;
         }
         return packageName.equals(deviceOwner.getPackageName());
     }
 
-    /**
-     * @hide
-     * Redirect to isDeviceOwnerApp.
-     */
-    public boolean isDeviceOwner(String packageName) {
-        return isDeviceOwnerApp(packageName);
+    private ComponentName getDeviceOwnerComponentInner(boolean callingUserOnly) {
+        if (mService != null) {
+            try {
+                return mService.getDeviceOwnerComponent(callingUserOnly);
+            } catch (RemoteException re) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+            }
+        }
+        return null;
     }
 
     /**
-     * Check whether a given component is registered as a device owner.
-     * Note this method does *not* check weather the device owner is actually running on the current
-     * user.
+     * @return ID of the user who runs device owner, or {@link UserHandle#USER_NULL} if there's
+     * no device owner.
+     *
+     * <p>Requires the MANAGE_USERS permission.
      *
      * @hide
      */
-    public boolean isDeviceOwner(ComponentName who) {
-        return (who != null) && who.equals(getDeviceOwner());
+    public int getDeviceOwnerUserId() {
+        if (mService != null) {
+            try {
+                return mService.getDeviceOwnerUserId();
+            } catch (RemoteException re) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+            }
+        }
+        return UserHandle.USER_NULL;
     }
 
     /**
@@ -2818,46 +2879,43 @@
     }
 
     /**
-     * Returns the device owner package name.  Note this method will still return the device owner
-     * package name even if it's running on a different user.
+     * Returns the device owner package name, only if it's running on the calling user.
+     *
+     * <p>Bundled components should use {@code getDeviceOwnerComponentOnCallingUser()} for clarity.
      *
      * @hide
      */
     @SystemApi
     public String getDeviceOwner() {
-        final ComponentName componentName = getDeviceOwnerComponent();
-        return componentName == null ? null : componentName.getPackageName();
+        final ComponentName name = getDeviceOwnerComponentOnCallingUser();
+        return name != null ? name.getPackageName() : null;
     }
 
     /**
-     * Returns the device owner name.  Note this method will still return the device owner
-     * name even if it's running on a different user.
+     * @return true if the device is managed by any device owner.
+     *
+     * <p>Requires the MANAGE_USERS permission.
      *
      * @hide
      */
-    public String getDeviceOwnerName() {
+    public boolean isDeviceManaged() {
+        return getDeviceOwnerComponentOnAnyUser() != null;
+    }
+
+    /**
+     * Returns the device owner name.  Note this method *will* return the device owner
+     * name when it's running on a different user.
+     *
+     * <p>Requires the MANAGE_USERS permission.
+     *
+     * @hide
+     */
+    public String getDeviceOwnerNameOnAnyUser() {
         if (mService != null) {
             try {
                 return mService.getDeviceOwnerName();
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to get device owner");
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns the device owner component name.  Note this method will still return the device owner
-     * component name even if it's running on a different user.
-     *
-     * @hide
-     */
-    public ComponentName getDeviceOwnerComponent() {
-        if (mService != null) {
-            try {
-                return mService.getDeviceOwner();
-            } catch (RemoteException re) {
-                Log.w(TAG, "Failed to get device owner");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
             }
         }
         return null;
@@ -3130,7 +3188,7 @@
 
     /**
      * @hide
-     * @param user The user for whom to fetch the profile owner name, if any.
+     * @param userId The user for whom to fetch the profile owner name, if any.
      * @return the human readable name of the organisation associated with this profile owner or
      *         null if one is not set.
      * @throws IllegalArgumentException if the userId is invalid.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index fc7c2b3..e198626 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -114,9 +114,10 @@
     void reportSuccessfulPasswordAttempt(int userHandle);
 
     boolean setDeviceOwner(in ComponentName who, String ownerName, int userId);
-    ComponentName getDeviceOwner();
+    ComponentName getDeviceOwnerComponent(boolean callingUserOnly);
     String getDeviceOwnerName();
     void clearDeviceOwner(String packageName);
+    int getDeviceOwnerUserId();
 
     boolean setProfileOwner(in ComponentName who, String ownerName, int userHandle);
     ComponentName getProfileOwner(int userHandle);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 47189b0..6d8b476 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -111,7 +111,9 @@
 
     private void handleRefreshState() {
         mIsIconVisible = mSecurityController.isVpnEnabled();
-        if (mSecurityController.hasDeviceOwner()) {
+        // If the device has device owner, show "Device may be monitored", but --
+        // TODO See b/25779452 -- device owner doesn't actually have monitoring power.
+        if (mSecurityController.isDeviceManaged()) {
             mFooterTextId = R.string.device_owned_footer;
             mIsVisible = true;
         } else {
@@ -156,6 +158,8 @@
 
     private String getMessage(String deviceOwner, String profileOwner, String primaryVpn,
             String profileVpn, boolean primaryUserIsManaged) {
+        // Show a special warning when the device has device owner, but --
+        // TODO See b/25779452 -- device owner doesn't actually have monitoring power.
         if (deviceOwner != null) {
             if (primaryVpn != null) {
                 return mContext.getString(R.string.monitoring_description_vpn_app_device_owned,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
index f06e5d3..a22f988 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
@@ -16,8 +16,8 @@
 package com.android.systemui.statusbar.policy;
 
 public interface SecurityController {
-
-    boolean hasDeviceOwner();
+    /** Whether the device has device owner, even if not on this user. */
+    boolean isDeviceManaged();
     boolean hasProfileOwner();
     String getDeviceOwnerName();
     String getProfileOwnerName();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 88f028f..6ddd7a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -102,13 +102,13 @@
     }
 
     @Override
-    public boolean hasDeviceOwner() {
-        return !TextUtils.isEmpty(mDevicePolicyManager.getDeviceOwner());
+    public boolean isDeviceManaged() {
+        return mDevicePolicyManager.isDeviceManaged();
     }
 
     @Override
     public String getDeviceOwnerName() {
-        return mDevicePolicyManager.getDeviceOwnerName();
+        return mDevicePolicyManager.getDeviceOwnerNameOnAnyUser();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index cf09b84..5d1906c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -866,10 +866,11 @@
             mAppOps.checkPackage(callingUid, callerPackageName);
         }
 
-        // Check whether the caller is device owner
+        // Check whether the caller is device owner, in which case we do it silently.
         DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
-        boolean isDeviceOwner = (dpm != null) && dpm.isDeviceOwnerApp(callerPackageName);
+        boolean isDeviceOwner = (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
+                callerPackageName);
 
         final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
                 statusReceiver, packageName, isDeviceOwner, userId);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index b0e43a5..fa0aa37 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -228,7 +228,8 @@
         final boolean isInstallerRoot = (installerUid == Process.ROOT_UID);
         final boolean forcePermissionPrompt =
                 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
-        mIsInstallerDeviceOwner = (dpm != null) && dpm.isDeviceOwnerApp(installerPackageName);
+        mIsInstallerDeviceOwner = (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
+                installerPackageName);
         if ((isPermissionGranted
                         || isInstallerRoot
                         || mIsInstallerDeviceOwner)
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 21a4206..4bc79cb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13065,7 +13065,8 @@
                 ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
         try {
             if (dpm != null) {
-                final ComponentName deviceOwnerComponentName = dpm.getDeviceOwner();
+                final ComponentName deviceOwnerComponentName = dpm.getDeviceOwnerComponent(
+                        /* callingUserOnly =*/ false);
                 final String deviceOwnerPackageName = deviceOwnerComponentName == null ? null
                         : deviceOwnerComponentName.getPackageName();
                 // Does the package contains the device owner?
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 558ea58..ff829ff 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -513,7 +513,7 @@
         DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
         // restricted profile can be created if there is no DO set and the admin user has no PO
-        return dpm.getDeviceOwner() == null && dpm.getProfileOwnerAsUser(userId) == null;
+        return !dpm.isDeviceManaged() && dpm.getProfileOwnerAsUser(userId) == null;
     }
 
     /*
@@ -1599,7 +1599,7 @@
                     DevicePolicyManager devicePolicyManager = (DevicePolicyManager)
                             mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
                     if (devicePolicyManager == null
-                            || devicePolicyManager.getDeviceOwner() == null) {
+                            || !devicePolicyManager.isDeviceManaged()) {
                         flags |= UserInfo.FLAG_ADMIN;
                     }
                 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8beee73..b3b647f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2045,9 +2045,12 @@
     private void updateDeviceOwnerLocked() {
         long ident = mInjector.binderClearCallingIdentity();
         try {
-            if (getDeviceOwner() != null) {
+            // TODO This is to prevent DO from getting "clear data"ed, but it should also check the
+            // user id and also protect all other DAs too.
+            final ComponentName deviceOwnerComponent = mOwners.getDeviceOwnerComponent();
+            if (deviceOwnerComponent != null) {
                 mInjector.getIActivityManager()
-                        .updateDeviceOwner(getDeviceOwner().getPackageName());
+                        .updateDeviceOwner(deviceOwnerComponent.getPackageName());
             }
         } catch (RemoteException e) {
             // Not gonna happen.
@@ -2248,6 +2251,7 @@
             // Build and show a warning notification
             int smallIconId;
             String contentText;
+            // TODO Why does it use the DO name?  The cert APIs are all for PO. b/25772443
             final String ownerName = getDeviceOwnerName();
             if (isManagedProfile(userHandle.getIdentifier())) {
                 contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_administrator);
@@ -4600,22 +4604,46 @@
     }
 
     @Override
-    public ComponentName getDeviceOwner() {
+    public ComponentName getDeviceOwnerComponent(boolean callingUserOnly) {
         if (!mHasFeature) {
             return null;
         }
+        if (!callingUserOnly) {
+            enforceManageUsers();
+        }
         synchronized (this) {
+            if (!mOwners.hasDeviceOwner()) {
+                return null;
+            }
+            if (callingUserOnly && mInjector.userHandleGetCallingUserId() !=
+                    mOwners.getDeviceOwnerUserId()) {
+                return null;
+            }
             return mOwners.getDeviceOwnerComponent();
         }
     }
 
     @Override
+    public int getDeviceOwnerUserId() {
+        if (!mHasFeature) {
+            return UserHandle.USER_NULL;
+        }
+        enforceManageUsers();
+        synchronized (this) {
+            return mOwners.hasDeviceOwner() ? mOwners.getDeviceOwnerUserId() : UserHandle.USER_NULL;
+        }
+    }
+
+    /**
+     * Returns the "name" of the device owner.  It'll work for non-DO users too, but requires
+     * MANAGE_USERS.
+     */
+    @Override
     public String getDeviceOwnerName() {
         if (!mHasFeature) {
             return null;
         }
-        // TODO: Do we really need it?  getDeviceOwner() doesn't require it.
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        enforceManageUsers();
         synchronized (this) {
             if (!mOwners.hasDeviceOwner()) {
                 return null;
@@ -4630,7 +4658,7 @@
     // Returns the active device owner or null if there is no device owner.
     @VisibleForTesting
     ActiveAdmin getDeviceOwnerAdminLocked() {
-        ComponentName component = getDeviceOwner();
+        ComponentName component = mOwners.getDeviceOwnerComponent();
         if (component == null) {
             return null;
         }
@@ -4659,16 +4687,20 @@
         } catch (NameNotFoundException e) {
             throw new SecurityException(e);
         }
-        if (!mOwners.hasDeviceOwner() || !getDeviceOwner().getPackageName().equals(packageName)
-                || (mOwners.getDeviceOwnerUserId() != UserHandle.getUserId(callingUid))) {
-            throw new SecurityException("clearDeviceOwner can only be called by the device owner");
-        }
         synchronized (this) {
+            if (!mOwners.hasDeviceOwner()
+                    || !mOwners.getDeviceOwnerComponent().getPackageName().equals(packageName)
+                    || (mOwners.getDeviceOwnerUserId() != UserHandle.getUserId(callingUid))) {
+                throw new SecurityException(
+                        "clearDeviceOwner can only be called by the device owner");
+            }
+
             final ActiveAdmin admin = getDeviceOwnerAdminLocked();
             if (admin != null) {
                 admin.disableCamera = false;
                 admin.userRestrictions = null;
             }
+
             clearUserPoliciesLocked(new UserHandle(UserHandle.USER_SYSTEM));
 
             mOwners.clearDeviceOwner();
@@ -4857,7 +4889,7 @@
         if (!mHasFeature) {
             return null;
         }
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        enforceManageUsers();
         ComponentName profileOwner = getProfileOwner(userHandle);
         if (profileOwner == null) {
             return null;
@@ -4987,13 +5019,20 @@
         }
     }
 
+    private void enforceManageUsers() {
+        final int callingUid = mInjector.binderGetCallingUid();
+        if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) || callingUid == 0)) {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        }
+    }
+
     private void enforceCrossUserPermission(int userHandle) {
         if (userHandle < 0) {
             throw new IllegalArgumentException("Invalid userId " + userHandle);
         }
         final int callingUid = mInjector.binderGetCallingUid();
         if (userHandle == UserHandle.getUserId(callingUid)) return;
-        if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
+        if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) || callingUid == 0)) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
                     + " INTERACT_ACROSS_USERS_FULL permission");
@@ -6619,8 +6658,9 @@
                 updateReceivedTime);
 
         synchronized (this) {
-            final String deviceOwnerPackage = getDeviceOwner() == null ? null :
-                    getDeviceOwner().getPackageName();
+            final String deviceOwnerPackage =
+                    mOwners.hasDeviceOwner() ? mOwners.getDeviceOwnerComponent().getPackageName()
+                            : null;
             if (deviceOwnerPackage == null) {
                 return;
             }
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 0bd4896..79ba08d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -27,6 +27,7 @@
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
+import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Pair;
@@ -35,6 +36,7 @@
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -56,9 +58,9 @@
  *
  m FrameworksServicesTests &&
  adb install \
- -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+   -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
  adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \
- -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+   -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
 
  (mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
  */
@@ -458,6 +460,7 @@
      */
     public void testSetDeviceOwner() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
         mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
 
@@ -467,12 +470,29 @@
         // Make sure admin1 is installed on system user.
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
 
+        // Check various get APIs.
+        checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ false);
+
         // DO needs to be an DA.
         dpm.setActiveAdmin(admin1, /* replace =*/ false);
 
         // Fire!
         assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
 
+        // getDeviceOwnerComponent should return the admin1 component.
+        assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+
+        // Check various get APIs.
+        checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ true);
+
+        // getDeviceOwnerComponent should *NOT* return the admin1 component for other users.
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
         // Verify internal calls.
         verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
                 eq(admin1.getPackageName()));
@@ -485,7 +505,7 @@
                 MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
                 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
 
-        assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
+        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
 
         // Try to set a profile owner on the same user, which should fail.
         setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
@@ -502,11 +522,163 @@
         // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
     }
 
+    private void checkGetDeviceOwnerInfoApi(DevicePolicyManager dpm, boolean hasDeviceOwner) {
+        final int origCallingUser = mContext.binder.callingUid;
+        final List origPermissions = new ArrayList(mContext.callerPermissions);
+        mContext.callerPermissions.clear();
+
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
+
+        mContext.binder.callingUid = Process.SYSTEM_UID;
+
+        // TODO Test getDeviceOwnerName() too.  To do so, we need to change
+        // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
+        if (hasDeviceOwner) {
+            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+
+            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
+        } else {
+            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
+        }
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        if (hasDeviceOwner) {
+            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+
+            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
+        } else {
+            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
+        }
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        // Still with MANAGE_USERS.
+        assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+        assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+        assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+        if (hasDeviceOwner) {
+            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
+        } else {
+            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
+        }
+
+        mContext.binder.callingUid = Process.SYSTEM_UID;
+        mContext.callerPermissions.remove(permission.MANAGE_USERS);
+        // System can still call "OnAnyUser" without MANAGE_USERS.
+        if (hasDeviceOwner) {
+            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+
+            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
+        } else {
+            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
+        }
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        // Still no MANAGE_USERS.
+        if (hasDeviceOwner) {
+            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+        } else {
+            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+        }
+
+        try {
+            dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName());
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            dpm.getDeviceOwnerComponentOnAnyUser();
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            dpm.getDeviceOwnerUserId();
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            dpm.getDeviceOwnerNameOnAnyUser();
+            fail();
+        } catch (SecurityException expected) {
+        }
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        // Still no MANAGE_USERS.
+        assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+        assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+        assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+        try {
+            dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName());
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            dpm.getDeviceOwnerComponentOnAnyUser();
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            dpm.getDeviceOwnerUserId();
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            dpm.getDeviceOwnerNameOnAnyUser();
+            fail();
+        } catch (SecurityException expected) {
+        }
+
+        // Restore.
+        mContext.binder.callingUid = origCallingUser;
+        mContext.callerPermissions.addAll(origPermissions);
+    }
+
+
     /**
      * Test for: {@link DevicePolicyManager#setDeviceOwner} Package doesn't exist.
      */
     public void testSetDeviceOwner_noSuchPackage() {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
         mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
 
@@ -528,6 +700,7 @@
 
     public void testClearDeviceOwner() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
         mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
 
@@ -547,7 +720,7 @@
         verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
                 eq(admin1.getPackageName()));
 
-        assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
+        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
 
         // Set up other mocks.
         when(mContext.userManager.getUserRestrictions()).thenReturn(new Bundle());
@@ -559,13 +732,14 @@
         dpm.clearDeviceOwnerApp(admin1.getPackageName());
 
         // Now DO shouldn't be set.
-        assertNull(dpm.getDeviceOwner());
+        assertNull(dpm.getDeviceOwnerComponentOnAnyUser());
 
         // TODO Check other calls.
     }
 
     public void testClearDeviceOwner_fromDifferentUser() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
         mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
 
@@ -585,7 +759,7 @@
         verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
                 eq(admin1.getPackageName()));
 
-        assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
+        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
 
         // Now call clear from the secondary user, which should throw.
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
@@ -601,8 +775,8 @@
             assertEquals("clearDeviceOwner can only be called by the device owner", e.getMessage());
         }
 
-        // Now DO shouldn't be set.
-        assertNotNull(dpm.getDeviceOwner());
+        // DO shouldn't be removed.
+        assertTrue(dpm.isDeviceManaged());
     }
 
     public void testSetProfileOwner() throws Exception {
@@ -639,6 +813,7 @@
         mMockContext.addUser(ANOTHER_USER_ID, 0); // Add one more user.
 
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
         mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
 
@@ -667,8 +842,7 @@
         mContext.setUserRunning(DpmMockContext.CALLER_USER_HANDLE, true);
         assertTrue(dpm.setDeviceOwner(admin2, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
 
-        // Make sure it's set.
-        assertEquals(admin2, dpm.getDeviceOwnerComponent());
+        assertEquals(admin2, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
 
         // Then check getDeviceOwnerAdminLocked().
         assertEquals(admin2, dpms.getDeviceOwnerAdminLocked().info.getComponent());
@@ -692,7 +866,7 @@
         dpms.mOwners.writeDeviceOwner();
 
         // Make sure the DO component name doesn't have a class name.
-        assertEquals("", dpms.getDeviceOwner().getClassName());
+        assertEquals("", dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false).getClassName());
 
         // Then create a new DPMS to have it load the settings from files.
         when(mContext.userManager.getUserRestrictions(any(UserHandle.class)))
@@ -702,7 +876,7 @@
         // Now the DO component name is a full name.
         // *BUT* because both admin1 and admin2 belong to the same package, we think admin1 is the
         // DO.
-        assertEquals(admin1, dpms.getDeviceOwner());
+        assertEquals(admin1, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
     }
 
     public void testSetGetApplicationRestriction() {
@@ -740,6 +914,7 @@
 
     public void testSetUserRestriction_asDo() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
         mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);