diff options
5 files changed, 218 insertions, 31 deletions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 0e6f86e..9310bf8 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -361,6 +361,40 @@ public class DevicePolicyManager { = "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); @@ -2127,6 +2162,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 * user. Also, this method must be called before the user has been used for the first time. @@ -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()); diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index a6544e6..6ce737a 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -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); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index a506c42..9935317 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -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; } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java index f1284d8..4b60c9f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java @@ -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(); } } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index f49451e..15bea5a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -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,26 +3323,28 @@ 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; } @@ -3349,6 +3352,38 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @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) { return; @@ -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); |