Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20b5c10c authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Allow DeviceOwner to be set on "mainless" user on HSUM devices." into main

parents 3bacd78c 63cf8dc7
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -2970,6 +2970,20 @@ public class DevicePolicyManager {
    @SystemApi
    public static final int STATUS_HEADLESS_ONLY_SYSTEM_USER = 17;
    // TODO(b/435271558): expose as @SystemApi
    /**
     * Result code for {@link #checkProvisioningPrecondition}.
     *
     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE} when provisioning a DPC into
     * the {@link DeviceAdminInfo#HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER} mode but the target user
     * is not the first full user of the device (i.e., first user other than the headless system
     * user).
     *
     * @hide
     */
    public static final int STATUS_HEADLESS_SINGLE_USER_MODE_ONLY_SUPPORTED_ON_FIRST_FULL_USER = 18;
    /**
     * Result codes for {@link #checkProvisioningPrecondition} indicating all the provisioning pre
     * conditions.
@@ -2984,7 +2998,8 @@ public class DevicePolicyManager {
            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_HEADLESS_SYSTEM_USER_MODE_NOT_SUPPORTED, STATUS_HEADLESS_ONLY_SYSTEM_USER
            STATUS_HEADLESS_SYSTEM_USER_MODE_NOT_SUPPORTED, STATUS_HEADLESS_ONLY_SYSTEM_USER,
            STATUS_HEADLESS_SINGLE_USER_MODE_ONLY_SUPPORTED_ON_FIRST_FULL_USER
    })
    public @interface ProvisioningPrecondition {}
+8 −1
Original line number Diff line number Diff line
@@ -510,3 +510,10 @@ flag {
  bug: "414733570"
  is_exported: true
}

flag {
  name: "device_owner_for_all"
  namespace: "enterprise"
  description: "Enable any user (not just the Main User) to be a DeviceOwner"
  bug: "435271558"
}
+10 −0
Original line number Diff line number Diff line
@@ -2454,6 +2454,15 @@ public class UserManager {
    @SystemApi
    public static final int REMOVE_RESULT_ERROR_LAST_ADMIN_USER = -6;

    // TODO(b/435271558): expose as @SystemApi
    /**
     * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
     * user being removed cannot be removed because it is the Device Owner on this device.
     *
     * @hide
     */
    public static final int REMOVE_RESULT_DEVICE_OWNER = -7;

    /**
     * Possible response codes from {@link #removeUserWhenPossible(UserHandle, boolean)}.
     *
@@ -2469,6 +2478,7 @@ public class UserManager {
            REMOVE_RESULT_ERROR_SYSTEM_USER,
            REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN,
            REMOVE_RESULT_ERROR_LAST_ADMIN_USER,
            REMOVE_RESULT_DEVICE_OWNER,
            REMOVE_RESULT_ERROR_UNKNOWN,
    })
    @Retention(RetentionPolicy.SOURCE)
+20 −0
Original line number Diff line number Diff line
@@ -1414,6 +1414,20 @@ public class UserManagerService extends IUserManager.Stub {
        return UserHandle.USER_NULL;
    }

    private @UserIdInt int getDeviceOwnerUserId() {
        DevicePolicyManagerInternal dpmi = getDevicePolicyManagerInternal();
        if (dpmi == null) {
            return UserHandle.USER_NULL;
        }
        // TODO(b/435271558): change dpmi.getDeviceOwnerUserId() so it doesn't check for permissions
        long ident = Binder.clearCallingIdentity();
        try {
            return dpmi.getDeviceOwnerUserId();
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

    @Override
    public void setBootUser(@UserIdInt int userId) {
        checkCreateUsersPermission("Set boot user");
@@ -7172,6 +7186,9 @@ public class UserManagerService extends IUserManager.Stub {
        if (mRemovingUserIds.get(userId)) {
            return UserManager.REMOVE_RESULT_ALREADY_BEING_REMOVED;
        }
        if (userId == getDeviceOwnerUserId()) {
            return UserManager.REMOVE_RESULT_DEVICE_OWNER;
        }
        if (isNonRemovableLastAdminUserLU(userData.info)) {
            return UserManager.REMOVE_RESULT_ERROR_LAST_ADMIN_USER;
        }
@@ -7196,6 +7213,9 @@ public class UserManagerService extends IUserManager.Stub {
            case UserManager.REMOVE_RESULT_ERROR_LAST_ADMIN_USER ->
                Slogf.e(LOG_TAG, "User %d can not be %s, last admin user cannot be removed.",
                        userId, action);
            case UserManager.REMOVE_RESULT_DEVICE_OWNER ->
                    Slogf.w(LOG_TAG, "User %d can not be %s because it's the device owner", userId,
                            action);
            default -> {}
        }
    }
+92 −12
Original line number Diff line number Diff line
@@ -205,6 +205,7 @@ 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_ONLY_SYSTEM_USER;
import static android.app.admin.DevicePolicyManager.STATUS_HEADLESS_SYSTEM_USER_MODE_NOT_SUPPORTED;
import static android.app.admin.DevicePolicyManager.STATUS_HEADLESS_SINGLE_USER_MODE_ONLY_SUPPORTED_ON_FIRST_FULL_USER;
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;
@@ -346,6 +347,7 @@ import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
import android.app.admin.DevicePolicyManager.OperationSafetyReason;
import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.admin.DevicePolicyManager.PersonalAppsSuspensionReason;
import android.app.admin.DevicePolicyManager.ProvisioningPrecondition;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicyManagerLiteInternal;
import android.app.admin.DevicePolicySafetyChecker;
@@ -11403,8 +11405,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                return "Not allowed to set the device owner because this device has already "
                        + "paired.";
            case STATUS_HEADLESS_SYSTEM_USER_MODE_NOT_SUPPORTED:
                return "Cannot provision an unsupported DPC into DO on a"
                        + " headless device";
                return "Cannot provision an unsupported DPC into DO on a headless device";
            case STATUS_HEADLESS_ONLY_SYSTEM_USER:
                return "Cannot provision DPC on single user mode on headless device when only the "
                        + "system user exists in the device";
            case STATUS_HEADLESS_SINGLE_USER_MODE_ONLY_SUPPORTED_ON_FIRST_FULL_USER:
                return "Cannot provision DPC on single user mode on headless device on user "
                    + userId + " because it's not the first \"human\" user";
            default:
                return "Unexpected @ProvisioningPreCondition: " + code;
        }
@@ -17831,12 +17838,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                }
                if (isHeadlessModeSingleUser) {
                    if (Flags.deviceOwnerForAll()) {
                        int status = checkDeviceOwnerForHeadlessModeSingleUser(deviceOwnerUserId);
                        if (status == STATUS_OK) {
                            ensureSetUpUser = deviceOwnerUserId;
                        } else {
                            return status;
                        }
                    } else {
                        ensureSetUpUser = mUserManagerInternal.getMainUserId();
                        if (ensureSetUpUser == UserHandle.USER_NULL) {
                            return STATUS_HEADLESS_ONLY_SYSTEM_USER;
                        }
                    }
                }
            }
            if (isHeadlessModeAffiliated && deviceOwnerUserId != UserHandle.USER_SYSTEM) {
                Slogf.e(LOG_TAG, "In headless system user mode, "
@@ -17883,12 +17900,63 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
    }
    private @ProvisioningPrecondition int checkDeviceOwnerForHeadlessModeSingleUser(
            @UserIdInt int userId) {
        if (userId == UserHandle.USER_SYSTEM) {
            Slogf.e(LOG_TAG, "Cannot set device owner for headless mode / single user on SYSTEM");
            return STATUS_SYSTEM_USER;
        }
        // In "real life" (not adb), the device owner would be called by the Setup Wizard of the
        // first non-HSU user on first boot, so we don't need to check for Main User, but instead
        // check that it's being called by the current user, which is an admin, and that the device
        // only contains the SYSTEM and that current user. And if it's called by adb, we can impose
        // these same restrictions...
        int currentUserId = getCurrentForegroundUserId();
        if (userId != currentUserId) {
            Slogf.e(LOG_TAG, "Cannot set device owner for headless mode / single user on user %d,"
                    + " only on current user (%d)", userId, currentUserId);
            return STATUS_HEADLESS_SINGLE_USER_MODE_ONLY_SUPPORTED_ON_FIRST_FULL_USER;
        }
        UserInfo user = mUserManagerInternal.getUserInfo(userId);
        if (user == null) {
            // Shouldn't happen as caller already check if user is running, but it doesn't hurt to
            // double check
            Slogf.wtf(LOG_TAG, "Trying to set device owner on user (%d) that doesn't exit", userId);
            return STATUS_USER_NOT_RUNNING; // No need for new code as it shouldn't happen
        }
        if (!user.isAdmin()) {
            Slogf.e(LOG_TAG, "Cannot set device owner for headless mode / single user on user %d "
                    + "because it's not an admin", userId);
            return STATUS_HEADLESS_SINGLE_USER_MODE_ONLY_SUPPORTED_ON_FIRST_FULL_USER;
        }
        // TODO(b/419086491): use new method that takes a filter
        long extraUsersCount = mUserManagerInternal.getUsers(/* excludeDying= */ false).stream()
                .filter(u -> u.id != UserHandle.USER_SYSTEM && u.id != userId)
                .count();
        // TODO(b/435271558): make sure to unit test these scenarios (as this checks comes before
        // the similar change when setting from adb)
        if (extraUsersCount > 0) {
            Slogf.e(LOG_TAG, "Cannot set device owner for headless mode / single user on user %d,"
                    + " as device has %d \"secondary\" user(s) already",
                    userId, extraUsersCount);
            return STATUS_HEADLESS_SINGLE_USER_MODE_ONLY_SUPPORTED_ON_FIRST_FULL_USER;
        }
        Slogf.d(LOG_TAG, "User %d is allowed to be the device owner", userId);
        return STATUS_OK;
    }
    /**
     * True if there are any users on the device which were not setup by default (1 usually, 2 for
     * devices with a headless system user) and also are not marked as FOR_TESTING.
     */
    private boolean nonTestNonPrecreatedUsersExist() {
        int allowedUsers = UserManager.isHeadlessSystemUserMode() ? 2 : 1;
        // TODO(b/419086491): use new method that takes a filter
        return mUserManagerInternal.getUsers(/* excludeDying= */ true).stream()
                .filter(u -> !u.isForTesting())
                .count() > allowedUsers;
@@ -22598,6 +22666,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    public void provisionFullyManagedDevice(
            @NonNull FullyManagedDeviceProvisioningParams provisioningParams,
            @NonNull String callerPackage) {
        Slogf.d(LOG_TAG, "provisionFullyManagedDevice(pkg=%s, params=%s)", callerPackage,
                provisioningParams);
        Objects.requireNonNull(provisioningParams, "provisioningParams is null.");
        Objects.requireNonNull(callerPackage, "callerPackage is null.");
@@ -22616,8 +22686,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        final long identity = Binder.clearCallingIdentity();
        try {
            boolean isSingleUserMode;
            int callerUserId = caller.getUserId();
            int headlessDeviceOwnerMode = getHeadlessDeviceOwnerModeForDeviceAdmin(
                    deviceAdmin, caller.getUserId());
                    deviceAdmin, callerUserId);
            isSingleUserMode = headlessDeviceOwnerMode == HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER;
            if (Flags.headlessSingleMinTargetSdk()
@@ -22625,12 +22696,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                    && isSingleUserMode
                    && !mInjector.isChangeEnabled(
                            PROVISION_SINGLE_USER_MODE, deviceAdmin.getPackageName(),
                    caller.getUserId())) {
                    callerUserId)) {
                throw new IllegalStateException("Device admin is not targeting Android V.");
            }
            int result = checkProvisioningPreconditionSkipPermission(
                    ACTION_PROVISION_MANAGED_DEVICE, deviceAdmin, caller.getUserId());
                    ACTION_PROVISION_MANAGED_DEVICE, deviceAdmin, callerUserId);
            if (result != STATUS_OK) {
                throw new ServiceSpecificException(
                        ERROR_PRE_CONDITION_FAILED,
@@ -22642,10 +22713,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            setTimeAndTimezone(provisioningParams.getTimeZone(), provisioningParams.getLocalTime());
            setLocale(provisioningParams.getLocale());
            int deviceOwnerUserId =
                    isSingleUserMode && mInjector.userManagerIsHeadlessSystemUserMode()
                    ? mUserManagerInternal.getMainUserId() : UserHandle.USER_SYSTEM;
            int deviceOwnerUserId = UserHandle.USER_SYSTEM;
            if (isSingleUserMode && mInjector.userManagerIsHeadlessSystemUserMode()) {
                if (Flags.deviceOwnerForAll()) {
                    deviceOwnerUserId = callerUserId;
                    Slogf.d(LOG_TAG,
                            "provisionFullyManagedDevice(): using calling user id (%d) as DO",
                            deviceOwnerUserId);
                } else {
                    deviceOwnerUserId = mUserManagerInternal.getMainUserId();
                    Slogf.d(LOG_TAG, "provisionFullyManagedDevice(): using main user id (%d) as DO",
                            deviceOwnerUserId);
                }
            }
            if (!removeNonRequiredAppsForManagedDevice(
                    deviceOwnerUserId,
                    provisioningParams.isLeaveAllSystemAppsEnabled(),
Loading