diff options
7 files changed, 68 insertions, 18 deletions
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index 9cf467534daf..3139151b78a0 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -73,6 +73,9 @@ public class UserInfo implements Parcelable { /** * Indicates that this user is disabled. + * + * <p>Note: If an ephemeral user is disabled, it shouldn't be later re-enabled. Ephemeral users + * are disabled as their removal is in progress to indicate that they shouldn't be re-entered. */ public static final int FLAG_DISABLED = 0x00000040; @@ -171,6 +174,10 @@ public class UserInfo implements Parcelable { * @return true if this user can be switched to. **/ public boolean supportsSwitchTo() { + if (isEphemeral() && !isEnabled()) { + // Don't support switching to an ephemeral user with removal in progress. + return false; + } // TODO remove fw.show_hidden_users when we have finished developing managed profiles. return !isManagedProfile() || SystemProperties.getBoolean("fw.show_hidden_users", false); } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 1a093d8e5d8e..da7f85fc0e1d 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1371,8 +1371,12 @@ public class UserManager { /** * Sets the user as enabled, if such an user exists. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. - * Note that the default is true, it's only that managed profiles might not be enabled. + * + * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + * + * <p>Note that the default is true, it's only that managed profiles might not be enabled. + * Also ephemeral users can be disabled to indicate that their removal is in progress and they + * shouldn't be re-entered. Therefore ephemeral users should not be re-enabled once disabled. * * @param userHandle the id of the profile to enable * @hide diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java index d2ece8bba3ad..f399719fa1fc 100644 --- a/core/java/android/os/UserManagerInternal.java +++ b/core/java/android/os/UserManagerInternal.java @@ -109,6 +109,17 @@ public abstract class UserManagerInternal { public abstract void removeAllUsers(); /** + * Called by the activity manager when the ephemeral user goes to background and its removal + * starts as a result. + * + * <p>It marks the ephemeral user as disabled in order to prevent it from being re-entered + * before its removal finishes. + * + * @param userId the ID of the ephemeral user. + */ + public abstract void onEphemeralUserStop(int userId); + + /** * Same as UserManager.createUser(), but bypasses the check for DISALLOW_ADD_USER. * * <p>Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 4c67010f54aa..53fd446b2444 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -199,24 +199,26 @@ public class UserSwitcherController { currentUserInfo = info; } boolean switchToEnabled = allowUserSwitching || isCurrent; - if (info.isGuest()) { - guestRecord = new UserRecord(info, null /* picture */, - true /* isGuest */, isCurrent, false /* isAddUser */, - false /* isRestricted */, switchToEnabled); - } else if (info.isEnabled() && info.supportsSwitchToByUser()) { - Bitmap picture = bitmaps.get(info.id); - if (picture == null) { - picture = mUserManager.getUserIcon(info.id); - - if (picture != null) { - picture = BitmapHelper.createCircularClip( - picture, avatarSize, avatarSize); + if (info.isEnabled()) { + if (info.isGuest()) { + guestRecord = new UserRecord(info, null /* picture */, + true /* isGuest */, isCurrent, false /* isAddUser */, + false /* isRestricted */, switchToEnabled); + } else if (info.supportsSwitchToByUser()) { + Bitmap picture = bitmaps.get(info.id); + if (picture == null) { + picture = mUserManager.getUserIcon(info.id); + + if (picture != null) { + picture = BitmapHelper.createCircularClip( + picture, avatarSize, avatarSize); + } } + int index = isCurrent ? 0 : records.size(); + records.add(index, new UserRecord(info, picture, false /* isGuest */, + isCurrent, false /* isAddUser */, false /* isRestricted */, + switchToEnabled)); } - int index = isCurrent ? 0 : records.size(); - records.add(index, new UserRecord(info, picture, false /* isGuest */, - isCurrent, false /* isAddUser */, false /* isRestricted */, - switchToEnabled)); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 29608ddf5e1a..ec0e07532104 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -20511,6 +20511,10 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, "No user info for user #" + targetUserId); return false; } + if (!targetUserInfo.supportsSwitchTo()) { + Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported"); + return false; + } if (targetUserInfo.isManagedProfile()) { Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not a full user"); return false; diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index df24d0bf027b..addffd33d746 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -68,6 +68,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; +import android.os.UserManagerInternal; import android.os.storage.IMountService; import android.os.storage.StorageManager; import android.provider.Settings; @@ -82,6 +83,7 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import com.android.internal.widget.LockPatternUtils; +import com.android.server.LocalServices; import com.android.server.pm.UserManagerService; import java.io.PrintWriter; @@ -561,6 +563,10 @@ final class UserController { continue; } UserInfo userInfo = getUserInfo(oldUserId); + if (userInfo.isEphemeral()) { + LocalServices.getService(UserManagerInternal.class) + .onEphemeralUserStop(oldUserId); + } if (userInfo.isGuest() || userInfo.isEphemeral()) { // This is a user to be stopped. stopUsersLocked(oldUserId, true, null); diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index d5ed04a94f37..549026090a49 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -2982,6 +2982,22 @@ public class UserManagerService extends IUserManager.Stub { } @Override + public void onEphemeralUserStop(int userId) { + synchronized (mUsersLock) { + UserInfo userInfo = getUserInfoLU(userId); + if (userInfo != null && userInfo.isEphemeral()) { + // Do not allow switching back to the ephemeral user again as the user is going + // to be deleted. + userInfo.flags |= UserInfo.FLAG_DISABLED; + if (userInfo.isGuest()) { + // Indicate that the guest will be deleted after it stops. + userInfo.guestToRemove = true; + } + } + } + } + + @Override public UserInfo createUserEvenWhenDisallowed(String name, int flags) { UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL); // Keep this in sync with UserManager.createUser |