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

Commit bf3a9465 authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Set profile owner via an intent

priv apps can request to become a profile owner after setup has
completed. This will pop up a consent dialog (in Settings).

Also, clean up profile owner concept to be a component name.

Change-Id: I5e8532866e8018f61836c4e84fbbadb6150218ae
parent acb5b7f0
Loading
Loading
Loading
Loading
+102 −5
Original line number Diff line number Diff line
@@ -360,6 +360,40 @@ public class DevicePolicyManager {
    public static final String ACTION_ADD_DEVICE_ADMIN
            = "android.app.action.ADD_DEVICE_ADMIN";

    /**
     * @hide
     * Activity action: ask the user to add a new device administrator as the profile owner
     * for this user. Only system privileged apps that have MANAGE_USERS and MANAGE_DEVICE_ADMINS
     * permission can call this API.
     *
     * <p>The ComponentName of the profile owner admin is pass in {@link #EXTRA_DEVICE_ADMIN} 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
     * 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.
     *
     * <p>You can optionally include the {@link #EXTRA_ADD_EXPLANATION}
     * field to provide the user with additional explanation (in addition
     * to your component's description) about what is being added.
     *
     * <p>If there is already a profile owner active or the caller doesn't have the required
     * permissions, the operation will return a failure result.
     */
    @SystemApi
    public static final String ACTION_SET_PROFILE_OWNER
            = "android.app.action.SET_PROFILE_OWNER";

    /**
     * @hide
     * Name of the profile owner admin that controls the user.
     */
    @SystemApi
    public static final String EXTRA_PROFILE_OWNER_NAME
            = "android.app.extra.PROFILE_OWNER_NAME";

    /**
     * Activity action: send when any policy admin changes a policy.
     * This is generally used to find out when a new policy is in effect.
@@ -397,6 +431,7 @@ public class DevicePolicyManager {
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    public static final String ACTION_SET_NEW_PASSWORD
            = "android.app.action.SET_NEW_PASSWORD";

    /**
     * Flag used by {@link #addCrossProfileIntentFilter} to allow access of certain intents from a
     * managed profile to its parent.
@@ -2018,7 +2053,6 @@ public class DevicePolicyManager {
        return false;
    }


    /**
     * Used to determine if a particular package has been registered as a Device Owner app.
     * A device owner app is a special device admin that cannot be deactivated by the user, once
@@ -2096,6 +2130,7 @@ public class DevicePolicyManager {

    /**
     * @hide
     * @deprecated Use #ACTION_SET_PROFILE_OWNER
     * Sets the given component as an active admin and registers the package as the profile
     * owner for this user. The package must already be installed and there shouldn't be
     * an existing profile owner registered for this user. Also, this method must be called
@@ -2116,7 +2151,7 @@ public class DevicePolicyManager {
            try {
                final int myUserId = UserHandle.myUserId();
                mService.setActiveAdmin(admin, false, myUserId);
                return mService.setProfileOwner(admin.getPackageName(), ownerName, myUserId);
                return mService.setProfileOwner(admin, ownerName, myUserId);
            } catch (RemoteException re) {
                Log.w(TAG, "Failed to set profile owner " + re);
                throw new IllegalArgumentException("Couldn't set profile owner.", re);
@@ -2126,6 +2161,42 @@ public class DevicePolicyManager {
    }

    /**
     * @hide
     * Clears the active profile owner and removes all user restrictions. The caller must
     * be from the same package as the active profile owner for this user, otherwise a
     * SecurityException will be thrown.
     *
     * @param admin The component to remove as the profile owner.
     * @return
     */
    @SystemApi
    public void clearProfileOwner(ComponentName admin) {
        if (mService != null) {
            try {
                mService.clearProfileOwner(admin);
            } catch (RemoteException re) {
                Log.w(TAG, "Failed to clear profile owner " + admin + re);
            }
        }
    }

    /**
     * @hide
     * Checks if the user was already setup.
     */
    public boolean hasUserSetupCompleted() {
        if (mService != null) {
            try {
                return mService.hasUserSetupCompleted();
            } catch (RemoteException re) {
                Log.w(TAG, "Failed to check if user setup has completed");
            }
        }
        return true;
    }

    /**
     * @deprecated Use setProfileOwner(ComponentName ...)
     * @hide
     * Sets the given package as the profile owner of the given user profile. The package must
     * already be installed and there shouldn't be an existing profile owner registered for this
@@ -2139,9 +2210,35 @@ public class DevicePolicyManager {
     */
    public boolean setProfileOwner(String packageName, String ownerName, int userHandle)
            throws IllegalArgumentException {
        if (packageName == null) {
            throw new NullPointerException("packageName cannot be null");
        }
        return setProfileOwner(new ComponentName(packageName, ""), ownerName, userHandle);
    }

    /**
     * @hide
     * Sets the given component as the profile owner of the given user profile. The package must
     * already be installed and there shouldn't be an existing profile owner registered for this
     * user. Only the system can call this API if the user has already completed setup.
     * @param admin the component name to be registered as profile owner.
     * @param ownerName the human readable name of the organisation associated with this DPM.
     * @param userHandle the userId to set the profile owner for.
     * @return whether the component was successfully registered as the profile owner.
     * @throws IllegalArgumentException if admin is null, the package isn't installed, or
     *         the user has already been set up.
     */
    public boolean setProfileOwner(ComponentName admin, String ownerName, int userHandle)
            throws IllegalArgumentException {
        if (admin == null) {
            throw new NullPointerException("admin cannot be null");
        }
        if (mService != null) {
            try {
                return mService.setProfileOwner(packageName, ownerName, userHandle);
                if (ownerName == null) {
                    ownerName = "";
                }
                return mService.setProfileOwner(admin, ownerName, userHandle);
            } catch (RemoteException re) {
                Log.w(TAG, "Failed to set profile owner", re);
                throw new IllegalArgumentException("Couldn't set profile owner.", re);
@@ -2200,7 +2297,7 @@ public class DevicePolicyManager {
        if (mService != null) {
            try {
                String profileOwnerPackage = mService.getProfileOwner(
                        Process.myUserHandle().getIdentifier());
                        Process.myUserHandle().getIdentifier()).getPackageName();
                return profileOwnerPackage != null && profileOwnerPackage.equals(packageName);
            } catch (RemoteException re) {
                Log.w(TAG, "Failed to check profile owner");
@@ -2215,7 +2312,7 @@ public class DevicePolicyManager {
     * owner has been set for that user.
     * @throws IllegalArgumentException if the userId is invalid.
     */
    public String getProfileOwner() throws IllegalArgumentException {
    public ComponentName getProfileOwner() throws IllegalArgumentException {
        if (mService != null) {
            try {
                return mService.getProfileOwner(Process.myUserHandle().getIdentifier());
+4 −2
Original line number Diff line number Diff line
@@ -113,11 +113,13 @@ interface IDevicePolicyManager {
    String getDeviceOwnerName();
    void clearDeviceOwner(String packageName);

    boolean setProfileOwner(String packageName, String ownerName, int userHandle);
    String getProfileOwner(int userHandle);
    boolean setProfileOwner(in ComponentName who, String ownerName, int userHandle);
    ComponentName getProfileOwner(int userHandle);
    String getProfileOwnerName(int userHandle);
    void setProfileEnabled(in ComponentName who);
    void setProfileName(in ComponentName who, String profileName);
    void clearProfileOwner(in ComponentName who);
    boolean hasUserSetupCompleted();

    boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
    void uninstallCaCert(in ComponentName admin, in String alias);
+6 −0
Original line number Diff line number Diff line
@@ -615,6 +615,12 @@ public class UserManager {
        if (guest != null) {
            Settings.Secure.putStringForUser(context.getContentResolver(),
                    Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
            try {
                mService.setUserRestrictions(
                        mService.getDefaultGuestRestrictions(), guest.id);
            } catch (RemoteException re) {
                Log.w(TAG, "Could not update guest restrictions");
            }
        }
        return guest;
    }
+56 −10
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.devicepolicy;

import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -53,6 +54,7 @@ public class DeviceOwner {
    private static final String TAG_PROFILE_OWNER = "profile-owner";
    private static final String ATTR_NAME = "name";
    private static final String ATTR_PACKAGE = "package";
    private static final String ATTR_COMPONENT_NAME = "component";
    private static final String ATTR_USERID = "userId";

    private AtomicFile fileForWriting;
@@ -100,6 +102,7 @@ public class DeviceOwner {
    }

    /**
     * @deprecated Use a component name instead of package name
     * Creates an instance of the device owner object with the profile owner set.
     */
    static DeviceOwner createWithProfileOwner(String packageName, String ownerName, int userId) {
@@ -108,6 +111,15 @@ public class DeviceOwner {
        return owner;
    }

    /**
     * Creates an instance of the device owner object with the profile owner set.
     */
    static DeviceOwner createWithProfileOwner(ComponentName admin, String ownerName, int userId) {
        DeviceOwner owner = new DeviceOwner();
        owner.mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
        return owner;
    }

    String getDeviceOwnerPackageName() {
        return mDeviceOwner != null ? mDeviceOwner.packageName : null;
    }
@@ -124,19 +136,36 @@ public class DeviceOwner {
        mDeviceOwner = null;
    }

    /**
     * @deprecated
     */
    void setProfileOwner(String packageName, String ownerName, int userId) {
        mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName));
    }

    void setProfileOwner(ComponentName admin, String ownerName, int userId) {
        mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
    }

    void removeProfileOwner(int userId) {
        mProfileOwners.remove(userId);
    }

    /**
     * @deprecated Use getProfileOwnerComponent
     * @param userId
     * @return
     */
    String getProfileOwnerPackageName(int userId) {
        OwnerInfo profileOwner = mProfileOwners.get(userId);
        return profileOwner != null ? profileOwner.packageName : null;
    }

    ComponentName getProfileOwnerComponent(int userId) {
        OwnerInfo profileOwner = mProfileOwners.get(userId);
        return profileOwner != null ? profileOwner.admin : null;
    }

    String getProfileOwnerName(int userId) {
        OwnerInfo profileOwner = mProfileOwners.get(userId);
        return profileOwner != null ? profileOwner.name : null;
@@ -191,15 +220,23 @@ public class DeviceOwner {

                String tag = parser.getName();
                if (tag.equals(TAG_DEVICE_OWNER)) {
                    mDeviceOwner = new OwnerInfo(
                            parser.getAttributeValue(null, ATTR_NAME),
                            parser.getAttributeValue(null, ATTR_PACKAGE));
                    String name = parser.getAttributeValue(null, ATTR_NAME);
                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                    mDeviceOwner = new OwnerInfo(name, packageName);
                } else if (tag.equals(TAG_PROFILE_OWNER)) {
                    String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                    String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
                    String profileOwnerComponentStr =
                            parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
                    int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
                    mProfileOwners.put(userId,
                            new OwnerInfo(profileOwnerName, profileOwnerPackageName));
                    OwnerInfo profileOwnerInfo;
                    if (profileOwnerComponentStr != null) {
                        profileOwnerInfo = new OwnerInfo(profileOwnerName,
                                ComponentName.unflattenFromString(profileOwnerComponentStr));
                    } else {
                        profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName);
                    }
                    mProfileOwners.put(userId, profileOwnerInfo);
                } else {
                    throw new XmlPullParserException(
                            "Unexpected tag in device owner file: " + tag);
@@ -230,9 +267,6 @@ public class DeviceOwner {
            if (mDeviceOwner != null) {
                out.startTag(null, TAG_DEVICE_OWNER);
                out.attribute(null, ATTR_PACKAGE, mDeviceOwner.packageName);
                if (mDeviceOwner.packageName != null) {
                    out.attribute(null, ATTR_NAME, mDeviceOwner.packageName);
                }
                out.endTag(null, TAG_DEVICE_OWNER);
            }

@@ -240,9 +274,13 @@ public class DeviceOwner {
            if (mProfileOwners.size() > 0) {
                for (HashMap.Entry<Integer, OwnerInfo> owner : mProfileOwners.entrySet()) {
                    out.startTag(null, TAG_PROFILE_OWNER);
                    out.attribute(null, ATTR_PACKAGE, owner.getValue().packageName);
                    out.attribute(null, ATTR_NAME, owner.getValue().name);
                    OwnerInfo ownerInfo = owner.getValue();
                    out.attribute(null, ATTR_PACKAGE, ownerInfo.packageName);
                    out.attribute(null, ATTR_NAME, ownerInfo.name);
                    out.attribute(null, ATTR_USERID, Integer.toString(owner.getKey()));
                    if (ownerInfo.admin != null) {
                        out.attribute(null, ATTR_COMPONENT_NAME, ownerInfo.admin.flattenToString());
                    }
                    out.endTag(null, TAG_PROFILE_OWNER);
                }
            }
@@ -282,10 +320,18 @@ public class DeviceOwner {
    static class OwnerInfo {
        public String name;
        public String packageName;
        public ComponentName admin;

        public OwnerInfo(String name, String packageName) {
            this.name = name;
            this.packageName = packageName;
            this.admin = new ComponentName(packageName, "");
        }

        public OwnerInfo(String name, ComponentName admin) {
            this.name = name;
            this.admin = admin;
            this.packageName = admin.getPackageName();
        }
    }
}
+50 −14
Original line number Diff line number Diff line
@@ -905,7 +905,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        for (ActiveAdmin admin : candidates) {
            boolean ownsDevice = isDeviceOwner(admin.info.getPackageName());
            boolean ownsProfile = (getProfileOwner(userHandle) != null
                    && getProfileOwner(userHandle).equals(admin.info.getPackageName()));
                    && getProfileOwner(userHandle).getPackageName()
                        .equals(admin.info.getPackageName()));

            if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
                if (ownsDevice) {
@@ -3310,7 +3311,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    }

    @Override
    public boolean setProfileOwner(String packageName, String ownerName, int userHandle) {
    public boolean setProfileOwner(ComponentName who, String ownerName, int userHandle) {
        if (!mHasFeature) {
            return false;
        }
@@ -3322,32 +3323,66 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                    "Attempted to set profile owner for invalid userId: " + userHandle);
        }

        if (packageName == null
                || !DeviceOwner.isInstalledForUser(packageName, userHandle)) {
            throw new IllegalArgumentException("Package name " + packageName
        if (who == null
                || !DeviceOwner.isInstalledForUser(who.getPackageName(), userHandle)) {
            throw new IllegalArgumentException("Component " + who
                    + " not installed for userId:" + userHandle);
        }
        synchronized (this) {
            if (isUserSetupComplete(userHandle)) {
            // Only SYSTEM_UID can override the userSetupComplete
            if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID
                    && isUserSetupComplete(userHandle)) {
                throw new IllegalStateException(
                        "Trying to set profile owner but user is already set-up.");
            }

            if (mDeviceOwner == null) {
                // Device owner state does not exist, create it.
                mDeviceOwner = DeviceOwner.createWithProfileOwner(packageName, ownerName,
                mDeviceOwner = DeviceOwner.createWithProfileOwner(who, ownerName,
                        userHandle);
                mDeviceOwner.writeOwnerFile();
                return true;
            } else {
                // Device owner already exists, update it.
                mDeviceOwner.setProfileOwner(packageName, ownerName, userHandle);
                mDeviceOwner.setProfileOwner(who, ownerName, userHandle);
                mDeviceOwner.writeOwnerFile();
                return true;
            }
        }
    }

    @Override
    public void clearProfileOwner(ComponentName who) {
        if (!mHasFeature) {
            return;
        }
        UserHandle callingUser = Binder.getCallingUserHandle();
        // Check if this is the profile owner who is calling
        getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
        synchronized (this) {
            long ident = Binder.clearCallingIdentity();
            try {
                mUserManager.setUserRestrictions(new Bundle(), callingUser);
                if (mDeviceOwner != null) {
                    mDeviceOwner.removeProfileOwner(callingUser.getIdentifier());
                    mDeviceOwner.writeOwnerFile();
                }
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    }

    @Override
    public boolean hasUserSetupCompleted() {
        if (!mHasFeature) {
            return true;
        }
        DevicePolicyData policy = getUserData(UserHandle.getCallingUserId());
        // If policy is null, return true, else check if the setup has completed.
        return policy == null || policy.mUserSetupComplete;
    }

    @Override
    public void setProfileEnabled(ComponentName who) {
        if (!mHasFeature) {
@@ -3397,14 +3432,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    }

    @Override
    public String getProfileOwner(int userHandle) {
    public ComponentName getProfileOwner(int userHandle) {
        if (!mHasFeature) {
            return null;
        }

        synchronized (this) {
            if (mDeviceOwner != null) {
                return mDeviceOwner.getProfileOwnerPackageName(userHandle);
                return mDeviceOwner.getProfileOwnerComponent(userHandle);
            }
        }
        return null;
@@ -3413,8 +3448,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    // Returns the active profile owner for this user or null if the current user has no
    // profile owner.
    private ActiveAdmin getProfileOwnerAdmin(int userHandle) {
        String profileOwnerPackage = getProfileOwner(userHandle);
        if (profileOwnerPackage == null) {
        ComponentName profileOwner =
                mDeviceOwner != null ? mDeviceOwner.getProfileOwnerComponent(userHandle) : null;
        if (profileOwner == null) {
            return null;
        }

@@ -3422,7 +3458,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        final int n = policy.mAdminList.size();
        for (int i = 0; i < n; i++) {
            ActiveAdmin admin = policy.mAdminList.get(i);
            if (profileOwnerPackage.equals(admin.info.getPackageName())) {
            if (profileOwner.equals(admin.info)) {
                return admin;
            }
        }
@@ -3800,7 +3836,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            }

            setActiveAdmin(profileOwnerComponent, true, user.getIdentifier(), adminExtras);
            setProfileOwner(profileOwnerPkg, ownerName, user.getIdentifier());
            setProfileOwner(profileOwnerComponent, ownerName, user.getIdentifier());
            return user;
        } finally {
            restoreCallingIdentity(id);