Implement DISALLOW_SHARE_INTO_MANAGED_PROFILE
Add a user restriction to allow profile owners to enforce a stronger
isolation of managed profile by preventing users sharing data into
the profile. This is achieved by disabling a subset of built-in cross
profile intent filters added by ManagedProvisioning during profile
inflation.
Implementation wise, DevicePolicyManagerService listens for the restriction
change and notifies ManagedProvisioning to modify the built-in intent
filters. This is needed since ManagedProvisioning has ground truth of all
built-in intent filters and manages them. It also has the advantage that
ManagedProvisioning only needs to run when a policy change happens.
Test: cts-tradefed run cts-dev -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.ManagedProfileTest#testDisallowSharingIntoProfileFromPersonal
Test: cts-tradefed run cts-dev -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.ManagedProfileTest#testDisallowSharingIntoProfileFromProfile
Bug: 63911046
Change-Id: Ia6d12a5086627d1280325cd19d6e3a0752dae633
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index b6a094c..6964e9d 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -117,7 +117,8 @@
UserManager.DISALLOW_UNIFIED_PASSWORD,
UserManager.DISALLOW_CONFIG_LOCATION_MODE,
UserManager.DISALLOW_AIRPLANE_MODE,
- UserManager.DISALLOW_CONFIG_BRIGHTNESS
+ UserManager.DISALLOW_CONFIG_BRIGHTNESS,
+ UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE,
});
/**
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3b0937b..43ced44 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -151,6 +151,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
+import android.os.UserManagerInternal.UserRestrictionsListener;
import android.os.storage.StorageManager;
import android.provider.ContactsContract.QuickContact;
import android.provider.ContactsInternal;
@@ -703,6 +704,33 @@
}
};
+ protected static class RestrictionsListener implements UserRestrictionsListener {
+ private Context mContext;
+
+ public RestrictionsListener(Context context) {
+ mContext = context;
+ }
+
+ public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
+ Bundle prevRestrictions) {
+ final boolean newlyDisallowed =
+ newRestrictions.getBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE);
+ final boolean previouslyDisallowed =
+ prevRestrictions.getBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE);
+ final boolean restrictionChanged = (newlyDisallowed != previouslyDisallowed);
+
+ if (restrictionChanged) {
+ // Notify ManagedProvisioning to update the built-in cross profile intent filters.
+ Intent intent = new Intent(
+ DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_CHANGED);
+ intent.setPackage(MANAGED_PROVISIONING_PKG);
+ intent.putExtra(Intent.EXTRA_USER_ID, userId);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+ }
+ }
+ }
+
static class ActiveAdmin {
private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
private static final String TAG_TEST_ONLY_ADMIN = "test-only-admin";
@@ -1982,6 +2010,8 @@
LocalServices.addService(DevicePolicyManagerInternal.class, mLocalService);
mSetupContentObserver = new SetupContentObserver(mHandler);
+
+ mUserManagerInternal.addUserRestrictionsListener(new RestrictionsListener(mContext));
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 57030e4..1df0ff2 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -87,6 +87,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.devicepolicy.DevicePolicyManagerService.RestrictionsListener;
import com.android.server.pm.UserRestrictionsUtils;
import org.hamcrest.BaseMatcher;
@@ -4020,6 +4021,8 @@
dpm.setPasswordMinimumNumeric(admin1, 1);
dpm.setPasswordMinimumSymbols(admin1, 0);
+ reset(mContext.spiedContext);
+
PasswordMetrics passwordMetricsNoSymbols = new PasswordMetrics(
DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 9,
8, 2,
@@ -4069,9 +4072,16 @@
dpm.setActivePasswordState(passwordMetrics, userHandle);
dpm.reportPasswordChanged(userHandle);
+ // Drain ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED broadcasts as part of
+ // reportPasswordChanged()
+ verify(mContext.spiedContext, times(3)).sendBroadcastAsUser(
+ MockUtils.checkIntentAction(
+ DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+ MockUtils.checkUserHandle(userHandle));
+
final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED);
intent.setComponent(admin1);
- intent.putExtra(Intent.EXTRA_USER, UserHandle.of(mContext.binder.callingUid));
+ intent.putExtra(Intent.EXTRA_USER, UserHandle.of(userHandle));
verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
MockUtils.checkIntent(intent),
@@ -4482,6 +4492,45 @@
verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(null, caller);
}
+ public void testDisallowSharingIntoProfileSetRestriction() {
+ Bundle restriction = new Bundle();
+ restriction.putBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, true);
+
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ RestrictionsListener listener = new RestrictionsListener(mContext);
+ listener.onUserRestrictionsChanged(DpmMockContext.CALLER_USER_HANDLE, restriction,
+ new Bundle());
+ verifyDataSharingChangedBroadcast();
+ }
+
+ public void testDisallowSharingIntoProfileClearRestriction() {
+ Bundle restriction = new Bundle();
+ restriction.putBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, true);
+
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ RestrictionsListener listener = new RestrictionsListener(mContext);
+ listener.onUserRestrictionsChanged(DpmMockContext.CALLER_USER_HANDLE, new Bundle(),
+ restriction);
+ verifyDataSharingChangedBroadcast();
+ }
+
+ public void testDisallowSharingIntoProfileUnchanged() {
+ RestrictionsListener listener = new RestrictionsListener(mContext);
+ listener.onUserRestrictionsChanged(DpmMockContext.CALLER_USER_HANDLE, new Bundle(),
+ new Bundle());
+ verify(mContext.spiedContext, never()).sendBroadcastAsUser(any(), any());
+ }
+
+ private void verifyDataSharingChangedBroadcast() {
+ Intent expectedIntent = new Intent(
+ DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_CHANGED);
+ expectedIntent.setPackage("com.android.managedprovisioning");
+ expectedIntent.putExtra(Intent.EXTRA_USER_ID, DpmMockContext.CALLER_USER_HANDLE);
+ verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
+ MockUtils.checkIntent(expectedIntent),
+ MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
+ }
+
private void verifyCanGetOwnerInstalledCaCerts(
final ComponentName caller, final DpmMockContext callerContext) throws Exception {
final String alias = "cert";
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
index 288a8be..dec962e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -91,7 +91,8 @@
@Override
public boolean matches(Object item) {
if (item == null) return false;
- return intent.filterEquals((Intent) item);
+ if (!intent.filterEquals((Intent) item)) return false;
+ return intent.getExtras().kindofEquals(((Intent) item).getExtras());
}
@Override
public void describeTo(Description description) {