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;