From 4f4f6f83c20162814e95e9ca0654eee89a818bde Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Tue, 28 Mar 2017 13:44:04 +0100 Subject: [PATCH] Introduce DISALLOW_BLUETOOTH_SHARING. When this restriction is enforced Bluetooth sharing option should not be present when the user tries to share something. Previously this was handled by explicitly disabling bluetooth sharing activity during managed provisioning, now this code is to be removed (see topic CLs) and the same behavior should be achieved by setting this restriction for profile owners by default. In Bluetooth: 1) Don't check restrictions on boot, it is invoked anyway through the listener during boot. 2) Ignore when the restriction is "changed" from true to true - i think it was the initial intent in that condition. 3) Disable the component for a particular user and not always the system user. This is something that has to be fixed in O I think since currently in secondary user the bluetooth itself gets disabled but the sharing thing still shows up. In DPMS: 1) Now ActiveAdmin for PO also contains a set of restrictions applied by default. 2) Now all ActiveAdmins for POs are loaded quite early. That shouldn't have huge impact though. Bug: 36249732 Test: run cts -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.ManagedProfileTest#testBluetoothSharingRestriction Test: run cts -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.DeviceOwnerTest#testBluetoothRestriction Test: runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java Change-Id: I78c4ffbd503c4a10138e8c0862a9f206f24c5631 Merged-in: I78c4ffbd503c4a10138e8c0862a9f206f24c5631 (cherry picked from commit 7f4ad75218bdd3f1bdf9022a146147eae032cc0c) --- api/current.txt | 1 + api/system-current.txt | 1 + api/test-current.txt | 1 + core/java/android/os/UserManager.java | 19 ++- .../server/BluetoothManagerService.java | 57 ++++---- .../server/pm/UserRestrictionsUtils.java | 44 +++++- .../DevicePolicyManagerService.java | 136 ++++++++++-------- .../profile_device_policies.xml | 8 ++ .../profile_owner.xml | 8 ++ .../system_device_policies.xml | 3 + ...vicePolicyManagerServiceMigrationTest.java | 110 ++++++++++---- .../DevicePolicyManagerServiceTestable.java | 10 +- .../server/devicepolicy/DpmMockContext.java | 2 +- 13 files changed, 270 insertions(+), 130 deletions(-) create mode 100644 services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_device_policies.xml create mode 100644 services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_owner.xml create mode 100644 services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/system_device_policies.xml diff --git a/api/current.txt b/api/current.txt index 227d75824cebf..241b4e43a135c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -31696,6 +31696,7 @@ package android.os { field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps"; field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill"; field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth"; + field public static final java.lang.String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing"; field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth"; field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts"; field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials"; diff --git a/api/system-current.txt b/api/system-current.txt index 157599ddfe772..80832bcce7d6e 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -34578,6 +34578,7 @@ package android.os { field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps"; field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill"; field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth"; + field public static final java.lang.String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing"; field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth"; field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts"; field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials"; diff --git a/api/test-current.txt b/api/test-current.txt index b7934a0ba9777..26526ae013813 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -31829,6 +31829,7 @@ package android.os { field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps"; field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill"; field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth"; + field public static final java.lang.String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing"; field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth"; field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts"; field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials"; diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index f95a34cd7ec85..52b2f52c452e9 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -64,7 +64,7 @@ import java.util.List; */ public class UserManager { - private static String TAG = "UserManager"; + private static final String TAG = "UserManager"; private final IUserManager mService; private final Context mContext; @@ -217,6 +217,23 @@ public class UserManager { */ public static final String DISALLOW_BLUETOOTH = "no_bluetooth"; + /** + * Specifies if outgoing bluetooth sharing is disallowed on the device. Device owner and profile + * owner can set this restriction. When it is set by device owner, all users on this device will + * be affected. + * + *

