diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index a1c644a4e4745..2a79c72f69f81 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -2056,7 +2056,9 @@ public class DevicePolicyManager { /** * Result code for {@link #checkProvisioningPreCondition}. * - *

Returned for {@link #ACTION_PROVISION_MANAGED_USER} if the user is a system user. + *

Returned for {@link #ACTION_PROVISION_MANAGED_USER} if the user is a system user and + * for {@link #ACTION_PROVISION_MANAGED_DEVICE} on devices running headless system user mode + * and the user is a system user. * * @hide */ diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 13aeb753b695f..2df58ccf88642 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -6112,9 +6112,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private void forceWipeUser(int userId, String wipeReasonForUser, boolean wipeSilently) { boolean success = false; try { - IActivityManager am = mInjector.getIActivityManager(); - if (am.getCurrentUser().id == userId) { - am.switchUser(UserHandle.USER_SYSTEM); + if (getCurrentForegroundUser() == userId) { + mInjector.getIActivityManager().switchUser(UserHandle.USER_SYSTEM); } success = mUserManagerInternal.removeUserEvenWhenDisallowed(userId); @@ -7578,9 +7577,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Slog.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId); if (mInjector.userManagerIsHeadlessSystemUserMode()) { - Slog.i(LOG_TAG, "manageUser: " + admin + " on user " + userId); - - manageUser(admin, admin, caller.getUserId(), null); + int currentForegroundUser = getCurrentForegroundUser(); + Slog.i(LOG_TAG, "setDeviceOwner(): setting " + admin + + " as profile owner on user " + currentForegroundUser); + // Sets profile owner on current foreground user since + // the human user will complete the DO setup workflow from there. + mInjector.binderWithCleanCallingIdentity(() -> + manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin, + /* managedUser= */ currentForegroundUser, + /* adminExtras= */ null)); } return true; } @@ -8565,16 +8570,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * permission. */ private void enforceCanSetDeviceOwnerLocked(CallerIdentity caller, - @Nullable ComponentName owner, @UserIdInt int userId) { + @Nullable ComponentName owner, @UserIdInt int deviceOwnerUserId) { if (!isAdb(caller)) { Preconditions.checkCallAuthorization( hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)); } - final int code = checkDeviceOwnerProvisioningPreConditionLocked(owner, userId, - isAdb(caller), hasIncompatibleAccountsOrNonAdbNoLock(caller, userId, owner)); + final int code = checkDeviceOwnerProvisioningPreConditionLocked(owner, + /* deviceOwnerUserId= */ deviceOwnerUserId, /* callingUserId*/ caller.getUserId(), + isAdb(caller), + hasIncompatibleAccountsOrNonAdbNoLock(caller, deviceOwnerUserId, owner)); if (code != CODE_OK) { - throw new IllegalStateException(computeProvisioningErrorString(code, userId)); + throw new IllegalStateException( + computeProvisioningErrorString(code, deviceOwnerUserId)); } } @@ -8702,6 +8710,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return UserHandle.isSameApp(caller.getUid(), Process.SHELL_UID); } + private @UserIdInt int getCurrentForegroundUser() { + try { + return mInjector.getIActivityManager().getCurrentUser().id; + } catch (RemoteException e) { + Slog.wtf(LOG_TAG, "cannot get current user"); + } + return UserHandle.USER_NULL; + } + protected int getProfileParentId(int userHandle) { return mInjector.binderWithCleanCallingIdentity(() -> { UserInfo parentUser = mUserManager.getProfileParent(userHandle); @@ -9613,7 +9630,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final long id = mInjector.binderClearCallingIdentity(); try { - manageUser(admin, profileOwner, userHandle, adminExtras); + manageUserUnchecked(admin, profileOwner, userHandle, adminExtras); if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) { Settings.Secure.putIntForUser(mContext.getContentResolver(), @@ -9634,43 +9651,34 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private void manageUser(ComponentName admin, ComponentName profileOwner, + private void manageUserUnchecked(ComponentName admin, ComponentName profileOwner, @UserIdInt int userId, PersistableBundle adminExtras) { - // Check for permission - final CallerIdentity caller = getCallerIdentity(); - Preconditions.checkCallAuthorization(canManageUsers(caller)); - Preconditions.checkCallAuthorization( - hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)); - mInjector.binderWithCleanCallingIdentity(() -> - manageUserNoCheck(admin, profileOwner, userId, adminExtras)); - } - - private void manageUserNoCheck(ComponentName admin, ComponentName profileOwner, - int user, PersistableBundle adminExtras) { - final String adminPkg = admin.getPackageName(); try { // Install the profile owner if not present. - if (!mIPackageManager.isPackageAvailable(adminPkg, user)) { - mIPackageManager.installExistingPackageAsUser(adminPkg, user, + if (!mIPackageManager.isPackageAvailable(adminPkg, userId)) { + mIPackageManager.installExistingPackageAsUser(adminPkg, userId, PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, - PackageManager.INSTALL_REASON_POLICY, null); + PackageManager.INSTALL_REASON_POLICY, + /* allowlistedRestrictedPermissions= */ null); } } catch (RemoteException e) { // Does not happen, same process + Slog.wtf(LOG_TAG, String.format("Failed to install admin package %s for user %d", + adminPkg, userId), e); } // Set admin. - setActiveAdmin(profileOwner, true, user); + setActiveAdmin(profileOwner, /* refreshing= */ true, userId); final String ownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier()); - setProfileOwner(profileOwner, ownerName, user); + setProfileOwner(profileOwner, ownerName, userId); synchronized (getLockObject()) { - DevicePolicyData policyData = getUserData(user); + DevicePolicyData policyData = getUserData(userId); policyData.mInitBundle = adminExtras; policyData.mAdminBroadcastPending = true; - saveSettingsLocked(user); + saveSettingsLocked(userId); } } @@ -12304,7 +12312,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * except for adb command if no accounts or additional users are present on the device. */ private int checkDeviceOwnerProvisioningPreConditionLocked(@Nullable ComponentName owner, - @UserIdInt int deviceOwnerUserId, boolean isAdb, + @UserIdInt int deviceOwnerUserId, @UserIdInt int callingUserId, boolean isAdb, boolean hasIncompatibleAccountsOrNonAdb) { if (mOwners.hasDeviceOwner()) { return CODE_HAS_DEVICE_OWNER; @@ -12320,6 +12328,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (mIsWatch && hasPaired(UserHandle.USER_SYSTEM)) { return CODE_HAS_PAIRED; } + + if (mInjector.userManagerIsHeadlessSystemUserMode()) { + if (deviceOwnerUserId != UserHandle.USER_SYSTEM) { + Slog.e(LOG_TAG, "In headless system user mode, " + + "device owner can only be set on headless system user."); + return CODE_NOT_SYSTEM_USER; + } + } + // TODO (b/137101239): clean up split system user codes if (isAdb) { // If shell command runs after user setup completed check device status. Otherwise, OK. @@ -12331,6 +12348,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { && mUserManager.getUserCount() > 1) { return CODE_NONSYSTEM_USER_EXISTS; } + + int currentForegroundUser = getCurrentForegroundUser(); + if (callingUserId != currentForegroundUser + && mInjector.userManagerIsHeadlessSystemUserMode() + && currentForegroundUser == UserHandle.USER_SYSTEM) { + Slog.wtf(LOG_TAG, "In headless system user mode, " + + "current user cannot be system user when setting device owner"); + return CODE_SYSTEM_USER; + } if (hasIncompatibleAccountsOrNonAdb) { return CODE_ACCOUNTS_NOT_EMPTY; } @@ -12362,7 +12388,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { callingUserId, deviceOwnerUserId)); // hasIncompatibleAccountsOrNonAdb doesn't matter since the caller is not adb. return checkDeviceOwnerProvisioningPreConditionLocked(/* owner unknown */ null, - deviceOwnerUserId, /* isAdb= */ false, + deviceOwnerUserId, callingUserId, /* isAdb= */ false, /* hasIncompatibleAccountsOrNonAdb=*/ true); } } @@ -14901,8 +14927,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private boolean isLockTaskFeatureEnabled(int lockTaskFeature) throws RemoteException { + //TODO(b/175285301): Explicitly get the user's identity to check. int lockTaskFeatures = - getUserData(mInjector.getIActivityManager().getCurrentUser().id).mLockTaskFeatures; + getUserData(getCurrentForegroundUser()).mLockTaskFeatures; return (lockTaskFeatures & lockTaskFeature) == lockTaskFeature; }