Loading core/api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -10416,6 +10416,7 @@ package android.os { field public static final String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background"; field public static final int REMOVE_RESULT_ALREADY_BEING_REMOVED = 2; // 0x2 field public static final int REMOVE_RESULT_DEFERRED = 1; // 0x1 field public static final int REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN = -5; // 0xfffffffb field public static final int REMOVE_RESULT_ERROR_SYSTEM_USER = -4; // 0xfffffffc field public static final int REMOVE_RESULT_ERROR_UNKNOWN = -1; // 0xffffffff field public static final int REMOVE_RESULT_ERROR_USER_NOT_FOUND = -3; // 0xfffffffd core/java/android/os/UserManager.java +13 −2 Original line number Diff line number Diff line Loading @@ -1826,6 +1826,15 @@ public class UserManager { @SystemApi public static final int REMOVE_RESULT_ERROR_SYSTEM_USER = -4; /** * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that * user being removed is a {@link UserInfo#FLAG_MAIN} user and can't be removed because * system property {@link com.android.internal.R.bool.isMainUserPermanentAdmin} is true. * @hide */ @SystemApi public static final int REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN = -5; /** * Possible response codes from {@link #removeUserWhenPossible(UserHandle, boolean)}. * Loading @@ -1838,6 +1847,7 @@ public class UserManager { REMOVE_RESULT_ERROR_USER_RESTRICTION, REMOVE_RESULT_ERROR_USER_NOT_FOUND, REMOVE_RESULT_ERROR_SYSTEM_USER, REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN, REMOVE_RESULT_ERROR_UNKNOWN, }) @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -5236,8 +5246,9 @@ public class UserManager { * @return the {@link RemoveResult} code: {@link #REMOVE_RESULT_REMOVED}, * {@link #REMOVE_RESULT_DEFERRED}, {@link #REMOVE_RESULT_ALREADY_BEING_REMOVED}, * {@link #REMOVE_RESULT_ERROR_USER_RESTRICTION}, {@link #REMOVE_RESULT_ERROR_USER_NOT_FOUND}, * {@link #REMOVE_RESULT_ERROR_SYSTEM_USER}, or {@link #REMOVE_RESULT_ERROR_UNKNOWN}. All error * codes have negative values. * {@link #REMOVE_RESULT_ERROR_SYSTEM_USER}, * {@link #REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN}, or * {@link #REMOVE_RESULT_ERROR_UNKNOWN}. All error codes have negative values. * * @hide */ Loading services/core/java/com/android/server/pm/PackageManagerShellCommand.java +4 −0 Original line number Diff line number Diff line Loading @@ -3023,6 +3023,10 @@ class PackageManagerShellCommand extends ShellCommand { case UserManager.REMOVE_RESULT_ALREADY_BEING_REMOVED: getOutPrintWriter().printf("Success: user %d is already being removed\n", userId); return 0; case UserManager.REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN: getOutPrintWriter().printf("Error: user %d is a permanent admin main user\n", userId); return 1; default: getErrPrintWriter().printf("Error: couldn't remove or mark ephemeral user id %d\n", userId); Loading services/core/java/com/android/server/pm/UserManagerService.java +35 −5 Original line number Diff line number Diff line Loading @@ -5442,6 +5442,12 @@ public class UserManagerService extends IUserManager.Stub { return false; } 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)); Loading Loading @@ -5546,6 +5552,12 @@ public class UserManagerService extends IUserManager.Stub { 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."); return UserManager.REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN; } if (mRemovingUserIds.get(userId)) { Slog.e(LOG_TAG, "User " + userId + " is already scheduled for removal."); return UserManager.REMOVE_RESULT_ALREADY_BEING_REMOVED; Loading Loading @@ -6764,7 +6776,7 @@ public class UserManagerService extends IUserManager.Stub { public void removeAllUsers() { if (UserHandle.USER_SYSTEM == getCurrentUserId()) { // Remove the non-system users straight away. removeNonSystemUsers(); removeAllUsersExceptSystemAndPermanentAdminMain(); } else { // Switch to the system user first and then remove the other users. BroadcastReceiver userSwitchedReceiver = new BroadcastReceiver() { Loading @@ -6776,7 +6788,7 @@ public class UserManagerService extends IUserManager.Stub { return; } mContext.unregisterReceiver(this); removeNonSystemUsers(); removeAllUsersExceptSystemAndPermanentAdminMain(); } }; IntentFilter userSwitchedFilter = new IntentFilter(); Loading Loading @@ -7129,14 +7141,14 @@ public class UserManagerService extends IUserManager.Stub { throw new UserManager.CheckedUserOperationException(message, userOperationResult); } /* Remove all the users except of the system one. */ private void removeNonSystemUsers() { /* Remove all the users except the system and permanent admin main.*/ private void removeAllUsersExceptSystemAndPermanentAdminMain() { ArrayList<UserInfo> usersToRemove = new ArrayList<>(); synchronized (mUsersLock) { final int userSize = mUsers.size(); for (int i = 0; i < userSize; i++) { UserInfo ui = mUsers.valueAt(i).info; if (ui.id != UserHandle.USER_SYSTEM) { if (ui.id != UserHandle.USER_SYSTEM && !isNonRemovableMainUser(ui)) { usersToRemove.add(ui); } } Loading Loading @@ -7265,4 +7277,22 @@ public class UserManagerService extends IUserManager.Stub { return mAmInternal; } /** * Returns true, when user has {@link UserInfo#FLAG_MAIN} and system property * {@link com.android.internal.R.bool.isMainUserPermanentAdmin} is true. */ private boolean isNonRemovableMainUser(UserInfo userInfo) { return userInfo.isMain() && isMainUserPermanentAdmin(); } /** * Returns true, when {@link com.android.internal.R.bool.isMainUserPermanentAdmin} is true. * If the main user is a permanent admin user it can't be deleted * or downgraded to non-admin status. */ private static boolean isMainUserPermanentAdmin() { return Resources.getSystem() .getBoolean(com.android.internal.R.bool.config_isMainUserPermanentAdmin); } } services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +29 −0 Original line number Diff line number Diff line Loading @@ -373,6 +373,29 @@ public final class UserManagerTest { assertThat(hasUser(UserHandle.USER_SYSTEM)).isTrue(); } @MediumTest @Test public void testRemoveUserWhenPossible_permanentAdminMainUserReturnsError() throws Exception { assumeHeadlessModeEnabled(); assumeTrue("Main user is not permanent admin", isMainUserPermanentAdmin()); int currentUser = ActivityManager.getCurrentUser(); final UserInfo otherUser = createUser("User 1", /* flags= */ UserInfo.FLAG_ADMIN); UserHandle mainUser = mUserManager.getMainUser(); switchUser(otherUser.id, null, true); assertThat(mUserManager.removeUserWhenPossible(mainUser, /* overrideDevicePolicy= */ false)) .isEqualTo(UserManager.REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN); assertThat(hasUser(mainUser.getIdentifier())).isTrue(); // Switch back to the starting user. switchUser(currentUser, null, true); } @MediumTest @Test public void testRemoveUserWhenPossible_invalidUserReturnsError() throws Exception { Loading Loading @@ -1423,4 +1446,10 @@ public final class UserManagerTest { private static UserHandle asHandle(int userId) { return new UserHandle(userId); } private boolean isMainUserPermanentAdmin() { return Resources.getSystem() .getBoolean(com.android.internal.R.bool.config_isMainUserPermanentAdmin); } } Loading
core/api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -10416,6 +10416,7 @@ package android.os { field public static final String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background"; field public static final int REMOVE_RESULT_ALREADY_BEING_REMOVED = 2; // 0x2 field public static final int REMOVE_RESULT_DEFERRED = 1; // 0x1 field public static final int REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN = -5; // 0xfffffffb field public static final int REMOVE_RESULT_ERROR_SYSTEM_USER = -4; // 0xfffffffc field public static final int REMOVE_RESULT_ERROR_UNKNOWN = -1; // 0xffffffff field public static final int REMOVE_RESULT_ERROR_USER_NOT_FOUND = -3; // 0xfffffffd
core/java/android/os/UserManager.java +13 −2 Original line number Diff line number Diff line Loading @@ -1826,6 +1826,15 @@ public class UserManager { @SystemApi public static final int REMOVE_RESULT_ERROR_SYSTEM_USER = -4; /** * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that * user being removed is a {@link UserInfo#FLAG_MAIN} user and can't be removed because * system property {@link com.android.internal.R.bool.isMainUserPermanentAdmin} is true. * @hide */ @SystemApi public static final int REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN = -5; /** * Possible response codes from {@link #removeUserWhenPossible(UserHandle, boolean)}. * Loading @@ -1838,6 +1847,7 @@ public class UserManager { REMOVE_RESULT_ERROR_USER_RESTRICTION, REMOVE_RESULT_ERROR_USER_NOT_FOUND, REMOVE_RESULT_ERROR_SYSTEM_USER, REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN, REMOVE_RESULT_ERROR_UNKNOWN, }) @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -5236,8 +5246,9 @@ public class UserManager { * @return the {@link RemoveResult} code: {@link #REMOVE_RESULT_REMOVED}, * {@link #REMOVE_RESULT_DEFERRED}, {@link #REMOVE_RESULT_ALREADY_BEING_REMOVED}, * {@link #REMOVE_RESULT_ERROR_USER_RESTRICTION}, {@link #REMOVE_RESULT_ERROR_USER_NOT_FOUND}, * {@link #REMOVE_RESULT_ERROR_SYSTEM_USER}, or {@link #REMOVE_RESULT_ERROR_UNKNOWN}. All error * codes have negative values. * {@link #REMOVE_RESULT_ERROR_SYSTEM_USER}, * {@link #REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN}, or * {@link #REMOVE_RESULT_ERROR_UNKNOWN}. All error codes have negative values. * * @hide */ Loading
services/core/java/com/android/server/pm/PackageManagerShellCommand.java +4 −0 Original line number Diff line number Diff line Loading @@ -3023,6 +3023,10 @@ class PackageManagerShellCommand extends ShellCommand { case UserManager.REMOVE_RESULT_ALREADY_BEING_REMOVED: getOutPrintWriter().printf("Success: user %d is already being removed\n", userId); return 0; case UserManager.REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN: getOutPrintWriter().printf("Error: user %d is a permanent admin main user\n", userId); return 1; default: getErrPrintWriter().printf("Error: couldn't remove or mark ephemeral user id %d\n", userId); Loading
services/core/java/com/android/server/pm/UserManagerService.java +35 −5 Original line number Diff line number Diff line Loading @@ -5442,6 +5442,12 @@ public class UserManagerService extends IUserManager.Stub { return false; } 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)); Loading Loading @@ -5546,6 +5552,12 @@ public class UserManagerService extends IUserManager.Stub { 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."); return UserManager.REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN; } if (mRemovingUserIds.get(userId)) { Slog.e(LOG_TAG, "User " + userId + " is already scheduled for removal."); return UserManager.REMOVE_RESULT_ALREADY_BEING_REMOVED; Loading Loading @@ -6764,7 +6776,7 @@ public class UserManagerService extends IUserManager.Stub { public void removeAllUsers() { if (UserHandle.USER_SYSTEM == getCurrentUserId()) { // Remove the non-system users straight away. removeNonSystemUsers(); removeAllUsersExceptSystemAndPermanentAdminMain(); } else { // Switch to the system user first and then remove the other users. BroadcastReceiver userSwitchedReceiver = new BroadcastReceiver() { Loading @@ -6776,7 +6788,7 @@ public class UserManagerService extends IUserManager.Stub { return; } mContext.unregisterReceiver(this); removeNonSystemUsers(); removeAllUsersExceptSystemAndPermanentAdminMain(); } }; IntentFilter userSwitchedFilter = new IntentFilter(); Loading Loading @@ -7129,14 +7141,14 @@ public class UserManagerService extends IUserManager.Stub { throw new UserManager.CheckedUserOperationException(message, userOperationResult); } /* Remove all the users except of the system one. */ private void removeNonSystemUsers() { /* Remove all the users except the system and permanent admin main.*/ private void removeAllUsersExceptSystemAndPermanentAdminMain() { ArrayList<UserInfo> usersToRemove = new ArrayList<>(); synchronized (mUsersLock) { final int userSize = mUsers.size(); for (int i = 0; i < userSize; i++) { UserInfo ui = mUsers.valueAt(i).info; if (ui.id != UserHandle.USER_SYSTEM) { if (ui.id != UserHandle.USER_SYSTEM && !isNonRemovableMainUser(ui)) { usersToRemove.add(ui); } } Loading Loading @@ -7265,4 +7277,22 @@ public class UserManagerService extends IUserManager.Stub { return mAmInternal; } /** * Returns true, when user has {@link UserInfo#FLAG_MAIN} and system property * {@link com.android.internal.R.bool.isMainUserPermanentAdmin} is true. */ private boolean isNonRemovableMainUser(UserInfo userInfo) { return userInfo.isMain() && isMainUserPermanentAdmin(); } /** * Returns true, when {@link com.android.internal.R.bool.isMainUserPermanentAdmin} is true. * If the main user is a permanent admin user it can't be deleted * or downgraded to non-admin status. */ private static boolean isMainUserPermanentAdmin() { return Resources.getSystem() .getBoolean(com.android.internal.R.bool.config_isMainUserPermanentAdmin); } }
services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +29 −0 Original line number Diff line number Diff line Loading @@ -373,6 +373,29 @@ public final class UserManagerTest { assertThat(hasUser(UserHandle.USER_SYSTEM)).isTrue(); } @MediumTest @Test public void testRemoveUserWhenPossible_permanentAdminMainUserReturnsError() throws Exception { assumeHeadlessModeEnabled(); assumeTrue("Main user is not permanent admin", isMainUserPermanentAdmin()); int currentUser = ActivityManager.getCurrentUser(); final UserInfo otherUser = createUser("User 1", /* flags= */ UserInfo.FLAG_ADMIN); UserHandle mainUser = mUserManager.getMainUser(); switchUser(otherUser.id, null, true); assertThat(mUserManager.removeUserWhenPossible(mainUser, /* overrideDevicePolicy= */ false)) .isEqualTo(UserManager.REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN); assertThat(hasUser(mainUser.getIdentifier())).isTrue(); // Switch back to the starting user. switchUser(currentUser, null, true); } @MediumTest @Test public void testRemoveUserWhenPossible_invalidUserReturnsError() throws Exception { Loading Loading @@ -1423,4 +1446,10 @@ public final class UserManagerTest { private static UserHandle asHandle(int userId) { return new UserHandle(userId); } private boolean isMainUserPermanentAdmin() { return Resources.getSystem() .getBoolean(com.android.internal.R.bool.config_isMainUserPermanentAdmin); } }