Default is true for managed profiles and false for otherwise. When a device + * upgrades to {@link android.os.Build.VERSION_CODES#O}, the system sets it for all existing + * managed profiles. + * + *

Key for user restrictions. + *

Type: Boolean + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) + * @see #getUserRestrictions() + */ + public static final String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing"; + /** * Specifies if a user is disallowed from transferring files over * USB. This can only be set by device owners and profile owners on the primary user. diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 6c18b260e18db..18b4571ca3eaf 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -18,6 +18,7 @@ package com.android.server; import android.Manifest; import android.app.ActivityManager; +import android.app.AppGlobals; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothProfile; import android.bluetooth.IBluetooth; @@ -37,11 +38,11 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.os.Binder; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -50,7 +51,6 @@ import android.os.Message; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; @@ -61,15 +61,15 @@ import android.provider.Settings.SettingNotFoundException; import android.util.Slog; import com.android.internal.util.DumpUtils; -import com.android.server.pm.PackageManagerService; +import com.android.server.pm.UserRestrictionsUtils; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantReadWriteLock; class BluetoothManagerService extends IBluetoothManager.Stub { @@ -120,7 +120,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int MESSAGE_ADD_PROXY_DELAYED = 400; private static final int MESSAGE_BIND_PROFILE_SERVICE = 401; - private static final int MAX_SAVE_RETRIES = 3; private static final int MAX_ERROR_RESTART_RETRIES = 6; // Bluetooth persisted setting is off @@ -223,22 +222,25 @@ class BluetoothManagerService extends IBluetoothManager.Stub { @Override public void onUserRestrictionsChanged(int userId, Bundle newRestrictions, Bundle prevRestrictions) { - if (!newRestrictions.containsKey(UserManager.DISALLOW_BLUETOOTH) - && !prevRestrictions.containsKey(UserManager.DISALLOW_BLUETOOTH)) { - // The relevant restriction has not changed - do nothing. - return; + if (!UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions, + UserManager.DISALLOW_BLUETOOTH, UserManager.DISALLOW_BLUETOOTH_SHARING)) { + return; // No relevant changes, nothing to do. } - final boolean bluetoothDisallowed = - newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH); - if ((mEnable || mEnableExternal) && bluetoothDisallowed) { + + final boolean disallowed = newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH); + + // DISALLOW_BLUETOOTH is a global restriction that can only be set by DO or PO on the + // system user, so we only look at the system user. + if (userId == UserHandle.USER_SYSTEM && disallowed && (mEnable || mEnableExternal)) { try { - disable(null, true); + disable(null /* packageName */, true /* persist */); } catch (RemoteException e) { - Slog.w(TAG, "Exception when disabling Bluetooth from UserRestrictionsListener", - e); + Slog.w(TAG, "Exception when disabling Bluetooth", e); } } - updateOppLauncherComponentState(bluetoothDisallowed); + final boolean sharingDisallowed = disallowed + || newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING); + updateOppLauncherComponentState(userId, sharingDisallowed); } }; @@ -994,11 +996,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { LocalServices.getService(UserManagerInternal.class); userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener); final boolean isBluetoothDisallowed = isBluetoothDisallowed(); - PackageManagerService packageManagerService = - (PackageManagerService) ServiceManager.getService("package"); - if (packageManagerService != null && !packageManagerService.isOnlyCoreApps()) { - updateOppLauncherComponentState(isBluetoothDisallowed); - } if (isBluetoothDisallowed) { return; } @@ -2074,21 +2071,21 @@ class BluetoothManagerService extends IBluetoothManager.Stub { /** * Disables BluetoothOppLauncherActivity component, so the Bluetooth sharing option is not - * offered to the user if Bluetooth is disallowed. Puts the component to its default state if - * Bluetooth is not disallowed. + * offered to the user if Bluetooth or sharing is disallowed. Puts the component to its default + * state if Bluetooth is not disallowed. * - * @param bluetoothDisallowed whether the {@link UserManager.DISALLOW_BLUETOOTH} user - * restriction was set. + * @param userId user to disable bluetooth sharing for. + * @param bluetoothSharingDisallowed whether bluetooth sharing is disallowed. */ - private void updateOppLauncherComponentState(boolean bluetoothDisallowed) { + private void updateOppLauncherComponentState(int userId, boolean bluetoothSharingDisallowed) { final ComponentName oppLauncherComponent = new ComponentName("com.android.bluetooth", "com.android.bluetooth.opp.BluetoothOppLauncherActivity"); - final int newState = bluetoothDisallowed + final int newState = bluetoothSharingDisallowed ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; try { - mContext.getPackageManager() - .setComponentEnabledSetting(oppLauncherComponent, newState, 0); + final IPackageManager imp = AppGlobals.getPackageManager(); + imp.setComponentEnabledSetting(oppLauncherComponent, newState, 0 /* flags */, userId); } catch (Exception e) { // The component was not found, do nothing. } diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 84381fe20acca..c6667a702f677 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -74,6 +74,7 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, UserManager.DISALLOW_CONFIG_BLUETOOTH, UserManager.DISALLOW_BLUETOOTH, + UserManager.DISALLOW_BLUETOOTH_SHARING, UserManager.DISALLOW_USB_FILE_TRANSFER, UserManager.DISALLOW_CONFIG_CREDENTIALS, UserManager.DISALLOW_REMOVE_USER, @@ -155,6 +156,7 @@ public class UserRestrictionsUtils { */ private static final Set GLOBAL_RESTRICTIONS = Sets.newArraySet( UserManager.DISALLOW_ADJUST_VOLUME, + UserManager.DISALLOW_BLUETOOTH_SHARING, UserManager.DISALLOW_RUN_IN_BACKGROUND, UserManager.DISALLOW_UNMUTE_MICROPHONE, UserManager.DISALLOW_UNMUTE_DEVICE @@ -167,6 +169,17 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_ADD_MANAGED_PROFILE ); + /** + * User restrictions that default to {@code true} for managed profile owners. + * + * NB: {@link UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES} is also set by default but it is + * not set to existing profile owners unless they used to have INSTALL_NON_MARKET_APPS disabled + * in settings. So it is handled separately. + */ + private static final Set DEFAULT_ENABLED_FOR_MANAGED_PROFILES = Sets.newArraySet( + UserManager.DISALLOW_BLUETOOTH_SHARING + ); + /* * Special user restrictions that are always applied to all users no matter who sets them. */ @@ -307,6 +320,13 @@ public class UserRestrictionsUtils { return DEFAULT_ENABLED_FOR_DEVICE_OWNERS; } + /** + * Returns the user restrictions that default to {@code true} for managed profile owners. + */ + public static @NonNull Set getDefaultEnabledForManagedProfiles() { + return DEFAULT_ENABLED_FOR_MANAGED_PROFILES; + } + /** * Takes restrictions that can be set by device owner, and sort them into what should be applied * globally and what should be applied only on the current user. @@ -544,8 +564,8 @@ public class UserRestrictionsUtils { public static void moveRestriction(String restrictionKey, SparseArray srcRestrictions, SparseArray destRestrictions) { for (int i = 0; i < srcRestrictions.size(); i++) { - int key = srcRestrictions.keyAt(i); - Bundle from = srcRestrictions.valueAt(i); + final int key = srcRestrictions.keyAt(i); + final Bundle from = srcRestrictions.valueAt(i); if (contains(from, restrictionKey)) { from.remove(restrictionKey); Bundle to = destRestrictions.get(key); @@ -562,4 +582,24 @@ public class UserRestrictionsUtils { } } } + + /** + * Returns whether restrictions differ between two bundles. + * @param oldRestrictions old bundle of restrictions. + * @param newRestrictions new bundle of restrictions + * @param restrictions restrictions of interest, if empty, all restrictions are checked. + */ + public static boolean restrictionsChanged(Bundle oldRestrictions, Bundle newRestrictions, + String... restrictions) { + if (restrictions.length == 0) { + return areEqual(oldRestrictions, newRestrictions); + } + for (final String restriction : restrictions) { + if (oldRestrictions.getBoolean(restriction, false) != + newRestrictions.getBoolean(restriction, false)) { + return true; + } + } + return false; + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 2f26f43b78a73..2ddce1652b612 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -1903,7 +1903,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { setDeviceOwnerSystemPropertyLocked(); findOwnerComponentIfNecessaryLocked(); migrateUserRestrictionsIfNecessaryLocked(); - setDefaultEnabledUserRestrictionsIfNecessaryLocked(); + maybeSetDefaultDeviceOwnerUserRestrictionsLocked(); // TODO PO may not have a class name either due to b/17652534. Address that too. @@ -1911,36 +1911,80 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private void setDefaultEnabledUserRestrictionsIfNecessaryLocked() { + /** Apply default restrictions that haven't been applied to device owners yet. */ + private void maybeSetDefaultDeviceOwnerUserRestrictionsLocked() { final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked(); - if (deviceOwner != null - && !UserRestrictionsUtils.getDefaultEnabledForDeviceOwner().equals( - deviceOwner.defaultEnabledRestrictionsAlreadySet)) { - Slog.i(LOG_TAG,"New user restrictions need to be set by default for the device owner"); + if (deviceOwner != null) { + maybeSetDefaultRestrictionsForAdminLocked(mOwners.getDeviceOwnerUserId(), + deviceOwner, UserRestrictionsUtils.getDefaultEnabledForDeviceOwner()); + } + } - if (VERBOSE_LOG) { - Slog.d(LOG_TAG,"Default enabled restrictions for DO: " - + UserRestrictionsUtils.getDefaultEnabledForDeviceOwner() - + ". Restrictions already enabled: " - + deviceOwner.defaultEnabledRestrictionsAlreadySet); - } - - Set restrictionsToSet = new ArraySet<>( - UserRestrictionsUtils.getDefaultEnabledForDeviceOwner()); - restrictionsToSet.removeAll(deviceOwner.defaultEnabledRestrictionsAlreadySet); - if (!restrictionsToSet.isEmpty()) { - for (String restriction : restrictionsToSet) { - deviceOwner.ensureUserRestrictions().putBoolean(restriction, true); + /** Apply default restrictions that haven't been applied to profile owners yet. */ + private void maybeSetDefaultProfileOwnerUserRestrictions() { + synchronized (this) { + for (final int userId : mOwners.getProfileOwnerKeys()) { + final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId); + // The following restrictions used to be applied to managed profiles by different + // means (via Settings or by disabling components). Now they are proper user + // restrictions so we apply them to managed profile owners. Non-managed secondary + // users didn't have those restrictions so we skip them to keep existing behavior. + if (profileOwner == null || !mUserManager.isManagedProfile(userId)) { + continue; } - deviceOwner.defaultEnabledRestrictionsAlreadySet.addAll(restrictionsToSet); - Slog.i(LOG_TAG, - "Enabled the following restrictions by default: " + restrictionsToSet); - - saveUserRestrictionsLocked(mOwners.getDeviceOwnerUserId()); + maybeSetDefaultRestrictionsForAdminLocked(userId, profileOwner, + UserRestrictionsUtils.getDefaultEnabledForManagedProfiles()); + ensureUnknownSourcesRestrictionForProfileOwnerLocked( + userId, profileOwner, false /* newOwner */); } } } + /** + * Checks whether {@link UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES} should be added to the + * set of restrictions for this profile owner. + */ + private void ensureUnknownSourcesRestrictionForProfileOwnerLocked(int userId, + ActiveAdmin profileOwner, boolean newOwner) { + if (newOwner || mInjector.settingsSecureGetIntForUser( + Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId) != 0) { + profileOwner.ensureUserRestrictions().putBoolean( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true); + saveUserRestrictionsLocked(userId); + mInjector.settingsSecurePutIntForUser( + Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId); + } + } + + /** + * Apply default restrictions that haven't been applied to a given admin yet. + */ + private void maybeSetDefaultRestrictionsForAdminLocked( + int userId, ActiveAdmin admin, Set defaultRestrictions) { + if (defaultRestrictions.equals(admin.defaultEnabledRestrictionsAlreadySet)) { + return; // The same set of default restrictions has been already applied. + } + Slog.i(LOG_TAG, "New user restrictions need to be set by default for user " + userId); + + if (VERBOSE_LOG) { + Slog.d(LOG_TAG,"Default enabled restrictions: " + + defaultRestrictions + + ". Restrictions already enabled: " + + admin.defaultEnabledRestrictionsAlreadySet); + } + + final Set restrictionsToSet = new ArraySet<>(defaultRestrictions); + restrictionsToSet.removeAll(admin.defaultEnabledRestrictionsAlreadySet); + if (!restrictionsToSet.isEmpty()) { + for (final String restriction : restrictionsToSet) { + admin.ensureUserRestrictions().putBoolean(restriction, true); + } + admin.defaultEnabledRestrictionsAlreadySet.addAll(restrictionsToSet); + Slog.i(LOG_TAG, "Enabled the following restrictions by default: " + restrictionsToSet); + saveUserRestrictionsLocked(userId); + } + } + private void setDeviceOwnerSystemPropertyLocked() { final boolean deviceProvisioned = mInjector.settingsGlobalGetInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0; @@ -2927,41 +2971,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private void ensureUnknownSourcesRestrictionForProfileOwners() { - synchronized (this) { - for (int userId : mOwners.getProfileOwnerKeys()) { - if (!mUserManager.isManagedProfile(userId) || - mInjector.settingsSecureGetIntForUser( - Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId) == 0) { - continue; - } - setUserRestrictionOnBehalfOfProfileOwnerLocked( - UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId); - mInjector.settingsSecurePutIntForUser( - Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId); - } - } - } - - private void setUserRestrictionOnBehalfOfProfileOwnerLocked(String userRestrictionKey, - int userId) { - if (UserRestrictionsUtils.isValidRestriction(userRestrictionKey) && - UserRestrictionsUtils.canProfileOwnerChange(userRestrictionKey, userId)) { - ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId); - if (profileOwner == null) { - return; - } - Bundle restrictions = profileOwner.ensureUserRestrictions(); - restrictions.putBoolean(userRestrictionKey, true); - saveUserRestrictionsLocked(userId); - } - } - private void onLockSettingsReady() { getUserData(UserHandle.USER_SYSTEM); loadOwners(); cleanUpOldUsers(); - ensureUnknownSourcesRestrictionForProfileOwners(); + maybeSetDefaultProfileOwnerUserRestrictions(); handleStartUser(UserHandle.USER_SYSTEM); // Register an observer for watching for user setup complete and settings changes. @@ -6713,8 +6727,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { enforceCanSetProfileOwnerLocked(who, userHandle, hasIncompatibleAccountsOrNonAdb); - if (getActiveAdminUncheckedLocked(who, userHandle) == null - || getUserData(userHandle).mRemovingAdmins.contains(who)) { + final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + if (admin == null || getUserData(userHandle).mRemovingAdmins.contains(who)) { throw new IllegalArgumentException("Not active admin: " + who); } @@ -6730,10 +6744,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final long id = mInjector.binderClearCallingIdentity(); try { if (mUserManager.isManagedProfile(userHandle)) { - setUserRestrictionOnBehalfOfProfileOwnerLocked( - UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userHandle); - mInjector.settingsSecurePutIntForUser( - Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userHandle); + maybeSetDefaultRestrictionsForAdminLocked(userHandle, admin, + UserRestrictionsUtils.getDefaultEnabledForManagedProfiles()); + ensureUnknownSourcesRestrictionForProfileOwnerLocked(userHandle, admin, + true /* newOwner */); } } finally { mInjector.binderRestoreCallingIdentity(id); diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_device_policies.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_device_policies.xml new file mode 100644 index 0000000000000..b162785aefef8 --- /dev/null +++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_device_policies.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_owner.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_owner.xml new file mode 100644 index 0000000000000..744042413e089 --- /dev/null +++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_owner.xml @@ -0,0 +1,8 @@ + + + + diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/system_device_policies.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/system_device_policies.xml new file mode 100644 index 0000000000000..5f9a87194bf79 --- /dev/null +++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/system_device_policies.xml @@ -0,0 +1,3 @@ + + + diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java index b440095e60cc4..be1d07bbec0be 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java @@ -15,31 +15,28 @@ */ package com.android.server.devicepolicy; -import com.android.server.LocalServices; -import com.android.server.SystemService; -import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; -import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; -import android.util.Pair; +import android.provider.Settings; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; +import com.android.server.LocalServices; +import com.android.server.SystemService; +import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable; import java.io.File; import java.util.HashMap; import java.util.Map; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.when; +import java.util.Set; public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { private DpmMockContext mContext; @@ -57,7 +54,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { public void testMigration() throws Exception { final File user10dir = mMockContext.addUser(10, 0); final File user11dir = mMockContext.addUser(11, UserInfo.FLAG_MANAGED_PROFILE); - final File user12dir = mMockContext.addUser(12, 0); + mMockContext.addUser(12, 0); setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); setUpPackageManagerForAdmin(admin2, UserHandle.getUid(10, 123)); @@ -109,16 +106,13 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { final Map newBaseRestrictions = new HashMap<>(); - doAnswer(new Answer() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - Integer userId = (Integer) invocation.getArguments()[0]; - Bundle bundle = (Bundle) invocation.getArguments()[1]; + doAnswer(invocation -> { + Integer userId = (Integer) invocation.getArguments()[0]; + Bundle bundle = (Bundle) invocation.getArguments()[1]; - newBaseRestrictions.put(userId, bundle); + newBaseRestrictions.put(userId, bundle); - return null; - } + return null; }).when(mContext.userManagerInternal).setBaseUserRestrictionsByDpmsForMigration( anyInt(), any(Bundle.class)); @@ -225,16 +219,13 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { final Map newBaseRestrictions = new HashMap<>(); - doAnswer(new Answer() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - Integer userId = (Integer) invocation.getArguments()[0]; - Bundle bundle = (Bundle) invocation.getArguments()[1]; + doAnswer(invocation -> { + Integer userId = (Integer) invocation.getArguments()[0]; + Bundle bundle = (Bundle) invocation.getArguments()[1]; - newBaseRestrictions.put(userId, bundle); + newBaseRestrictions.put(userId, bundle); - return null; - } + return null; }).when(mContext.userManagerInternal).setBaseUserRestrictionsByDpmsForMigration( anyInt(), any(Bundle.class)); @@ -278,4 +269,63 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { ), dpms.getProfileOwnerAdminLocked(UserHandle.USER_SYSTEM).ensureUserRestrictions()); } + + // Test setting default restrictions for managed profile. + public void testMigration3_managedProfileOwner() throws Exception { + // Create a managed profile user. + final File user10dir = mMockContext.addUser(10, UserInfo.FLAG_MANAGED_PROFILE); + // Profile owner package for managed profile user. + setUpPackageManagerForAdmin(admin1, UserHandle.getUid(10, 123)); + // Set up fake UserManager to make it look like a managed profile. + when(mMockContext.userManager.isManagedProfile(eq(10))).thenReturn(true); + // Set up fake Settings to make it look like INSTALL_NON_MARKET_APPS was reversed. + when(mMockContext.settings.settingsSecureGetIntForUser( + eq(Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED), + eq(0), eq(10))).thenReturn(1); + // Write policy and owners files. + DpmTestUtils.writeToFile( + (new File(mContext.systemUserDataDir, "device_policies.xml")).getAbsoluteFile(), + DpmTestUtils.readAsset(mRealTestContext, + "DevicePolicyManagerServiceMigrationTest3/system_device_policies.xml")); + DpmTestUtils.writeToFile( + (new File(user10dir, "device_policies.xml")).getAbsoluteFile(), + DpmTestUtils.readAsset(mRealTestContext, + "DevicePolicyManagerServiceMigrationTest3/profile_device_policies.xml")); + DpmTestUtils.writeToFile( + (new File(user10dir, "profile_owner.xml")).getAbsoluteFile(), + DpmTestUtils.readAsset(mRealTestContext, + "DevicePolicyManagerServiceMigrationTest3/profile_owner.xml")); + + final DevicePolicyManagerServiceTestable dpms; + + // Initialize DPM/DPMS and let it migrate the persisted information. + // (Need clearCallingIdentity() to pass permission checks.) + final long ident = mContext.binder.clearCallingIdentity(); + try { + LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); + + dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir); + + dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY); + dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED); + } finally { + mContext.binder.restoreCallingIdentity(ident); + } + + assertFalse(dpms.mOwners.hasDeviceOwner()); + assertTrue(dpms.mOwners.hasProfileOwner(10)); + + // Check that default restrictions were applied. + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, + UserManager.DISALLOW_BLUETOOTH_SHARING + ), + dpms.getProfileOwnerAdminLocked(10).ensureUserRestrictions()); + + final Set alreadySet = + dpms.getProfileOwnerAdminLocked(10).defaultEnabledRestrictionsAlreadySet; + assertEquals(alreadySet.size(), 1); + assertTrue(alreadySet.contains(UserManager.DISALLOW_BLUETOOTH_SHARING)); + } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index a6ce1d51f80ea..46da3dedc77e4 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -21,7 +21,6 @@ import android.app.PendingIntent; import android.app.backup.IBackupManager; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.pm.IPackageManager; import android.content.pm.PackageManagerInternal; import android.database.ContentObserver; @@ -56,17 +55,17 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi public static class OwnersTestable extends Owners { public static final String LEGACY_FILE = "legacy.xml"; public static final String DEVICE_OWNER_FILE = "device_owner2.xml"; - public static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml"; + public static final String PROFILE_OWNER_FILE = "profile_owner.xml"; private final File mLegacyFile; private final File mDeviceOwnerFile; - private final File mProfileOwnerBase; + private final File mUsersDataDir; public OwnersTestable(DpmMockContext context) { super(context.userManager, context.userManagerInternal, context.packageManagerInternal); mLegacyFile = new File(context.dataDir, LEGACY_FILE); mDeviceOwnerFile = new File(context.dataDir, DEVICE_OWNER_FILE); - mProfileOwnerBase = new File(context.dataDir, PROFILE_OWNER_FILE_BASE); + mUsersDataDir = new File(context.dataDir, "users"); } @Override @@ -81,7 +80,8 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi @Override File getProfileOwnerFileWithTestOverride(int userId) { - return new File(mDeviceOwnerFile.getAbsoluteFile() + "-" + userId); + final File userDir = new File(mUsersDataDir, String.valueOf(userId)); + return new File(userDir, PROFILE_OWNER_FILE); } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 1ea12d8535563..23fada46d16e9 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -468,7 +468,7 @@ public class DpmMockContext extends MockContext { when(accountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]); // Create a data directory. - final File dir = new File(dataDir, "user" + userId); + final File dir = new File(dataDir, "users/" + userId); DpmTestUtils.clearDir(dir); when(environment.getUserSystemDirectory(eq(userId))).thenReturn(dir);