Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c8a5a555 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

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
parent abef6d6f
Loading
Loading
Loading
Loading
+94 −36
Original line number Diff line number Diff line
@@ -89,6 +89,10 @@ public class DevicePolicyManager {
    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 @@ public class DevicePolicyManager {
     * 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 @@ public class DevicePolicyManager {
     * 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 @@ public class DevicePolicyManager {
    }

    /**
     * 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() {
        if (mService != null) {
            try {
                return mService.getDeviceOwnerName();
            } catch (RemoteException re) {
                Log.w(TAG, "Failed to get device owner");
            }
        }
        return null;
    public boolean isDeviceManaged() {
        return getDeviceOwnerComponentOnAnyUser() != 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.
     * 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 ComponentName getDeviceOwnerComponent() {
    public String getDeviceOwnerNameOnAnyUser() {
        if (mService != null) {
            try {
                return mService.getDeviceOwner();
                return mService.getDeviceOwnerName();
            } catch (RemoteException re) {
                Log.w(TAG, "Failed to get device owner");
                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
            }
        }
        return null;
@@ -3130,7 +3188,7 @@ public class DevicePolicyManager {

    /**
     * @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.
+2 −1
Original line number Diff line number Diff line
@@ -114,9 +114,10 @@ interface IDevicePolicyManager {
    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);
+5 −1
Original line number Diff line number Diff line
@@ -111,7 +111,9 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene

    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 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene

    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,
+2 −2
Original line number Diff line number Diff line
@@ -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();
+3 −3
Original line number Diff line number Diff line
@@ -102,13 +102,13 @@ public class SecurityControllerImpl implements SecurityController {
    }

    @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
Loading