summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/pm/UserProperties.java75
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/am/UserController.java65
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java14
-rw-r--r--services/core/java/com/android/server/pm/UserTypeFactory.java1
-rw-r--r--services/tests/servicestests/res/xml/usertypes_test_profile.xml1
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UserControllerTest.java99
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java4
10 files changed, 244 insertions, 33 deletions
diff --git a/core/java/android/content/pm/UserProperties.java b/core/java/android/content/pm/UserProperties.java
index c4012688406d..57749d43eb37 100644
--- a/core/java/android/content/pm/UserProperties.java
+++ b/core/java/android/content/pm/UserProperties.java
@@ -68,6 +68,8 @@ public final class UserProperties implements Parcelable {
"authAlwaysRequiredToDisableQuietMode";
private static final String ATTR_DELETE_APP_WITH_PARENT = "deleteAppWithParent";
private static final String ATTR_ALWAYS_VISIBLE = "alwaysVisible";
+ private static final String ATTR_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING =
+ "allowStoppingUserWithDelayedLocking";
private static final String ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY =
"crossProfileContentSharingStrategy";
@@ -89,7 +91,8 @@ public final class UserProperties implements Parcelable {
INDEX_SHOW_IN_QUIET_MODE,
INDEX_SHOW_IN_SHARING_SURFACES,
INDEX_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE,
- INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY
+ INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY,
+ INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING,
})
@Retention(RetentionPolicy.SOURCE)
private @interface PropertyIndex {
@@ -110,6 +113,7 @@ public final class UserProperties implements Parcelable {
private static final int INDEX_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE = 13;
private static final int INDEX_SHOW_IN_SHARING_SURFACES = 14;
private static final int INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY = 15;
+ private static final int INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING = 16;
/** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
private long mPropertiesPresent = 0;
@@ -450,6 +454,7 @@ public final class UserProperties implements Parcelable {
setCrossProfileIntentResolutionStrategy(orig.getCrossProfileIntentResolutionStrategy());
setDeleteAppWithParent(orig.getDeleteAppWithParent());
setAlwaysVisible(orig.getAlwaysVisible());
+ setAllowStoppingUserWithDelayedLocking(orig.getAllowStoppingUserWithDelayedLocking());
}
if (hasManagePermission) {
// Add items that require MANAGE_USERS or stronger.
@@ -725,6 +730,11 @@ public final class UserProperties implements Parcelable {
this.mUpdateCrossProfileIntentFiltersOnOTA = val;
setPresent(INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA);
}
+ /**
+ Indicate if {@link com.android.server.pm.CrossProfileIntentFilter}s need to be updated during
+ OTA update between user-parent
+ */
+ private boolean mUpdateCrossProfileIntentFiltersOnOTA;
/**
* Returns whether a profile shares media with its parent user.
@@ -786,12 +796,38 @@ public final class UserProperties implements Parcelable {
}
private boolean mAuthAlwaysRequiredToDisableQuietMode;
- /*
- Indicate if {@link com.android.server.pm.CrossProfileIntentFilter}s need to be updated during
- OTA update between user-parent
+ /**
+ * Returns whether a user (usually a profile) is allowed to leave the CE storage unlocked when
+ * stopped.
+ *
+ * <p> Setting this property to true will enable the user's CE storage to remain unlocked when
+ * the user is stopped using
+ * {@link com.android.server.am.ActivityManagerService#stopUserWithDelayedLocking(int,
+ * boolean, IStopUserCallback)}.
+ *
+ * <p> When this property is false, delayed locking may still be applicable at a global
+ * level for all users via the {@code config_multiuserDelayUserDataLocking}. That is, delayed
+ * locking for a user can happen if either the device configuration is set or if this property
+ * is set. When both, the config and the property value is false, the user storage is always
+ * locked when the user is stopped.
+ * @hide
*/
- private boolean mUpdateCrossProfileIntentFiltersOnOTA;
-
+ public boolean getAllowStoppingUserWithDelayedLocking() {
+ if (isPresent(INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING)) {
+ return mAllowStoppingUserWithDelayedLocking;
+ }
+ if (mDefaultProperties != null) {
+ return mDefaultProperties.mAllowStoppingUserWithDelayedLocking;
+ }
+ throw new SecurityException(
+ "You don't have permission to query allowStoppingUserWithDelayedLocking");
+ }
+ /** @hide */
+ public void setAllowStoppingUserWithDelayedLocking(boolean val) {
+ this.mAllowStoppingUserWithDelayedLocking = val;
+ setPresent(INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING);
+ }
+ private boolean mAllowStoppingUserWithDelayedLocking;
/**
* Returns the user's {@link CrossProfileIntentFilterAccessControlLevel}.
@@ -899,6 +935,8 @@ public final class UserProperties implements Parcelable {
+ ", mCredentialShareableWithParent=" + isCredentialShareableWithParent()
+ ", mAuthAlwaysRequiredToDisableQuietMode="
+ isAuthAlwaysRequiredToDisableQuietMode()
+ + ", mAllowStoppingUserWithDelayedLocking="
+ + getAllowStoppingUserWithDelayedLocking()
+ ", mDeleteAppWithParent=" + getDeleteAppWithParent()
+ ", mAlwaysVisible=" + getAlwaysVisible()
+ ", mCrossProfileContentSharingStrategy=" + getCrossProfileContentSharingStrategy()
@@ -929,6 +967,8 @@ public final class UserProperties implements Parcelable {
+ isCredentialShareableWithParent());
pw.println(prefix + " mAuthAlwaysRequiredToDisableQuietMode="
+ isAuthAlwaysRequiredToDisableQuietMode());
+ pw.println(prefix + " mAllowStoppingUserWithDelayedLocking="
+ + getAllowStoppingUserWithDelayedLocking());
pw.println(prefix + " mDeleteAppWithParent=" + getDeleteAppWithParent());
pw.println(prefix + " mAlwaysVisible=" + getAlwaysVisible());
pw.println(prefix + " mCrossProfileContentSharingStrategy="
@@ -1005,6 +1045,9 @@ public final class UserProperties implements Parcelable {
case ATTR_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE:
setAuthAlwaysRequiredToDisableQuietMode(parser.getAttributeBoolean(i));
break;
+ case ATTR_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING:
+ setAllowStoppingUserWithDelayedLocking(parser.getAttributeBoolean(i));
+ break;
case ATTR_DELETE_APP_WITH_PARENT:
setDeleteAppWithParent(parser.getAttributeBoolean(i));
break;
@@ -1079,6 +1122,10 @@ public final class UserProperties implements Parcelable {
serializer.attributeBoolean(null, ATTR_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE,
mAuthAlwaysRequiredToDisableQuietMode);
}
+ if (isPresent(INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING)) {
+ serializer.attributeBoolean(null, ATTR_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING,
+ mAllowStoppingUserWithDelayedLocking);
+ }
if (isPresent(INDEX_DELETE_APP_WITH_PARENT)) {
serializer.attributeBoolean(null, ATTR_DELETE_APP_WITH_PARENT,
mDeleteAppWithParent);
@@ -1110,6 +1157,7 @@ public final class UserProperties implements Parcelable {
dest.writeBoolean(mMediaSharedWithParent);
dest.writeBoolean(mCredentialShareableWithParent);
dest.writeBoolean(mAuthAlwaysRequiredToDisableQuietMode);
+ dest.writeBoolean(mAllowStoppingUserWithDelayedLocking);
dest.writeBoolean(mDeleteAppWithParent);
dest.writeBoolean(mAlwaysVisible);
dest.writeInt(mCrossProfileContentSharingStrategy);
@@ -1136,6 +1184,7 @@ public final class UserProperties implements Parcelable {
mMediaSharedWithParent = source.readBoolean();
mCredentialShareableWithParent = source.readBoolean();
mAuthAlwaysRequiredToDisableQuietMode = source.readBoolean();
+ mAllowStoppingUserWithDelayedLocking = source.readBoolean();
mDeleteAppWithParent = source.readBoolean();
mAlwaysVisible = source.readBoolean();
mCrossProfileContentSharingStrategy = source.readInt();
@@ -1183,6 +1232,7 @@ public final class UserProperties implements Parcelable {
private boolean mMediaSharedWithParent = false;
private boolean mCredentialShareableWithParent = false;
private boolean mAuthAlwaysRequiredToDisableQuietMode = false;
+ private boolean mAllowStoppingUserWithDelayedLocking = false;
private boolean mDeleteAppWithParent = false;
private boolean mAlwaysVisible = false;
private @CrossProfileContentSharingStrategy int mCrossProfileContentSharingStrategy =
@@ -1302,6 +1352,16 @@ public final class UserProperties implements Parcelable {
return this;
}
+ /** Sets the value for {@link #mAllowStoppingUserWithDelayedLocking}
+ * @hide
+ */
+ public Builder setAllowStoppingUserWithDelayedLocking(
+ boolean allowStoppingUserWithDelayedLocking) {
+ mAllowStoppingUserWithDelayedLocking =
+ allowStoppingUserWithDelayedLocking;
+ return this;
+ }
+
/** Sets the value for {@link #mDeleteAppWithParent}
* @hide
*/
@@ -1352,6 +1412,7 @@ public final class UserProperties implements Parcelable {
mMediaSharedWithParent,
mCredentialShareableWithParent,
mAuthAlwaysRequiredToDisableQuietMode,
+ mAllowStoppingUserWithDelayedLocking,
mDeleteAppWithParent,
mAlwaysVisible,
mCrossProfileContentSharingStrategy);
@@ -1372,6 +1433,7 @@ public final class UserProperties implements Parcelable {
boolean mediaSharedWithParent,
boolean credentialShareableWithParent,
boolean authAlwaysRequiredToDisableQuietMode,
+ boolean allowStoppingUserWithDelayedLocking,
boolean deleteAppWithParent,
boolean alwaysVisible,
@CrossProfileContentSharingStrategy int crossProfileContentSharingStrategy) {
@@ -1390,6 +1452,7 @@ public final class UserProperties implements Parcelable {
setCredentialShareableWithParent(credentialShareableWithParent);
setAuthAlwaysRequiredToDisableQuietMode(
authAlwaysRequiredToDisableQuietMode);
+ setAllowStoppingUserWithDelayedLocking(allowStoppingUserWithDelayedLocking);
setDeleteAppWithParent(deleteAppWithParent);
setAlwaysVisible(alwaysVisible);
setCrossProfileContentSharingStrategy(crossProfileContentSharingStrategy);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3e533a6ce601..b992e7714617 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17510,6 +17510,8 @@ public class ActivityManagerService extends IActivityManager.Stub
* other {@code ActivityManager#USER_OP_*} codes for failure.
*
*/
+ // TODO(b/302662311): Add javadoc changes corresponding to the user property that allows
+ // delayed locking behavior once the private space flag is finalized.
@Override
public int stopUserWithDelayedLocking(final int userId, boolean force,
final IStopUserCallback callback) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 47a99fe24ec4..a6b532cdef09 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -356,6 +356,8 @@ class UserController implements Handler.Callback {
* Once total number of unlocked users reach mMaxRunningUsers, least recently used user
* will be locked.
*/
+ // TODO(b/302662311): Add javadoc changes corresponding to the user property that allows
+ // delayed locking behavior once the private space flag is finalized.
@GuardedBy("mLock")
private boolean mDelayUserDataLocking;
@@ -365,11 +367,12 @@ class UserController implements Handler.Callback {
private volatile boolean mAllowUserUnlocking;
/**
- * Keep track of last active users for mDelayUserDataLocking.
- * The latest stopped user is placed in front while the least recently stopped user in back.
+ * Keep track of last active users for delayUserDataLocking.
+ * The most recently stopped user with delayed locking is placed in front, while the least
+ * recently stopped user in back.
*/
@GuardedBy("mLock")
- private final ArrayList<Integer> mLastActiveUsers = new ArrayList<>();
+ private final ArrayList<Integer> mLastActiveUsersForDelayedLocking = new ArrayList<>();
/**
* Map of userId to {@link UserCompletedEventType} event flags, indicating which as-yet-
@@ -1011,20 +1014,21 @@ class UserController implements Handler.Callback {
Slogf.i(TAG, "stopSingleUserLU userId=" + userId);
final UserState uss = mStartedUsers.get(userId);
if (uss == null) { // User is not started
- // If mDelayUserDataLocking is set and allowDelayedLocking is not set, we need to lock
- // the requested user as the client wants to stop and lock the user. On the other hand,
- // having keyEvictedCallback set will lead into locking user if mDelayUserDataLocking
- // is set as that means client wants to lock the user immediately.
- // If mDelayUserDataLocking is not set, the user was already locked when it was stopped
- // and no further action is necessary.
- if (mDelayUserDataLocking) {
+ // If canDelayDataLockingForUser() is true and allowDelayedLocking is false, we need
+ // to lock the requested user as the client wants to stop and lock the user. On the
+ // other hand, having keyEvictedCallback set will lead into locking user if
+ // canDelayDataLockingForUser() is true as that means client wants to lock the user
+ // immediately.
+ // If canDelayDataLockingForUser() is false, the user was already locked when it was
+ // stopped and no further action is necessary.
+ if (canDelayDataLockingForUser(userId)) {
if (allowDelayedLocking && keyEvictedCallback != null) {
Slogf.wtf(TAG, "allowDelayedLocking set with KeyEvictedCallback, ignore it"
+ " and lock user:" + userId, new RuntimeException());
allowDelayedLocking = false;
}
if (!allowDelayedLocking) {
- if (mLastActiveUsers.remove(Integer.valueOf(userId))) {
+ if (mLastActiveUsersForDelayedLocking.remove(Integer.valueOf(userId))) {
// should lock the user, user is already gone
final ArrayList<KeyEvictedCallback> keyEvictedCallbacks;
if (keyEvictedCallback != null) {
@@ -1354,14 +1358,21 @@ class UserController implements Handler.Callback {
@GuardedBy("mLock")
private int updateUserToLockLU(@UserIdInt int userId, boolean allowDelayedLocking) {
int userIdToLock = userId;
- if (mDelayUserDataLocking && allowDelayedLocking && !getUserInfo(userId).isEphemeral()
+ // TODO: Decouple the delayed locking flows from mMaxRunningUsers or rename the property to
+ // state maximum running unlocked users specifically
+ if (canDelayDataLockingForUser(userIdToLock) && allowDelayedLocking
+ && !getUserInfo(userId).isEphemeral()
&& !hasUserRestriction(UserManager.DISALLOW_RUN_IN_BACKGROUND, userId)) {
- mLastActiveUsers.remove((Integer) userId); // arg should be object, not index
- mLastActiveUsers.add(0, userId);
- int totalUnlockedUsers = mStartedUsers.size() + mLastActiveUsers.size();
+ // arg should be object, not index
+ mLastActiveUsersForDelayedLocking.remove((Integer) userId);
+ mLastActiveUsersForDelayedLocking.add(0, userId);
+ int totalUnlockedUsers = mStartedUsers.size()
+ + mLastActiveUsersForDelayedLocking.size();
if (totalUnlockedUsers > mMaxRunningUsers) { // should lock a user
- userIdToLock = mLastActiveUsers.get(mLastActiveUsers.size() - 1);
- mLastActiveUsers.remove(mLastActiveUsers.size() - 1);
+ userIdToLock = mLastActiveUsersForDelayedLocking.get(
+ mLastActiveUsersForDelayedLocking.size() - 1);
+ mLastActiveUsersForDelayedLocking
+ .remove(mLastActiveUsersForDelayedLocking.size() - 1);
Slogf.i(TAG, "finishUserStopped, stopping user:" + userId
+ " lock user:" + userIdToLock);
} else {
@@ -1374,6 +1385,24 @@ class UserController implements Handler.Callback {
}
/**
+ * Returns whether the user can have its CE storage left unlocked, even when it is stopped,
+ * either due to a global device configuration or an individual user's property.
+ */
+ private boolean canDelayDataLockingForUser(@UserIdInt int userIdToLock) {
+ if (allowBiometricUnlockForPrivateProfile()) {
+ final UserProperties userProperties = getUserProperties(userIdToLock);
+ return (mDelayUserDataLocking || (userProperties != null
+ && userProperties.getAllowStoppingUserWithDelayedLocking()));
+ }
+ return mDelayUserDataLocking;
+ }
+
+ private boolean allowBiometricUnlockForPrivateProfile() {
+ return android.os.Flags.allowPrivateProfile()
+ && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace();
+ }
+
+ /**
* Determines the list of users that should be stopped together with the specified
* {@code userId}. The returned list includes {@code userId}.
*/
@@ -3161,7 +3190,7 @@ class UserController implements Handler.Callback {
pw.println(" mCurrentProfileIds:" + Arrays.toString(mCurrentProfileIds));
pw.println(" mCurrentUserId:" + mCurrentUserId);
pw.println(" mTargetUserId:" + mTargetUserId);
- pw.println(" mLastActiveUsers:" + mLastActiveUsers);
+ pw.println(" mLastActiveUsersForDelayedLocking:" + mLastActiveUsersForDelayedLocking);
pw.println(" mDelayUserDataLocking:" + mDelayUserDataLocking);
pw.println(" mAllowUserUnlocking:" + mAllowUserUnlocking);
pw.println(" shouldStopUserOnSwitch():" + shouldStopUserOnSwitch());
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b53a21c9aa1c..a7b52f4e7a58 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1519,7 +1519,7 @@ public class UserManagerService extends IUserManager.Stub {
try {
if (enableQuietMode) {
- ActivityManager.getService().stopUser(userId, /* force= */ true, null);
+ stopUserForQuietMode(userId);
LocalServices.getService(ActivityManagerInternal.class)
.killForegroundAppsForUser(userId);
} else {
@@ -1547,6 +1547,18 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ private void stopUserForQuietMode(int userId) throws RemoteException {
+ if (android.os.Flags.allowPrivateProfile()
+ && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) {
+ // Allow delayed locking since some profile types want to be able to unlock again via
+ // biometrics.
+ ActivityManager.getService()
+ .stopUserWithDelayedLocking(userId, /* force= */ true, null);
+ return;
+ }
+ ActivityManager.getService().stopUser(userId, /* force= */ true, null);
+ }
+
private void logQuietModeEnabled(@UserIdInt int userId, boolean enableQuietMode,
@Nullable String callingPackage) {
Slogf.i(LOG_TAG,
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 7f013b8df444..7386301bdd6e 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -311,6 +311,7 @@ public final class UserTypeFactory {
.setStartWithParent(true)
.setCredentialShareableWithParent(true)
.setAuthAlwaysRequiredToDisableQuietMode(true)
+ .setAllowStoppingUserWithDelayedLocking(true)
.setMediaSharedWithParent(false)
.setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
.setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE)
diff --git a/services/tests/servicestests/res/xml/usertypes_test_profile.xml b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
index 9b047f2abff7..6537d47106a9 100644
--- a/services/tests/servicestests/res/xml/usertypes_test_profile.xml
+++ b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
@@ -40,6 +40,7 @@
mediaSharedWithParent='true'
credentialShareableWithParent='false'
authAlwaysRequiredToDisableQuietMode='true'
+ allowStoppingUserWithDelayedLocking='true'
showInSettings='23'
hideInSettingsInQuietMode='true'
inheritDevicePolicy='450'
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index d26d67107001..77b1455a2ecc 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -92,6 +92,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.IStorageManager;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.Log;
import android.view.Display;
@@ -104,11 +105,14 @@ import com.android.server.am.UserState.KeyEvictedCallback;
import com.android.server.pm.UserJourneyLogger;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
+import com.android.server.pm.UserTypeDetails;
+import com.android.server.pm.UserTypeFactory;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerService;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -175,6 +179,9 @@ public class UserControllerTest {
USER_START_MSG,
REPORT_LOCKED_BOOT_COMPLETE_MSG);
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Before
public void setUp() throws Exception {
runWithDexmakerShareClassLoader(() -> {
@@ -789,28 +796,99 @@ public class UserControllerTest {
}
@Test
- public void testStartProfile() throws Exception {
- setUpAndStartProfileInBackground(TEST_USER_ID1);
+ public void testStartManagedProfile() throws Exception {
+ setUpAndStartProfileInBackground(TEST_USER_ID1, UserManager.USER_TYPE_PROFILE_MANAGED);
startBackgroundUserAssertions();
verifyUserAssignedToDisplay(TEST_USER_ID1, Display.DEFAULT_DISPLAY);
}
@Test
- public void testStartProfile_whenUsersOnSecondaryDisplaysIsEnabled() throws Exception {
+ public void testStartManagedProfile_whenUsersOnSecondaryDisplaysIsEnabled() throws Exception {
mockIsUsersOnSecondaryDisplaysEnabled(true);
- setUpAndStartProfileInBackground(TEST_USER_ID1);
+ setUpAndStartProfileInBackground(TEST_USER_ID1, UserManager.USER_TYPE_PROFILE_MANAGED);
startBackgroundUserAssertions();
verifyUserAssignedToDisplay(TEST_USER_ID1, Display.DEFAULT_DISPLAY);
}
@Test
- public void testStopProfile() throws Exception {
- setUpAndStartProfileInBackground(TEST_USER_ID1);
+ public void testStopManagedProfile() throws Exception {
+ setUpAndStartProfileInBackground(TEST_USER_ID1, UserManager.USER_TYPE_PROFILE_MANAGED);
+ assertProfileLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* expectLocking= */ true);
+ verifyUserUnassignedFromDisplay(TEST_USER_ID1);
+ }
+
+ @Test
+ public void testStopPrivateProfile() throws Exception {
+ mUserController.setInitialConfig(/* mUserSwitchUiEnabled */ true,
+ /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
+ mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+ android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE);
+ setUpAndStartProfileInBackground(TEST_USER_ID1, UserManager.USER_TYPE_PROFILE_PRIVATE);
assertProfileLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* expectLocking= */ true);
verifyUserUnassignedFromDisplay(TEST_USER_ID1);
+
+ mSetFlagsRule.disableFlags(
+ android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE);
+ setUpAndStartProfileInBackground(TEST_USER_ID2, UserManager.USER_TYPE_PROFILE_PRIVATE);
+ assertProfileLockedOrUnlockedAfterStopping(TEST_USER_ID2, /* expectLocking= */ true);
+ verifyUserUnassignedFromDisplay(TEST_USER_ID2);
+ }
+
+ @Test
+ public void testStopPrivateProfileWithDelayedLocking() throws Exception {
+ mUserController.setInitialConfig(/* mUserSwitchUiEnabled */ true,
+ /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
+ mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+ android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE);
+ setUpAndStartProfileInBackground(TEST_USER_ID1, UserManager.USER_TYPE_PROFILE_PRIVATE);
+ assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* delayedLocking= */ true,
+ /* keyEvictedCallback */ null, /* expectLocking= */ false);
+ }
+
+ @Test
+ public void testStopPrivateProfileWithDelayedLocking_flagDisabled() throws Exception {
+ mUserController.setInitialConfig(/* mUserSwitchUiEnabled */ true,
+ /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
+ mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE);
+ mSetFlagsRule.disableFlags(
+ android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE);
+ setUpAndStartProfileInBackground(TEST_USER_ID1, UserManager.USER_TYPE_PROFILE_PRIVATE);
+ assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* delayedLocking= */ true,
+ /* keyEvictedCallback */ null, /* expectLocking= */ true);
+
+ mSetFlagsRule.disableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE);
+ mSetFlagsRule.enableFlags(
+ android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE);
+ setUpAndStartProfileInBackground(TEST_USER_ID2, UserManager.USER_TYPE_PROFILE_PRIVATE);
+ assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID2, /* delayedLocking= */ true,
+ /* keyEvictedCallback */ null, /* expectLocking= */ true);
+ }
+
+ @Test
+ public void testStopPrivateProfileWithDelayedLocking_maxRunningUsersBreached()
+ throws Exception {
+ mUserController.setInitialConfig(/* mUserSwitchUiEnabled */ true,
+ /* maxRunningUsers= */ 1, /* delayUserDataLocking= */ false);
+ mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+ android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE);
+ setUpAndStartProfileInBackground(TEST_USER_ID1, UserManager.USER_TYPE_PROFILE_PRIVATE);
+ setUpAndStartProfileInBackground(TEST_USER_ID2, UserManager.USER_TYPE_PROFILE_MANAGED);
+ assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* delayedLocking= */ true,
+ /* keyEvictedCallback */ null, /* expectLocking= */ true);
+ }
+
+ @Test
+ public void testStopManagedProfileWithDelayedLocking() throws Exception {
+ mUserController.setInitialConfig(/* mUserSwitchUiEnabled */ true,
+ /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
+ mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+ android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE);
+ setUpAndStartProfileInBackground(TEST_USER_ID1, UserManager.USER_TYPE_PROFILE_MANAGED);
+ assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* delayedLocking= */ true,
+ /* keyEvictedCallback */ null, /* expectLocking= */ true);
}
/** Tests handleIncomingUser() for a variety of permissions and situations. */
@@ -1001,8 +1079,8 @@ public class UserControllerTest {
mUserStates.put(userId, mUserController.getStartedUserState(userId));
}
- private void setUpAndStartProfileInBackground(int userId) throws Exception {
- setUpUser(userId, UserInfo.FLAG_PROFILE, false, UserManager.USER_TYPE_PROFILE_MANAGED);
+ private void setUpAndStartProfileInBackground(int userId, String userType) throws Exception {
+ setUpUser(userId, UserInfo.FLAG_PROFILE, false, userType);
assertThat(mUserController.startProfile(userId, /* evenWhenDisabled=*/ false,
/* unlockListener= */ null)).isTrue();
@@ -1070,6 +1148,11 @@ public class UserControllerTest {
userInfo.preCreated = preCreated;
when(mInjector.mUserManagerMock.getUserInfo(eq(userId))).thenReturn(userInfo);
when(mInjector.mUserManagerMock.isPreCreated(userId)).thenReturn(preCreated);
+
+ UserTypeDetails userTypeDetails = UserTypeFactory.getUserTypes().get(userType);
+ assertThat(userTypeDetails).isNotNull();
+ when(mInjector.mUserManagerInternalMock.getUserProperties(eq(userId)))
+ .thenReturn(userTypeDetails.getDefaultUserPropertiesReference());
}
private static List<String> getActions(List<Intent> intents) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
index 72cc969b5fb1..d7ed7c2d6469 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
@@ -69,6 +69,7 @@ public class UserManagerServiceUserPropertiesTest {
.setMediaSharedWithParent(false)
.setCredentialShareableWithParent(true)
.setAuthAlwaysRequiredToDisableQuietMode(false)
+ .setAllowStoppingUserWithDelayedLocking(false)
.setDeleteAppWithParent(false)
.setAlwaysVisible(false)
.setCrossProfileContentSharingStrategy(0)
@@ -85,6 +86,7 @@ public class UserManagerServiceUserPropertiesTest {
actualProps.setMediaSharedWithParent(true);
actualProps.setCredentialShareableWithParent(false);
actualProps.setAuthAlwaysRequiredToDisableQuietMode(true);
+ actualProps.setAllowStoppingUserWithDelayedLocking(true);
actualProps.setDeleteAppWithParent(true);
actualProps.setAlwaysVisible(true);
actualProps.setCrossProfileContentSharingStrategy(1);
@@ -130,6 +132,7 @@ public class UserManagerServiceUserPropertiesTest {
.setMediaSharedWithParent(true)
.setDeleteAppWithParent(true)
.setAuthAlwaysRequiredToDisableQuietMode(false)
+ .setAllowStoppingUserWithDelayedLocking(false)
.setAlwaysVisible(true)
.build();
final UserProperties orig = new UserProperties(defaultProps);
@@ -139,6 +142,7 @@ public class UserManagerServiceUserPropertiesTest {
orig.setInheritDevicePolicy(9456);
orig.setDeleteAppWithParent(false);
orig.setAuthAlwaysRequiredToDisableQuietMode(true);
+ orig.setAllowStoppingUserWithDelayedLocking(true);
orig.setAlwaysVisible(false);
// Test every permission level. (Currently, it's linear so it's easy.)
@@ -184,6 +188,8 @@ public class UserManagerServiceUserPropertiesTest {
assertEqualGetterOrThrows(orig::getDeleteAppWithParent,
copy::getDeleteAppWithParent, exposeAll);
assertEqualGetterOrThrows(orig::getAlwaysVisible, copy::getAlwaysVisible, exposeAll);
+ assertEqualGetterOrThrows(orig::getAllowStoppingUserWithDelayedLocking,
+ copy::getAllowStoppingUserWithDelayedLocking, exposeAll);
// Items requiring hasManagePermission - put them here using hasManagePermission.
assertEqualGetterOrThrows(orig::getShowInSettings, copy::getShowInSettings,
@@ -258,6 +264,8 @@ public class UserManagerServiceUserPropertiesTest {
.isEqualTo(actual.isCredentialShareableWithParent());
assertThat(expected.isAuthAlwaysRequiredToDisableQuietMode())
.isEqualTo(actual.isAuthAlwaysRequiredToDisableQuietMode());
+ assertThat(expected.getAllowStoppingUserWithDelayedLocking())
+ .isEqualTo(actual.getAllowStoppingUserWithDelayedLocking());
assertThat(expected.getDeleteAppWithParent()).isEqualTo(actual.getDeleteAppWithParent());
assertThat(expected.getAlwaysVisible()).isEqualTo(actual.getAlwaysVisible());
assertThat(expected.getCrossProfileContentSharingStrategy())
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
index d0ad57365942..70837061b0bb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
@@ -90,6 +90,7 @@ public class UserManagerServiceUserTypeTest {
.setMediaSharedWithParent(true)
.setCredentialShareableWithParent(false)
.setAuthAlwaysRequiredToDisableQuietMode(true)
+ .setAllowStoppingUserWithDelayedLocking(true)
.setShowInSettings(900)
.setShowInSharingSurfaces(20)
.setShowInQuietMode(30)
@@ -167,6 +168,8 @@ public class UserManagerServiceUserTypeTest {
assertFalse(type.getDefaultUserPropertiesReference().isCredentialShareableWithParent());
assertTrue(type.getDefaultUserPropertiesReference()
.isAuthAlwaysRequiredToDisableQuietMode());
+ assertTrue(type.getDefaultUserPropertiesReference()
+ .getAllowStoppingUserWithDelayedLocking());
assertEquals(900, type.getDefaultUserPropertiesReference().getShowInSettings());
assertEquals(20, type.getDefaultUserPropertiesReference().getShowInSharingSurfaces());
assertEquals(30,
@@ -322,6 +325,7 @@ public class UserManagerServiceUserTypeTest {
.setMediaSharedWithParent(false)
.setCredentialShareableWithParent(true)
.setAuthAlwaysRequiredToDisableQuietMode(false)
+ .setAllowStoppingUserWithDelayedLocking(false)
.setShowInSettings(20)
.setInheritDevicePolicy(21)
.setShowInSharingSurfaces(22)
@@ -367,6 +371,8 @@ public class UserManagerServiceUserTypeTest {
.isCredentialShareableWithParent());
assertFalse(aospType.getDefaultUserPropertiesReference()
.isAuthAlwaysRequiredToDisableQuietMode());
+ assertFalse(aospType.getDefaultUserPropertiesReference()
+ .getAllowStoppingUserWithDelayedLocking());
assertEquals(20, aospType.getDefaultUserPropertiesReference().getShowInSettings());
assertEquals(21, aospType.getDefaultUserPropertiesReference()
.getInheritDevicePolicy());
@@ -420,6 +426,8 @@ public class UserManagerServiceUserTypeTest {
.isCredentialShareableWithParent());
assertTrue(aospType.getDefaultUserPropertiesReference()
.isAuthAlwaysRequiredToDisableQuietMode());
+ assertTrue(aospType.getDefaultUserPropertiesReference()
+ .getAllowStoppingUserWithDelayedLocking());
assertEquals(23, aospType.getDefaultUserPropertiesReference().getShowInSettings());
assertEquals(22,
aospType.getDefaultUserPropertiesReference().getShowInSharingSurfaces());
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index ced0bb5bc51c..a743fff5d2ea 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -342,8 +342,12 @@ public final class UserManagerTest {
assertThat(typeProps.getCrossProfileContentSharingStrategy())
.isEqualTo(privateProfileUserProperties.getCrossProfileContentSharingStrategy());
assertThrows(SecurityException.class, privateProfileUserProperties::getDeleteAppWithParent);
+ assertThrows(SecurityException.class,
+ privateProfileUserProperties::getAllowStoppingUserWithDelayedLocking);
+
compareDrawables(mUserManager.getUserBadge(),
Resources.getSystem().getDrawable(userTypeDetails.getBadgePlain()));
+
// Verify private profile parent
assertThat(mUserManager.getProfileParent(mainUserId)).isNull();
UserInfo parentProfileInfo = mUserManager.getProfileParent(userInfo.id);