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

Commit dae46965 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Move removeUserWithProfilesUnchecked outside of mPackagesLock."

parents c0646a9f 5395814a
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -1816,6 +1816,13 @@ public class UserManager {
    @SystemApi
    public static final int REMOVE_RESULT_ALREADY_BEING_REMOVED = 2;

    /**
     * A response code indicating that the specified user is removable.
     *
     * @hide
     */
    public static final int REMOVE_RESULT_USER_IS_REMOVABLE = 3;

    /**
     * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
     * an unknown error occurred that prevented the user from being removed or set as ephemeral.
@@ -1871,6 +1878,7 @@ public class UserManager {
            REMOVE_RESULT_REMOVED,
            REMOVE_RESULT_DEFERRED,
            REMOVE_RESULT_ALREADY_BEING_REMOVED,
            REMOVE_RESULT_USER_IS_REMOVABLE,
            REMOVE_RESULT_ERROR_USER_RESTRICTION,
            REMOVE_RESULT_ERROR_USER_NOT_FOUND,
            REMOVE_RESULT_ERROR_SYSTEM_USER,
+104 −119
Original line number Diff line number Diff line
@@ -2391,39 +2391,56 @@ public class UserManagerService extends IUserManager.Stub {
    @Override
    public boolean setUserEphemeral(@UserIdInt int userId, boolean enableEphemeral) {
        checkCreateUsersPermission("update ephemeral user flag");
        UserData userToUpdate = null;
        return enableEphemeral
                ? UserManager.isRemoveResultSuccessful(setUserEphemeralUnchecked(userId))
                : setUserNonEphemeralUnchecked(userId);
    }

    private boolean setUserNonEphemeralUnchecked(@UserIdInt int userId) {
        synchronized (mPackagesLock) {
            final UserData userData;
            synchronized (mUsersLock) {
                final UserData userData = mUsers.get(userId);
                userData = mUsers.get(userId);
                if (userData == null) {
                    Slog.e(LOG_TAG, "User not found for setting ephemeral mode: u" + userId);
                    Slog.e(LOG_TAG, TextUtils.formatSimple(
                            "Cannot set user %d non-ephemeral, invalid user id provided.", userId));
                    return false;
                }
                boolean isEphemeralUser = (userData.info.flags & UserInfo.FLAG_EPHEMERAL) != 0;
                boolean isEphemeralOnCreateUser =
                        (userData.info.flags & UserInfo.FLAG_EPHEMERAL_ON_CREATE) != 0;
                if (!userData.info.isEphemeral()) {
                    return true;
                }

                if ((userData.info.flags & UserInfo.FLAG_EPHEMERAL_ON_CREATE) != 0) {
                    // when user is created in ephemeral mode via FLAG_EPHEMERAL
                // its state cannot be changed to non ephemeral.
                    // its state cannot be changed to non-ephemeral.
                    // FLAG_EPHEMERAL_ON_CREATE is used to keep track of this state
                if (isEphemeralOnCreateUser && !enableEphemeral) {
                    Slog.e(LOG_TAG, "Failed to change user state to non-ephemeral for user "
                            + userId);
                    Slog.e(LOG_TAG, TextUtils.formatSimple("User %d can not be changed to "
                            + "non-ephemeral because it was set ephemeral on create.", userId));
                    return false;
                }
                if (isEphemeralUser != enableEphemeral) {
                    if (enableEphemeral) {
                        userData.info.flags |= UserInfo.FLAG_EPHEMERAL;
                    } else {
            }
            userData.info.flags &= ~UserInfo.FLAG_EPHEMERAL;
            writeUserLP(userData);
        }
                    userToUpdate = userData;
        return true;
    }

    private @UserManager.RemoveResult int setUserEphemeralUnchecked(@UserIdInt int userId) {
        synchronized (mPackagesLock) {
            final UserData userData;
            synchronized (mUsersLock) {
                final int userRemovability = getUserRemovabilityLocked(userId, "set as ephemeral");
                if (userRemovability != UserManager.REMOVE_RESULT_USER_IS_REMOVABLE) {
                    return userRemovability;
                }
            if (userToUpdate != null) {
                writeUserLP(userToUpdate);
                userData = mUsers.get(userId);
            }
            userData.info.flags |= UserInfo.FLAG_EPHEMERAL;
            writeUserLP(userData);
        }
        return true;
        Slog.i(LOG_TAG, TextUtils.formatSimple(
                "User %d is set ephemeral and will be removed on user switch or reboot.", userId));
        return UserManager.REMOVE_RESULT_DEFERRED;
    }

    @Override
@@ -5366,17 +5383,31 @@ public class UserManagerService extends IUserManager.Stub {
    }

    private boolean removeUserWithProfilesUnchecked(@UserIdInt int userId) {
        UserInfo userInfo = getUserInfoNoChecks(userId);
        final UserData userData;
        final boolean isProfile;
        final IntArray profileIds;
        synchronized (mUsersLock) {
            final int userRemovability = getUserRemovabilityLocked(userId, "removed");
            if (userRemovability != UserManager.REMOVE_RESULT_USER_IS_REMOVABLE) {
                return UserManager.isRemoveResultSuccessful(userRemovability);
            }
            userData = mUsers.get(userId);
            isProfile = userData.info.isProfile();
            profileIds = isProfile ? null : getProfileIdsLU(userId, null, false);
        }

        if (userInfo == null) {
            Slog.e(LOG_TAG, TextUtils.formatSimple(
                    "Cannot remove user %d, invalid user id provided.", userId));
        if (!isProfile) {
            Pair<Integer, Integer> currentAndTargetUserIds = getCurrentAndTargetUserIds();
            if (userId == currentAndTargetUserIds.first) {
                Slog.w(LOG_TAG, "Current user cannot be removed.");
                return false;
            }

        if (!userInfo.isProfile()) {
            int[] profileIds = getProfileIds(userId, false);
            for (int profileId : profileIds) {
            if (userId == currentAndTargetUserIds.second) {
                Slog.w(LOG_TAG, "Target user of an ongoing user switch cannot be removed.");
                return false;
            }
            for (int i = profileIds.size() - 1; i >= 0; i--) {
                int profileId = profileIds.get(i);
                if (profileId == userId) {
                    //Remove the associated profiles first and then remove the user
                    continue;
@@ -5429,45 +5460,16 @@ public class UserManagerService extends IUserManager.Stub {
        final long ident = Binder.clearCallingIdentity();
        try {
            final UserData userData;
            Pair<Integer, Integer> currentAndTargetUserIds = getCurrentAndTargetUserIds();
            if (userId == currentAndTargetUserIds.first) {
                Slog.w(LOG_TAG, "Current user cannot be removed.");
                return false;
            }
            if (userId == currentAndTargetUserIds.second) {
                Slog.w(LOG_TAG, "Target user of an ongoing user switch cannot be removed.");
                return false;
            }
            synchronized (mPackagesLock) {
                synchronized (mUsersLock) {
                    userData = mUsers.get(userId);
                    if (userId == UserHandle.USER_SYSTEM) {
                        Slog.e(LOG_TAG, "System user cannot be removed.");
                        return false;
                    }

                    if (userData == null) {
                        Slog.e(LOG_TAG, TextUtils.formatSimple(
                                "Cannot remove user %d, invalid user id provided.", userId));
                        return false;
                    final int userRemovability = getUserRemovabilityLocked(userId, "removed");
                    if (userRemovability != UserManager.REMOVE_RESULT_USER_IS_REMOVABLE) {
                        return UserManager.isRemoveResultSuccessful(userRemovability);
                    }

                    if (isNonRemovableMainUser(userData.info)) {
                        Slog.e(LOG_TAG, "Main user cannot be removed when "
                                + "it's a permanent admin user.");
                        return false;
                    }

                    if (mRemovingUserIds.get(userId)) {
                        Slog.e(LOG_TAG, TextUtils.formatSimple(
                                "User %d is already scheduled for removal.", userId));
                        return false;
                    }

                    userData = mUsers.get(userId);
                    Slog.i(LOG_TAG, "Removing user " + userId);
                    addRemovingUserIdLocked(userId);
                }

                // Set this to a partially created user, so that the user will be purged
                // on next startup, in case the runtime stops now before stopping and
                // removing the user completely.
@@ -5536,6 +5538,7 @@ public class UserManagerService extends IUserManager.Stub {
    @Override
    public @UserManager.RemoveResult int removeUserWhenPossible(@UserIdInt int userId,
            boolean overrideDevicePolicy) {
        Slog.i(LOG_TAG, "removeUserWhenPossible u" + userId);
        checkCreateUsersPermission("Only the system can remove users");

        if (!overrideDevicePolicy) {
@@ -5545,64 +5548,46 @@ public class UserManagerService extends IUserManager.Stub {
                return UserManager.REMOVE_RESULT_ERROR_USER_RESTRICTION;
            }
        }
        Slog.i(LOG_TAG, "Attempting to immediately remove user " + userId);
        if (removeUserWithProfilesUnchecked(userId)) {
            return UserManager.REMOVE_RESULT_REMOVED;
        }
        Slog.i(LOG_TAG, TextUtils.formatSimple(
                "Unable to immediately remove user %d. Now trying to set it ephemeral.", userId));
        return setUserEphemeralUnchecked(userId);
    }

    /**
     * Returns the user's removability status.
     * User is removable if the return value is {@link UserManager#REMOVE_RESULT_USER_IS_REMOVABLE}.
     * If the user is not removable this method also prints the reason.
     * See also {@link UserManager#isRemoveResultSuccessful}.
     */
    @GuardedBy("mUsersLock")
    private @UserManager.RemoveResult int getUserRemovabilityLocked(@UserIdInt int userId,
            String msg) {
        String prefix = TextUtils.formatSimple("User %d can not be %s, ", userId, msg);
        if (userId == UserHandle.USER_SYSTEM) {
            Slog.e(LOG_TAG, "System user cannot be removed.");
            Slog.e(LOG_TAG, prefix + "system user cannot be removed.");
            return UserManager.REMOVE_RESULT_ERROR_SYSTEM_USER;
        }

        final long ident = Binder.clearCallingIdentity();
        try {
            final UserData userData;
            synchronized (mPackagesLock) {
                synchronized (mUsersLock) {
                    userData = mUsers.get(userId);
        final UserData userData = mUsers.get(userId);
        if (userData == null) {
                        Slog.e(LOG_TAG,
                                "Cannot remove user " + userId + ", invalid user id provided.");
            Slog.e(LOG_TAG, prefix + "invalid user id provided.");
            return UserManager.REMOVE_RESULT_ERROR_USER_NOT_FOUND;
        }

        if (isNonRemovableMainUser(userData.info)) {
                        Slog.e(LOG_TAG, "Main user cannot be removed when "
                                + "it's a permanent admin user.");
            Slog.e(LOG_TAG, prefix
                    + "main user cannot be removed when it's a permanent admin user.");
            return UserManager.REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN;
        }

        if (mRemovingUserIds.get(userId)) {
                        Slog.e(LOG_TAG, "User " + userId + " is already scheduled for removal.");
            Slog.w(LOG_TAG, prefix + "it is already scheduled for removal.");
            return UserManager.REMOVE_RESULT_ALREADY_BEING_REMOVED;
        }
        return UserManager.REMOVE_RESULT_USER_IS_REMOVABLE;
    }

                // Attempt to immediately remove a non-current and non-target user
                Pair<Integer, Integer> currentAndTargetUserIds = getCurrentAndTargetUserIds();
                if (userId != currentAndTargetUserIds.first
                        && userId != currentAndTargetUserIds.second) {
                    // Attempt to remove the user. This will fail if the user is the current user
                    if (removeUserWithProfilesUnchecked(userId)) {
                        return UserManager.REMOVE_RESULT_REMOVED;
                    }
                }
                // If the user was not immediately removed, make sure it is marked as ephemeral.
                // Don't mark as disabled since, per UserInfo.FLAG_DISABLED documentation, an
                // ephemeral user should only be marked as disabled when its removal is in progress.
                Slog.i(LOG_TAG, TextUtils.formatSimple("Unable to immediately remove user %d "
                                + "(%s is %d). User is set as ephemeral and will be removed on "
                                + "user switch or reboot.",
                        userId,
                        userId == currentAndTargetUserIds.first
                                ? "current user"
                                : "target user of an ongoing user switch",
                        userId));
                userData.info.flags |= UserInfo.FLAG_EPHEMERAL;
                writeUserLP(userData);

                return UserManager.REMOVE_RESULT_DEFERRED;
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

    private void finishRemoveUser(final @UserIdInt int userId) {
        Slog.i(LOG_TAG, "finishRemoveUser " + userId);