diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 9c352dfa76cd2..556dfc7a96b3b 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -9609,6 +9609,37 @@ public class DevicePolicyManager { } } + /** + * Gets the user a {@link #logoutUser(ComponentName)} call would switch to, + * or {@link UserHandle#USER_NULL} if the current user is not in a session. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) + public @UserIdInt int getLogoutUserId() { + try { + return mService.getLogoutUserId(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Clears the user that {@link #logoutUser(ComponentName)} would switch to. + * + *

Typically used by system UI after it logout a session. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) + public void clearLogoutUser() { + try { + mService.clearLogoutUser(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + /** * Called by a device owner to list all secondary users on the device. Managed profiles are not * considered as secondary users. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 7804ab0015a5e..21ec0bd6664dc 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -261,6 +261,8 @@ interface IDevicePolicyManager { int startUserInBackground(in ComponentName who, in UserHandle userHandle); int stopUser(in ComponentName who, in UserHandle userHandle); int logoutUser(in ComponentName who); + int getLogoutUserId(); + void clearLogoutUser(); List getSecondaryUsers(in ComponentName who); void resetNewUserDisclaimer(); diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java index b06b024a63a46..ad472326555ec 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java @@ -607,6 +607,9 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene } else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) { addIfShouldShowAction(tempActions, new ScreenshotAction()); } else if (GLOBAL_ACTION_KEY_LOGOUT.equals(actionKey)) { + // TODO(b/206032495): should call mDevicePolicyManager.getLogoutUserId() instead of + // hardcode it to USER_SYSTEM so it properly supports headless system user mode + // (and then call mDevicePolicyManager.clearLogoutUser() after switched) if (mDevicePolicyManager.isLogoutEnabled() && currentUser.get() != null && currentUser.get().id != UserHandle.USER_SYSTEM) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 606447b16b020..35161aae90ad2 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -9692,7 +9692,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mStatLogger.dump(pw); pw.println(); pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus())); - pw.println("Logout user: " + getLogoutUserId()); + pw.println("Logout user: " + getLogoutUserIdUnchecked()); pw.println(); if (mPendingUserCreatedCallbackTokens.isEmpty()) { @@ -10805,7 +10805,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { boolean switched = false; // Save previous logout user id in case of failure - int logoutUserId = getLogoutUserId(); + int logoutUserId = getLogoutUserIdUnchecked(); synchronized (getLockObject()) { long id = mInjector.binderClearCallingIdentity(); try { @@ -10832,7 +10832,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private @UserIdInt int getLogoutUserId() { + @Override + public int getLogoutUserId() { + Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity())); + + return getLogoutUserIdUnchecked(); + } + + private @UserIdInt int getLogoutUserIdUnchecked() { if (!mInjector.userManagerIsHeadlessSystemUserMode()) { // mLogoutUserId is USER_SYSTEM as well, but there's no need to acquire the lock return UserHandle.USER_SYSTEM; @@ -10842,11 +10849,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private void setLogoutUserId(@UserIdInt int userId) { + @Override + public void clearLogoutUser() { + CallerIdentity caller = getCallerIdentity(); + Preconditions.checkCallAuthorization(canManageUsers(caller)); + + Slogf.i(LOG_TAG, "Clearing logout user as requested by %s", caller); + clearLogoutUserUnchecked(); + } + + private void clearLogoutUserUnchecked() { if (!mInjector.userManagerIsHeadlessSystemUserMode()) return; // ignore synchronized (getLockObject()) { - setLogoutUserIdLocked(userId); + setLogoutUserIdLocked(UserHandle.USER_NULL); } } @@ -10943,7 +10959,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return stopUserUnchecked(callingUserId); } - int logoutUserId = getLogoutUserId(); + int logoutUserId = getLogoutUserIdUnchecked(); if (logoutUserId == UserHandle.USER_NULL) { // Could happen on devices using headless system user mode when called before calling // switchUser() or startUserInBackground() first @@ -10958,7 +10974,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // This should never happen as target user is determined by getPreviousUserId() return UserManager.USER_OPERATION_ERROR_UNKNOWN; } - setLogoutUserId(UserHandle.USER_CURRENT); + clearLogoutUserUnchecked(); } catch (RemoteException e) { // Same process, should not happen. return UserManager.USER_OPERATION_ERROR_UNKNOWN;