diff options
| author | 2014-04-25 18:23:36 +0000 | |
|---|---|---|
| committer | 2014-04-25 18:23:37 +0000 | |
| commit | 250bb6e3e045a88022db526b074e7ab38c47d93c (patch) | |
| tree | 64eb3f1995b7f105c8a427e4897c3af940e9bf26 | |
| parent | b22aabbbd2801db0be526a64badf2efa208f19f1 (diff) | |
| parent | be46532c9fbebf3ab6498c1b78013a33f620cd31 (diff) | |
Merge "Allow profile owners to set user restrictions"
6 files changed, 126 insertions, 91 deletions
diff --git a/api/current.txt b/api/current.txt index c5dea2458cce..81362f17ce17 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4967,7 +4967,9 @@ package android.app.admin { public class DevicePolicyManager { method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName); + method public void addUserRestriction(android.content.ComponentName, java.lang.String); method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String); + method public void clearUserRestriction(android.content.ComponentName, java.lang.String); method public java.util.List<android.content.ComponentName> getActiveAdmins(); method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String); method public boolean getCameraDisabled(android.content.ComponentName); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index d7170e81dcbb..d173f19501b1 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1957,4 +1957,48 @@ public class DevicePolicyManager { } return null; } + + /** + * Called by a profile or device owner to set a user restriction specified + * by the key. + * <p> + * The calling device admin must be a profile or device owner; if it is not, + * a security exception will be thrown. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated + * with. + * @param key The key of the restriction. See the constants in + * {@link android.os.UserManager} for the list of keys. + */ + public void addUserRestriction(ComponentName admin, String key) { + if (mService != null) { + try { + mService.setUserRestriction(admin, key, true); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } + + /** + * Called by a profile or device owner to clear a user restriction specified + * by the key. + * <p> + * The calling device admin must be a profile or device owner; if it is not, + * a security exception will be thrown. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated + * with. + * @param key The key of the restriction. See the constants in + * {@link android.os.UserManager} for the list of keys. + */ + public void clearUserRestriction(ComponentName admin, String key) { + if (mService != null) { + try { + mService.setUserRestriction(admin, key, false); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 85ba58b26985..72b3c205902c 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -119,4 +119,6 @@ interface IDevicePolicyManager { void setApplicationRestrictions(in ComponentName who, in String packageName, in Bundle settings); Bundle getApplicationRestrictions(in ComponentName who, in String packageName); + + void setUserRestriction(in ComponentName who, in String key, boolean enable); } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 6a4f9700fbb6..1fe9337e7518 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -300,8 +300,7 @@ public class UserManager { /** * Sets all the user-wide restrictions for this user. - * Requires the MANAGE_USERS permission or profile/device owner - * privileges. + * Requires the MANAGE_USERS permission. * @param restrictions the Bundle containing all the restrictions. */ public void setUserRestrictions(Bundle restrictions) { @@ -310,8 +309,7 @@ public class UserManager { /** * Sets all the user-wide restrictions for the specified user. - * Requires the MANAGE_USERS permission or profile/device owner - * privileges. + * Requires the MANAGE_USERS permission. * @param restrictions the Bundle containing all the restrictions. * @param userHandle the UserHandle of the user for whom to set the restrictions. */ @@ -325,8 +323,7 @@ public class UserManager { /** * Sets the value of a specific restriction. - * Requires the MANAGE_USERS permission or profile/device owner - * privileges. + * Requires the MANAGE_USERS permission. * @param key the key of the restriction * @param value the value for the restriction */ @@ -339,8 +336,7 @@ public class UserManager { /** * @hide * Sets the value of a specific restriction on a specific user. - * Requires the {@link android.Manifest.permission#MANAGE_USERS} permission or profile/device owner - * privileges. + * Requires the MANAGE_USERS permission. * @param key the key of the restriction * @param value the value for the restriction * @param userHandle the user whose restriction is to be changed. @@ -561,7 +557,7 @@ public class UserManager { /** * Returns information for all users on this device. Requires * {@link android.Manifest.permission#MANAGE_USERS} permission. - * + * * @param excludeDying specify if the list should exclude users being * removed. * @return the list of users that were created. diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 210e151b10a7..f8103de7a2d8 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -22,7 +22,6 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.ActivityThread; -import android.app.admin.DevicePolicyManager; import android.app.IStopUserCallback; import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; @@ -263,44 +262,56 @@ public class UserManagerService extends IUserManager.Stub { if (userId != UserHandle.getCallingUserId()) { checkManageUsersPermission("getting profiles related to user " + userId); } - synchronized (mPackagesLock) { - // Getting the service here is not good for testing purposes. However, this service - // is not available when UserManagerService starts up so we need a lazy load. - - DevicePolicyManager dpm = null; - if (enabledOnly) { - dpm = (DevicePolicyManager) - mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mPackagesLock) { + return getProfilesLocked(userId, enabledOnly); } + } finally { + Binder.restoreCallingIdentity(ident); + } + } - UserInfo user = getUserInfoLocked(userId); - ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); - for (int i = 0; i < mUsers.size(); i++) { - UserInfo profile = mUsers.valueAt(i); - if (!isProfileOf(user, profile)) { - continue; - } + /** Assume permissions already checked and caller's identity cleared */ + private List<UserInfo> getProfilesLocked(int userId, boolean enabledOnly) { + // Getting the service here is not good for testing purposes. + // However, this service is not available when UserManagerService starts + // up so we need a lazy load. - if (enabledOnly && profile.isManagedProfile()) { - if (dpm != null) { - if(!dpm.isProfileEnabled(profile.id)) { - continue; - } - } else { - Log.w(LOG_TAG, - "Attempting to reach DevicePolicyManager before it was started"); - // TODO: There might be system apps that need to call this. Make sure that - // DevicePolicyManagerService is ready at that time (otherwise, any default - // value is a bad one). - throw new IllegalArgumentException(String.format( - "Attempting to get enabled profiles for %d before " - + "DevicePolicyManagerService has been started.", userId)); + DevicePolicyManager dpm = null; + if (enabledOnly) { + dpm = (DevicePolicyManager) + mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + } + + UserInfo user = getUserInfoLocked(userId); + ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); + for (int i = 0; i < mUsers.size(); i++) { + UserInfo profile = mUsers.valueAt(i); + if (!isProfileOf(user, profile)) { + continue; + } + + if (enabledOnly && profile.isManagedProfile()) { + if (dpm != null) { + if (!dpm.isProfileEnabled(profile.id)) { + continue; } + } else { + Log.w(LOG_TAG, + "Attempting to reach DevicePolicyManager before it is started"); + // TODO: There might be system apps that need to call this. + // Make sure that DevicePolicyManagerService is ready at that + // time (otherwise, any default value is a bad one). + throw new IllegalArgumentException(String.format( + "Attempting to get enabled profiles for %d before " + + "DevicePolicyManagerService has been started.", + userId)); } - users.add(profile); } - return users; + users.add(profile); } + return users; } private boolean isProfileOf(UserInfo user, UserInfo profile) { @@ -459,13 +470,13 @@ public class UserManagerService extends IUserManager.Stub { synchronized (mPackagesLock) { Bundle restrictions = mUserRestrictions.get(userId); - return restrictions != null ? restrictions : Bundle.EMPTY; + return restrictions != null ? new Bundle(restrictions) : new Bundle(); } } @Override public void setUserRestrictions(Bundle restrictions, int userId) { - checkProfileOwnerOrManageUsersPermission("setUserRestrictions"); + checkManageUsersPermission("setUserRestrictions"); if (restrictions == null) return; synchronized (mPackagesLock) { @@ -491,51 +502,14 @@ public class UserManagerService extends IUserManager.Stub { * @param message used as message if SecurityException is thrown * @throws SecurityException if the caller is not system or root */ - private final void checkManageUsersPermission(String message) { - final int uid = Binder.getCallingUid(); - - if (missingManageUsersPermission(uid)) { - throw new SecurityException("You need MANAGE_USERS permission to: " + message); - } - } - - /** - * Enforces that only the system UID, root's UID, apps that have the - * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} - * permission, the profile owner, or the device owner can make certain calls to the - * UserManager. - * - * @param message used as message if SecurityException is thrown - * @throws SecurityException if the caller is not system, root, or device - * owner - */ - private final void checkProfileOwnerOrManageUsersPermission(String message) { + private static final void checkManageUsersPermission(String message) { final int uid = Binder.getCallingUid(); - boolean isProfileOwner = false; - if (mContext != null && mContext.getPackageManager() != null) { - String[] pkgs = mContext.getPackageManager().getPackagesForUid(uid); - DevicePolicyManager dpm = - (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); - if (dpm != null) { - for (String pkg : pkgs) { - if (dpm.isDeviceOwnerApp(pkg) || dpm.isProfileOwnerApp(pkg)) { - isProfileOwner = true; - } - } - } - } - - if (missingManageUsersPermission(uid) && !isProfileOwner) { - throw new SecurityException( - "You need MANAGE_USERS permission or device owner privileges to: " + message); - } - } - - private boolean missingManageUsersPermission(int uid) { - return uid != Process.SYSTEM_UID && uid != 0 + if (uid != Process.SYSTEM_UID && uid != 0 && ActivityManager.checkComponentPermission( android.Manifest.permission.MANAGE_USERS, - uid, -1, true) != PackageManager.PERMISSION_GRANTED; + uid, -1, true) != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("You need MANAGE_USERS permission to: " + message); + } } private void writeBitmapLocked(UserInfo info, Bitmap bitmap) { @@ -1240,8 +1214,7 @@ public class UserManagerService extends IUserManager.Stub { public Bundle getApplicationRestrictionsForUser(String packageName, int userId) { if (UserHandle.getCallingUserId() != userId || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) { - checkProfileOwnerOrManageUsersPermission( - "Only system or device owner can get restrictions for other users/apps"); + checkManageUsersPermission("Only system can get restrictions for other users/apps"); } synchronized (mPackagesLock) { // Read the restrictions from XML @@ -1254,8 +1227,7 @@ public class UserManagerService extends IUserManager.Stub { int userId) { if (UserHandle.getCallingUserId() != userId || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) { - checkProfileOwnerOrManageUsersPermission( - "Only system or device owner can set restrictions for other users/apps"); + checkManageUsersPermission("Only system can set restrictions for other users/apps"); } synchronized (mPackagesLock) { // Write the restrictions to XML @@ -1357,8 +1329,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public void removeRestrictions() { - checkProfileOwnerOrManageUsersPermission( - "Only system or device owner can remove restrictions"); + checkManageUsersPermission("Only system can remove restrictions"); final int userHandle = UserHandle.getCallingUserId(); removeRestrictionsForUser(userHandle, true); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index b82a1269d3a0..f1ee280257f4 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3118,4 +3118,24 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } + + @Override + public void setUserRestriction(ComponentName who, String key, boolean enabled) { + final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); + + synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + UserManager um = UserManager.get(mContext); + long id = Binder.clearCallingIdentity(); + try { + um.setUserRestriction(key, enabled, userHandle); + } finally { + restoreCallingIdentity(id); + } + } + } } |