diff options
| author | 2023-01-16 11:01:56 +0000 | |
|---|---|---|
| committer | 2023-01-18 11:28:17 +0000 | |
| commit | 75f28f8e5e88e317a1571b68587dbefde201c0ef (patch) | |
| tree | e3638c1c2dde800c464a1d42a33b87de6eb0dec5 | |
| parent | cefe8382f360371f821c79da197added908dfd96 (diff) | |
Return STATUS_HEADLESS_SYSTEM_USER_MODE_NOT_SUPPORTED if the DO doesn't
specify the correct metadata.
Test: btest android.devicepolicy.cts.ProvisioningTest
Bug: 241553133
Change-Id: Icd725ca38c21134f40753330554ace3e70a310e1
6 files changed, 94 insertions, 34 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 4b1335e0d6d6..644cb60bdcc6 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -7408,6 +7408,7 @@ package android.app.admin { method public void dump(android.util.Printer, String); method public android.content.pm.ActivityInfo getActivityInfo(); method @NonNull public android.content.ComponentName getComponent(); + method public int getHeadlessDeviceOwnerMode(); method public String getPackageName(); method public String getReceiverName(); method public String getTagForPolicy(int); @@ -7419,6 +7420,8 @@ package android.app.admin { method public boolean usesPolicy(int); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.DeviceAdminInfo> CREATOR; + field public static final int HEADLESS_DEVICE_OWNER_MODE_AFFILIATED = 1; // 0x1 + field public static final int HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED = 0; // 0x0 field public static final int USES_ENCRYPTED_STORAGE = 7; // 0x7 field public static final int USES_POLICY_DISABLE_CAMERA = 8; // 0x8 field public static final int USES_POLICY_DISABLE_KEYGUARD_FEATURES = 9; // 0x9 diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 0fce784b6166..3f959fa918ed 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1272,6 +1272,7 @@ package android.app.admin { field public static final int STATUS_DEVICE_ADMIN_NOT_SUPPORTED = 13; // 0xd field public static final int STATUS_HAS_DEVICE_OWNER = 1; // 0x1 field public static final int STATUS_HAS_PAIRED = 8; // 0x8 + field public static final int STATUS_HEADLESS_SYSTEM_USER_MODE_NOT_SUPPORTED = 16; // 0x10 field public static final int STATUS_MANAGED_USERS_NOT_SUPPORTED = 9; // 0x9 field public static final int STATUS_NONSYSTEM_USER_EXISTS = 5; // 0x5 field public static final int STATUS_NOT_SYSTEM_USER = 7; // 0x7 diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java index 67408a47c334..e4ee959336a5 100644 --- a/core/java/android/app/admin/DeviceAdminInfo.java +++ b/core/java/android/app/admin/DeviceAdminInfo.java @@ -16,6 +16,7 @@ package android.app.admin; +import android.annotation.IntDef; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; @@ -158,6 +159,24 @@ public final class DeviceAdminInfo implements Parcelable { */ public static final int USES_POLICY_DISABLE_KEYGUARD_FEATURES = 9; + + /** + * Value for {@link #getHeadlessDeviceOwnerMode} which indicates that this DPC should not + * be provisioned into Device Owner mode on a Headless System User Mode device. + */ + public static final int HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED = 0; + + /** + * Value for {@link #getHeadlessDeviceOwnerMode} which indicates that this DPC should be + * provisioned into "affiliated" mode when on a Headless System User Mode device. + * + * <p>This mode adds a Profile Owner to all users other than the user the Device Owner is on. + */ + public static final int HEADLESS_DEVICE_OWNER_MODE_AFFILIATED = 1; + + @IntDef({HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED, HEADLESS_DEVICE_OWNER_MODE_AFFILIATED}) + private @interface HeadlessDeviceOwnerMode {} + /** @hide */ public static class PolicyInfo { public final int ident; @@ -255,6 +274,8 @@ public final class DeviceAdminInfo implements Parcelable { */ boolean mSupportsTransferOwnership; + @HeadlessDeviceOwnerMode int mHeadlessDeviceOwnerMode = HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED; + /** * Constructor. * @@ -341,6 +362,17 @@ public final class DeviceAdminInfo implements Parcelable { "support-transfer-ownership tag must be empty."); } mSupportsTransferOwnership = true; + } else if (tagName.equals("headless-system-user")) { + String deviceOwnerModeStringValue = + parser.getAttributeValue(null, "device-owner-mode"); + + if (deviceOwnerModeStringValue.equalsIgnoreCase("unsupported")) { + mHeadlessDeviceOwnerMode = HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED; + } else if (deviceOwnerModeStringValue.equalsIgnoreCase("affiliated")) { + mHeadlessDeviceOwnerMode = HEADLESS_DEVICE_OWNER_MODE_AFFILIATED; + } else { + throw new XmlPullParserException("headless-system-user mode must be valid"); + } } } } catch (NameNotFoundException e) { @@ -355,6 +387,7 @@ public final class DeviceAdminInfo implements Parcelable { mActivityInfo = ActivityInfo.CREATOR.createFromParcel(source); mUsesPolicies = source.readInt(); mSupportsTransferOwnership = source.readBoolean(); + mHeadlessDeviceOwnerMode = source.readInt(); } /** @@ -460,6 +493,14 @@ public final class DeviceAdminInfo implements Parcelable { return mSupportsTransferOwnership; } + /** + * Returns the mode this DeviceAdmin wishes to use if provisioned as a Device Owner on a + * headless system user mode device. + */ + public @HeadlessDeviceOwnerMode int getHeadlessDeviceOwnerMode() { + return mHeadlessDeviceOwnerMode; + } + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public ArrayList<PolicyInfo> getUsedPolicies() { @@ -505,6 +546,7 @@ public final class DeviceAdminInfo implements Parcelable { mActivityInfo.writeToParcel(dest, flags); dest.writeInt(mUsesPolicies); dest.writeBoolean(mSupportsTransferOwnership); + dest.writeInt(mHeadlessDeviceOwnerMode); } /** diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 33721a0de32f..8c77955fd346 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -16,10 +16,10 @@ package android.app.admin; +import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.QUERY_ADMIN_POLICY; import static android.Manifest.permission.SET_TIME; import static android.Manifest.permission.SET_TIME_ZONE; -import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM; import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1; @@ -2812,6 +2812,17 @@ public class DevicePolicyManager { public static final int STATUS_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS = 15; /** + * Result code for {@link #checkProvisioningPrecondition}. + * + * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE} when provisioning a DPC which does + * not support headless system user mode on a headless system user mode device. + * + * @hide + */ + @SystemApi + public static final int STATUS_HEADLESS_SYSTEM_USER_MODE_NOT_SUPPORTED = 16; + + /** * Result codes for {@link #checkProvisioningPrecondition} indicating all the provisioning pre * conditions. * @@ -2824,7 +2835,8 @@ public class DevicePolicyManager { STATUS_HAS_PAIRED, STATUS_MANAGED_USERS_NOT_SUPPORTED, STATUS_SYSTEM_USER, STATUS_CANNOT_ADD_MANAGED_PROFILE, STATUS_DEVICE_ADMIN_NOT_SUPPORTED, STATUS_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER, - STATUS_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS + STATUS_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS, + STATUS_HEADLESS_SYSTEM_USER_MODE_NOT_SUPPORTED }) public @interface ProvisioningPrecondition {} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index fa6fa530296c..104b712250d1 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -30,6 +30,7 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_APP_STANDBY; +import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_AFFILIATED; import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED; import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE; import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE; @@ -105,6 +106,7 @@ import static android.app.admin.DevicePolicyManager.STATUS_CANNOT_ADD_MANAGED_PR import static android.app.admin.DevicePolicyManager.STATUS_DEVICE_ADMIN_NOT_SUPPORTED; import static android.app.admin.DevicePolicyManager.STATUS_HAS_DEVICE_OWNER; import static android.app.admin.DevicePolicyManager.STATUS_HAS_PAIRED; +import static android.app.admin.DevicePolicyManager.STATUS_HEADLESS_SYSTEM_USER_MODE_NOT_SUPPORTED; import static android.app.admin.DevicePolicyManager.STATUS_MANAGED_USERS_NOT_SUPPORTED; import static android.app.admin.DevicePolicyManager.STATUS_NONSYSTEM_USER_EXISTS; import static android.app.admin.DevicePolicyManager.STATUS_NOT_SYSTEM_USER; @@ -140,6 +142,7 @@ import static android.app.admin.ProvisioningException.ERROR_SETTING_PROFILE_OWNE import static android.app.admin.ProvisioningException.ERROR_SET_DEVICE_OWNER_FAILED; import static android.app.admin.ProvisioningException.ERROR_STARTING_PROFILE_FAILED; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.pm.PackageManager.GET_META_DATA; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; @@ -2929,7 +2932,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final ActivityInfo ai = mInjector.binderWithCleanCallingIdentity(() -> { try { return mIPackageManager.getReceiverInfo(adminName, - PackageManager.GET_META_DATA + GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle); @@ -14670,7 +14673,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Preconditions.checkCallAuthorization( hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)); - return checkProvisioningPreconditionSkipPermission(action, packageName, caller.getUserId()); + long originalId = mInjector.binderClearCallingIdentity(); + try { + return checkProvisioningPreconditionSkipPermission( + action, packageName, caller.getUserId()); + } finally { + mInjector.binderRestoreCallingIdentity(originalId); + } + } private int checkProvisioningPreconditionSkipPermission(String action, String packageName, int userId) { @@ -14736,22 +14746,31 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return STATUS_USER_HAS_PROFILE_OWNER; } - boolean isHeadlessSystemUserMode = mInjector.userManagerIsHeadlessSystemUserMode(); - // System user is always running in headless system user mode. - if (!isHeadlessSystemUserMode - && !mUserManager.isUserRunning(new UserHandle(deviceOwnerUserId))) { + if (!mUserManager.isUserRunning(new UserHandle(deviceOwnerUserId))) { return STATUS_USER_NOT_RUNNING; } if (mIsWatch && hasPaired(UserHandle.USER_SYSTEM)) { return STATUS_HAS_PAIRED; } + boolean isHeadlessSystemUserMode = mInjector.userManagerIsHeadlessSystemUserMode(); + if (isHeadlessSystemUserMode) { if (deviceOwnerUserId != UserHandle.USER_SYSTEM) { Slogf.e(LOG_TAG, "In headless system user mode, " + "device owner can only be set on headless system user."); return STATUS_NOT_SYSTEM_USER; } + + if (owner != null) { + DeviceAdminInfo adminInfo = findAdmin( + owner, deviceOwnerUserId, /* throwForMissingPermission= */ false); + + if (adminInfo.getHeadlessDeviceOwnerMode() + != HEADLESS_DEVICE_OWNER_MODE_AFFILIATED) { + return STATUS_HEADLESS_SYSTEM_USER_MODE_NOT_SUPPORTED; + } + } } if (isAdb) { @@ -18883,11 +18902,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { "Provisioning preconditions failed with result: " + result); } onProvisionFullyManagedDeviceStarted(provisioningParams); + + // These properties are global so will apply on all users setTimeAndTimezone(provisioningParams.getTimeZone(), provisioningParams.getLocalTime()); setLocale(provisioningParams.getLocale()); - final int deviceOwnerUserId = mInjector.userManagerIsHeadlessSystemUserMode() - ? UserHandle.USER_SYSTEM : caller.getUserId(); + int deviceOwnerUserId = UserHandle.USER_SYSTEM; if (!removeNonRequiredAppsForManagedDevice( deviceOwnerUserId, provisioningParams.isLeaveAllSystemAppsEnabled(), @@ -19013,9 +19033,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private void disallowAddUser() { - if (mInjector.userManagerIsHeadlessSystemUserMode()) { - Slogf.i(LOG_TAG, "Not setting DISALLOW_ADD_USER on headless system user mode."); - return; + if (!isHeadlessFlagEnabled() || mIsAutomotive) { + // Auto still enables adding users due to the communal nature of those devices + if (mInjector.userManagerIsHeadlessSystemUserMode()) { + Slogf.i(LOG_TAG, "Not setting DISALLOW_ADD_USER on headless system user mode."); + return; + } } for (UserInfo userInfo : mUserManager.getUsers()) { UserHandle userHandle = userInfo.getUserHandle(); 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 210aeefde2b2..4998a6c20e63 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -1085,27 +1085,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable. } - /** - * TODO(b/174859111): move to automotive-only section - * Test for {@link DevicePolicyManager#setDeviceOwner} in headless system user mode. - */ - @Test - public void testSetDeviceOwner_headlessSystemUserMode() throws Exception { - when(getServices().userManagerForMock.isHeadlessSystemUserMode()).thenReturn(true); - setDeviceOwner_headlessSystemUser(); - - // Try to set a profile owner on the same user, which should fail. - setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID); - dpm.setActiveAdmin(admin2, /* refreshing= */ true, CALLER_USER_HANDLE); - assertExpectException(IllegalStateException.class, - /* messageRegex= */ "profile owner is already set", - () -> dpm.setProfileOwner(admin2, CALLER_USER_HANDLE)); - - // DO admin can't be deactivated. - dpm.removeActiveAdmin(admin1); - assertThat(dpm.isAdminActive(admin1)).isTrue(); - } - private void setDeviceOwner() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); |