Merge "Add getBindDeviceAdminTargetUsers API"

This commit is contained in:
TreeHugger Robot
2016-11-24 18:02:20 +00:00
committed by Android (Google) Code Review
6 changed files with 121 additions and 51 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,
@@ -6748,6 +6755,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.

View File

@@ -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();

View File

@@ -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");
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.");
}
}
if (!getBindDeviceAdminTargetUsers(admin).contains(UserHandle.of(targetUserId))) {
throw new SecurityException("Not allowed to bind to target user id");
}
final String targetPackage;
synchronized (this) {
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;