summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt3
-rw-r--r--core/api/system-current.txt1
-rw-r--r--core/java/android/app/admin/DeviceAdminInfo.java42
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java16
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java45
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java21
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);