diff options
author | Nicolas Prevot <nprevot@google.com> | 2015-04-24 15:08:01 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-04-24 15:08:02 +0000 |
commit | 7defaef1bfc05757652d3a5d00d35090397e7f3e (patch) | |
tree | 50cfedf437340a751bf4d70407a3f3347fbdb2d3 | |
parent | f74a212ffbdfdf39de128682ec174a9ee1403a9e (diff) | |
parent | 2806374f9531490296547d4e884ce9163f4ac867 (diff) | |
download | frameworks_base-7defaef1bfc05757652d3a5d00d35090397e7f3e.zip frameworks_base-7defaef1bfc05757652d3a5d00d35090397e7f3e.tar.gz frameworks_base-7defaef1bfc05757652d3a5d00d35090397e7f3e.tar.bz2 |
Merge "Restrict setting the profile/device owner with a signature-level permission."
4 files changed, 106 insertions, 57 deletions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index a20aa66..47133d4 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -2651,14 +2651,12 @@ public class DevicePolicyManager { /** * @hide - * Sets the given package as the device owner. The package must already be installed and there - * shouldn't be an existing device owner registered, for this call to succeed. Also, this - * method must be called before the device is provisioned. + * Sets the given package as the device owner. + * Same as {@link #setDeviceOwner(String, String)} but without setting a device owner name. * @param packageName the package name of the application to be registered as the device owner. * @return whether the package was successfully registered as the device owner. * @throws IllegalArgumentException if the package name is null or invalid - * @throws IllegalStateException if a device owner is already registered or the device has - * already been provisioned. + * @throws IllegalStateException If the preconditions mentioned are not met. */ public boolean setDeviceOwner(String packageName) throws IllegalArgumentException, IllegalStateException { @@ -2667,15 +2665,17 @@ public class DevicePolicyManager { /** * @hide - * Sets the given package as the device owner. The package must already be installed and there - * shouldn't be an existing device owner registered, for this call to succeed. Also, this - * method must be called before the device is provisioned. + * Sets the given package as the device owner. The package must already be installed. There + * must not already be a device owner. + * Only apps with the MANAGE_PROFILE_AND_DEVICE_OWNERS permission and the shell uid can call + * this method. + * Calling this after the setup phase of the primary user has completed is allowed only if + * the caller is the shell uid, and there are no additional users and no accounts. * @param packageName the package name of the application to be registered as the device owner. * @param ownerName the human readable name of the institution that owns this device. * @return whether the package was successfully registered as the device owner. * @throws IllegalArgumentException if the package name is null or invalid - * @throws IllegalStateException if a device owner is already registered or the device has - * already been provisioned. + * @throws IllegalStateException If the preconditions mentioned are not met. */ public boolean setDeviceOwner(String packageName, String ownerName) throws IllegalArgumentException, IllegalStateException { @@ -2961,14 +2961,18 @@ public class DevicePolicyManager { /** * @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. + * already be installed. There must not already be a profile owner for this user. + * Only apps with the MANAGE_PROFILE_AND_DEVICE_OWNERS permission and the shell uid can call + * this method. + * Calling this after the setup phase of the specified user has completed is allowed only if: + * - the caller is SYSTEM_UID. + * - or the caller is the shell uid, and there are no accounts on the specified user. * @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. + * @throws IllegalArgumentException if admin is null, the package isn't installed, or the + * preconditions mentioned are not met. */ public boolean setProfileOwner(ComponentName admin, String ownerName, int userHandle) throws IllegalArgumentException { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 62685a1..dced051 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1309,6 +1309,14 @@ <permission android:name="android.permission.MANAGE_USERS" android:protectionLevel="signature|system" /> + <!-- @hide Allows an application to set the profile owners and the device owner. + This permission is not available to third party applications.--> + <permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" + android:permissionGroup="android.permission-group.SYSTEM_TOOLS" + android:protectionLevel="signature" + android:label="@string/permlab_manageProfileAndDeviceOwners" + android:description="@string/permdesc_manageProfileAndDeviceOwners" /> + <!-- Allows an application to get full detailed information about recently running tasks, with full fidelity to the real state. @hide --> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 6f554f0..51c2062 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -699,6 +699,12 @@ discover information about which applications are used on the device.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_manageProfileAndDeviceOwners">Manage profile and device owners</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to set the profile/device owners. + [CHAR LIMIT=NONE] --> + <string name="permdesc_manageProfileAndDeviceOwners">Allows apps to set the profile owners and the device owner.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_reorderTasks">reorder running apps</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_reorderTasks">Allows the app to move tasks to the diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index eb9234a..6fc3103 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3983,15 +3983,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + " for device owner"); } synchronized (this) { - if (!allowedToSetDeviceOwnerOnDevice()) { - throw new IllegalStateException( - "Trying to set device owner but device is already provisioned."); - } - - if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) { - throw new IllegalStateException( - "Trying to set device owner but device owner is already set."); - } + enforceCanSetDeviceOwner(); // Shutting down backup manager service permanently. long ident = Binder.clearCallingIdentity(); @@ -4009,7 +4001,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Device owner is not set and does not exist, set it. mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName); } else { - // Device owner is not set but a profile owner exists, update Device owner state. + // Device owner state already exists, update it. mDeviceOwner.setDeviceOwner(packageName, ownerName); } mDeviceOwner.writeOwnerFile(); @@ -4225,43 +4217,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return false; } - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null); - - UserInfo info = mUserManager.getUserInfo(userHandle); - if (info == null) { - // User doesn't exist. - throw new IllegalArgumentException( - "Attempted to set profile owner for invalid userId: " + userHandle); - } - if (info.isGuest()) { - throw new IllegalStateException("Cannot set a profile owner on a guest"); - } - if (who == null || !DeviceOwner.isInstalledForUser(who.getPackageName(), userHandle)) { throw new IllegalArgumentException("Component " + who + " not installed for userId:" + userHandle); } synchronized (this) { - // Only SYSTEM_UID can override the userSetupComplete - if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID - && hasUserSetupCompleted(userHandle)) { - throw new IllegalStateException( - "Trying to set profile owner but user is already set-up."); - } - + enforceCanSetProfileOwner(userHandle); if (mDeviceOwner == null) { // Device owner state does not exist, create it. mDeviceOwner = DeviceOwner.createWithProfileOwner(who, ownerName, userHandle); - mDeviceOwner.writeOwnerFile(); - return true; } else { - // Device owner already exists, update it. + // Device owner state already exists, update it. mDeviceOwner.setProfileOwner(who, ownerName, userHandle); - mDeviceOwner.writeOwnerFile(); - return true; } + mDeviceOwner.writeOwnerFile(); + return true; } } @@ -4451,18 +4423,77 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } /** - * Device owner can only be set on an unprovisioned device. However, if initiated via "adb", - * we also allow it if no accounts or additional users are present on the device. + * The profile owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS + * permission. + * The profile owner can only be set before the user setup phase has completed, + * except for: + * - SYSTEM_UID + * - adb if there are not accounts. */ - private boolean allowedToSetDeviceOwnerOnDevice() { - if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) { - return true; + private void enforceCanSetProfileOwner(int userHandle) { + UserInfo info = mUserManager.getUserInfo(userHandle); + if (info == null) { + // User doesn't exist. + throw new IllegalArgumentException( + "Attempted to set profile owner for invalid userId: " + userHandle); + } + if (info.isGuest()) { + throw new IllegalStateException("Cannot set a profile owner on a guest"); + } + if (getProfileOwner(userHandle) != null) { + throw new IllegalStateException("Trying to set the profile owner, but profile owner " + + "is already set."); + } + int callingUid = Binder.getCallingUid(); + if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { + if (hasUserSetupCompleted(userHandle) && + AccountManager.get(mContext).getAccountsAsUser(userHandle).length > 0) { + throw new IllegalStateException("Not allowed to set the profile owner because " + + "there are already some accounts on the profile"); + } + return; + } + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null); + if (hasUserSetupCompleted(userHandle) + && UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) { + throw new IllegalStateException("Cannot set the profile owner on a user which is " + + "already set-up"); } + } - int callingId = Binder.getCallingUid(); - return (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID) - && mUserManager.getUserCount() == 1 - && AccountManager.get(mContext).getAccounts().length == 0; + /** + * The Device owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS + * permission. + * The device owner can only be set before the setup phase of the primary user has completed, + * except for adb if no accounts or additional users are present on the device. + */ + private void enforceCanSetDeviceOwner() { + if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) { + throw new IllegalStateException("Trying to set the device owner, but device owner " + + "is already set."); + } + int callingUid = Binder.getCallingUid(); + if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { + if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) { + return; + } + if (mUserManager.getUserCount() > 1) { + throw new IllegalStateException("Not allowed to set the device owner because there " + + "are already several users on the device"); + } + if (AccountManager.get(mContext).getAccounts().length > 0) { + throw new IllegalStateException("Not allowed to set the device owner because there " + + "are already some accounts on the device"); + } + return; + } + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null); + if (hasUserSetupCompleted(UserHandle.USER_OWNER)) { + throw new IllegalStateException("Cannot set the device owner if the device is " + + "already set-up"); + } } private void enforceCrossUserPermission(int userHandle) { |