diff options
| author | 2016-11-24 18:02:20 +0000 | |
|---|---|---|
| committer | 2016-11-24 18:02:23 +0000 | |
| commit | 8d4527db199b67de3a142a37adaa887bd026c22c (patch) | |
| tree | c0a419a3388e51ad44e5faec30c5d7d2c5b24240 | |
| parent | 5ce42bba5080fec4987a4a9ae2b93978d2266c35 (diff) | |
| parent | fc291bcbe007692ab7a6de0651769b1f2e09de49 (diff) | |
Merge "Add getBindDeviceAdminTargetUsers API"
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rw-r--r-- | api/system-current.txt | 1 | ||||
| -rw-r--r-- | api/test-current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/app/admin/DevicePolicyManager.java | 36 | ||||
| -rw-r--r-- | core/java/android/app/admin/IDevicePolicyManager.aidl | 1 | ||||
| -rw-r--r-- | services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java | 130 |
6 files changed, 120 insertions, 50 deletions
diff --git a/api/current.txt b/api/current.txt index 33564a28ddf3..e42913c57d98 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6007,6 +6007,7 @@ package android.app.admin { method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String); method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName); method public boolean getAutoTimeRequired(); + method public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(android.content.ComponentName); method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName); method public boolean getCameraDisabled(android.content.ComponentName); method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException; diff --git a/api/system-current.txt b/api/system-current.txt index 150d92515845..873f0215d16c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6179,6 +6179,7 @@ package android.app.admin { method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String); method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName); method public boolean getAutoTimeRequired(); + method public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(android.content.ComponentName); method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName); method public boolean getCameraDisabled(android.content.ComponentName); method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException; diff --git a/api/test-current.txt b/api/test-current.txt index 0730cc4a5216..4f2bea5956a0 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -6023,6 +6023,7 @@ package android.app.admin { method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String); method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName); method public boolean getAutoTimeRequired(); + method public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(android.content.ComponentName); method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName); method public boolean getCameraDisabled(android.content.ComponentName); method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index ef1e55a5880b..2fa231863810 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -6713,11 +6713,14 @@ public class DevicePolicyManager { } /** - * Called by device owner/ profile owner in managed profile to bind the service with each other. + * Called by a device owner to bind to a service from a profile owner of a managed profile or + * vice versa. See {@link #getBindDeviceAdminTargetUsers} for a definition of which + * device/profile owners are allowed to bind to services of another profile/device owner. + * <p> * The service must be unexported. Note that the {@link Context} used to obtain this * {@link DevicePolicyManager} instance via {@link Context#getSystemService(Class)} will be used * to bind to the {@link android.app.Service}. - * STOPSHIP (b/31952368): Update the javadoc after we policy to control which packages can talk. + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param serviceIntent Identifies the service to connect to. The Intent must specify either an * explicit component name or a package name to match an @@ -6726,11 +6729,15 @@ public class DevicePolicyManager { * valid {@link ServiceConnection} object; it must not be {@code null}. * @param flags Operation options for the binding operation. See * {@link Context#bindService(Intent, ServiceConnection, int)}. - * @param targetUser Which user to bind to. + * @param targetUser Which user to bind to. Must be one of the users returned by + * {@link #getBindDeviceAdminTargetUsers}, otherwise a {@link SecurityException} will + * be thrown. * @return If you have successfully bound to the service, {@code true} is returned; * {@code false} is returned if the connection is not made and you will not * receive the service object. + * * @see Context#bindService(Intent, ServiceConnection, int) + * @see #getBindDeviceAdminTargetUsers(ComponentName) */ public boolean bindDeviceAdminServiceAsUser( @NonNull ComponentName admin, Intent serviceIntent, @NonNull ServiceConnection conn, @@ -6749,6 +6756,29 @@ public class DevicePolicyManager { } /** + * Returns the list of target users that the calling device or profile owner can use when + * calling {@link #bindDeviceAdminServiceAsUser}. + * <p> + * A device owner can bind to a service from a profile owner of a managed profile and + * vice versa, provided that: + * <ul> + * <li>Both belong to the same package name. + * <li>The managed profile is a profile of the user where the device owner is set. + * See {@link UserManager#getUserProfiles()} + * <li>Both users are affiliated. + * STOPSHIP(b/32326223) Add reference to setAffiliationIds here once public. + * </ul> + */ + public @NonNull List<UserHandle> getBindDeviceAdminTargetUsers(@NonNull ComponentName admin) { + throwIfParentInstance("getBindDeviceAdminTargetUsers"); + try { + return mService.getBindDeviceAdminTargetUsers(admin); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** * Called by the system to get the time at which the device owner last retrieved security * logging entries. * diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index d14e0d0dfdf0..b7e0e9266e0e 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -325,6 +325,7 @@ interface IDevicePolicyManager { boolean bindDeviceAdminServiceAsUser(in ComponentName admin, IApplicationThread caller, IBinder token, in Intent service, IServiceConnection connection, int flags, int targetUserId); + List<UserHandle> getBindDeviceAdminTargetUsers(in ComponentName admin); long getLastSecurityLogRetrievalTime(); long getLastBugReportRequestTime(); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 29c90193d8a0..f7bb190990b0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -6634,7 +6634,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private boolean isManagedProfile(int userHandle) { - return getUserInfo(userHandle).isManagedProfile(); + final UserInfo user = getUserInfo(userHandle); + return user != null && user.isManagedProfile(); } private void enableIfNecessary(String packageName, int userId) { @@ -8903,9 +8904,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); } - final int callingUserId = mInjector.userHandleGetCallingUserId(); - final UserInfo user = getUserInfo(callingUserId); - return user != null && user.isManagedProfile(); + return isManagedProfile(mInjector.userHandleGetCallingUserId()); } @Override @@ -9537,65 +9536,97 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkNotNull(caller); Preconditions.checkNotNull(serviceIntent); Preconditions.checkNotNull(connection); - final int callingUserId = mInjector.userHandleGetCallingUserId(); - Preconditions.checkArgument(callingUserId != targetUserId, + Preconditions.checkArgument(mInjector.userHandleGetCallingUserId() != targetUserId, "target user id must be different from the calling user id"); + if (!getBindDeviceAdminTargetUsers(admin).contains(UserHandle.of(targetUserId))) { + throw new SecurityException("Not allowed to bind to target user id"); + } + + final String targetPackage; synchronized (this) { - final ActiveAdmin callingAdmin = getActiveAdminForCallerLocked(admin, - DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - // Ensure the target user is valid. - if (isDeviceOwner(callingAdmin)) { - enforceManagedProfile(targetUserId, "Target user must be a managed profile"); - } else { - // Further lock down to profile owner in managed profile. - enforceManagedProfile(callingUserId, - "Only support profile owner in managed profile."); - if (mOwners.getDeviceOwnerUserId() != targetUserId) { - throw new SecurityException("Target user must be a device owner."); - } - } + targetPackage = getOwnerPackageNameForUserLocked(targetUserId); } + final long callingIdentity = mInjector.binderClearCallingIdentity(); try { - if (!mUserManager.isSameProfileGroup(callingUserId, targetUserId)) { - throw new SecurityException( - "Can only bind service across users under the same profile group"); - } - final String targetPackage; - synchronized (this) { - targetPackage = getOwnerPackageNameForUserLocked(targetUserId); - } - // STOPSHIP(b/31952368): Add policy to control which packages can talk. - if (TextUtils.isEmpty(targetPackage) || !targetPackage.equals(admin.getPackageName())) { - throw new SecurityException("Device owner and profile owner must be the same " + - "package in order to communicate."); - } // Validate and sanitize the incoming service intent. final Intent sanitizedIntent = - createCrossUserServiceIntent(serviceIntent, targetPackage); + createCrossUserServiceIntent(serviceIntent, targetPackage, targetUserId); if (sanitizedIntent == null) { // Fail, cannot lookup the target service. throw new SecurityException("Invalid intent or failed to look up the service"); } + // Ask ActivityManager to bind it. Notice that we are binding the service with the // caller app instead of DevicePolicyManagerService. - try { - return mInjector.getIActivityManager().bindService( - caller, activtiyToken, serviceIntent, - serviceIntent.resolveTypeIfNeeded(mContext.getContentResolver()), - connection, flags, mContext.getOpPackageName(), - targetUserId) != 0; - } catch (RemoteException ex) { - // Same process, should not happen. - } + return mInjector.getIActivityManager().bindService( + caller, activtiyToken, serviceIntent, + serviceIntent.resolveTypeIfNeeded(mContext.getContentResolver()), + connection, flags, mContext.getOpPackageName(), + targetUserId) != 0; + } catch (RemoteException ex) { + // Same process, should not happen. } finally { mInjector.binderRestoreCallingIdentity(callingIdentity); } - // Fail to bind. + + // Failed to bind. return false; } + @Override + public @NonNull List<UserHandle> getBindDeviceAdminTargetUsers(@NonNull ComponentName admin) { + if (!mHasFeature) { + return Collections.emptyList(); + } + Preconditions.checkNotNull(admin); + ArrayList<UserHandle> targetUsers = new ArrayList<>(); + + synchronized (this) { + ActiveAdmin callingOwner = getActiveAdminForCallerLocked( + admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + final int callingUserId = mInjector.userHandleGetCallingUserId(); + final boolean isCallerDeviceOwner = isDeviceOwner(callingOwner); + final boolean isCallerManagedProfile = isManagedProfile(callingUserId); + if (!isCallerDeviceOwner && !isCallerManagedProfile + /* STOPSHIP(b/32326223) Reinstate when setAffiliationIds is public + || !isAffiliatedUser(callingUserId) */) { + return targetUsers; + } + + final long callingIdentity = mInjector.binderClearCallingIdentity(); + try { + String callingOwnerPackage = callingOwner.info.getComponent().getPackageName(); + for (int userId : mUserManager.getProfileIds( + callingUserId, /* enabledOnly= */ false)) { + if (userId == callingUserId) { + continue; + } + + // We only allow the device owner and a managed profile owner to bind to each + // other. + if ((isCallerManagedProfile && userId == mOwners.getDeviceOwnerUserId()) + || (isCallerDeviceOwner && isManagedProfile(userId))) { + String targetOwnerPackage = getOwnerPackageNameForUserLocked(userId); + + // Both must be the same package and be affiliated in order to bind. + if (callingOwnerPackage.equals(targetOwnerPackage) + /* STOPSHIP(b/32326223) Reinstate when setAffiliationIds is public + && isAffiliatedUser(userId)*/) { + targetUsers.add(UserHandle.of(userId)); + } + } + } + } finally { + mInjector.binderRestoreCallingIdentity(callingIdentity); + } + } + + return targetUsers; + } + /** * Return true if a given user has any accounts that'll prevent installing a device or profile * owner {@code owner}. @@ -9776,7 +9807,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Return the package name of owner in a given user. */ private String getOwnerPackageNameForUserLocked(int userId) { - return getDeviceOwnerUserId() == userId + return mOwners.getDeviceOwnerUserId() == userId ? mOwners.getDeviceOwnerPackageName() : mOwners.getProfileOwnerPackage(userId); } @@ -9787,14 +9818,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * @return Intent that have component explicitly set. {@code null} if the incoming intent * or target service is invalid. */ - private Intent createCrossUserServiceIntent ( - @NonNull Intent rawIntent, @NonNull String expectedPackageName) { + private Intent createCrossUserServiceIntent( + @NonNull Intent rawIntent, @NonNull String expectedPackageName, + @UserIdInt int targetUserId) throws RemoteException { if (rawIntent.getComponent() == null && rawIntent.getPackage() == null) { Log.e(LOG_TAG, "Service intent must be explicit (with a package name or component): " + rawIntent); return null; } - ResolveInfo info = mInjector.getPackageManager().resolveService(rawIntent, 0); + ResolveInfo info = mIPackageManager.resolveService( + rawIntent, + rawIntent.resolveTypeIfNeeded(mContext.getContentResolver()), + 0, // flags + targetUserId); if (info == null || info.serviceInfo == null) { Log.e(LOG_TAG, "Fail to look up the service: " + rawIntent); return null; |