Loading services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +72 −95 Original line number Diff line number Diff line Loading @@ -26,10 +26,8 @@ import static org.testng.Assert.assertThrows; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.pm.UserProperties; Loading @@ -41,6 +39,7 @@ import android.platform.test.annotations.Postsubmit; import android.provider.Settings; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; import android.util.ArraySet; import android.util.Slog; import androidx.annotation.Nullable; Loading @@ -48,6 +47,8 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.compatibility.common.util.BlockingBroadcastReceiver; import com.google.common.collect.ImmutableList; import com.google.common.collect.Range; Loading @@ -56,16 +57,14 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; import javax.annotation.concurrent.GuardedBy; /** Test {@link UserManager} functionality. */ @Postsubmit @RunWith(AndroidJUnit4.class) Loading @@ -73,8 +72,6 @@ public final class UserManagerTest { // Taken from UserManagerService private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // 30 years private static final int REMOVE_CHECK_INTERVAL_MILLIS = 500; // 0.5 seconds private static final int REMOVE_TIMEOUT_MILLIS = 60 * 1000; // 60 seconds private static final int SWITCH_USER_TIMEOUT_SECONDS = 40; // 40 seconds // Packages which are used during tests. Loading @@ -86,12 +83,10 @@ public final class UserManagerTest { private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); private final Object mUserRemoveLock = new Object(); private UserManager mUserManager = null; private ActivityManager mActivityManager; private PackageManager mPackageManager; private List<Integer> usersToRemove; private ArraySet<Integer> mUsersToRemove; private UserSwitchWaiter mUserSwitchWaiter; @Before Loading @@ -101,30 +96,16 @@ public final class UserManagerTest { mPackageManager = mContext.getPackageManager(); mUserSwitchWaiter = new UserSwitchWaiter(TAG, SWITCH_USER_TIMEOUT_SECONDS); IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED); mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { case Intent.ACTION_USER_REMOVED: synchronized (mUserRemoveLock) { mUserRemoveLock.notifyAll(); } break; } } }, filter); mUsersToRemove = new ArraySet<>(); removeExistingUsers(); usersToRemove = new ArrayList<>(); } @After public void tearDown() throws Exception { mUserSwitchWaiter.close(); for (Integer userId : usersToRemove) { removeUser(userId); } // Making a copy of mUsersToRemove to avoid ConcurrentModificationException mUsersToRemove.stream().toList().forEach(this::removeUser); } private void removeExistingUsers() { Loading Loading @@ -406,13 +387,11 @@ public final class UserManagerTest { mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_USER, /* value= */ true, asHandle(currentUser)); try { synchronized (mUserRemoveLock) { runThenWaitForUserRemoval(() -> { assertThat(mUserManager.removeUserWhenPossible(user1.getUserHandle(), /* overrideDevicePolicy= */ true)) .isEqualTo(UserManager.REMOVE_RESULT_REMOVED); waitForUserRemovalLocked(user1.id); } }, user1.id); // wait for user removal } finally { mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_USER, /* value= */ false, asHandle(currentUser)); Loading Loading @@ -477,13 +456,12 @@ public final class UserManagerTest { assertThat(hasUser(user1.id)).isTrue(); assertThat(getUser(user1.id).isEphemeral()).isTrue(); runThenWaitForUserRemoval(() -> { // Switch back to the starting user. switchUser(startUser); // User will be removed once switch is complete }, user1.id); // wait for user removal // User is removed once switch is complete synchronized (mUserRemoveLock) { waitForUserRemovalLocked(user1.id); } assertThat(hasUser(user1.id)).isFalse(); } Loading @@ -495,19 +473,19 @@ public final class UserManagerTest { // Switch to the user just created. switchUser(testUser.id); runThenWaitForUserRemoval(() -> { switchUserThenRun(startUser, () -> { // While the user switch is happening, call removeUserWhenPossible for the current user. assertThat(mUserManager.removeUserWhenPossible(testUser.getUserHandle(), false)) // While the switch is happening, call removeUserWhenPossible for the current user. assertThat(mUserManager.removeUserWhenPossible(testUser.getUserHandle(), /* overrideDevicePolicy= */ false)) .isEqualTo(UserManager.REMOVE_RESULT_DEFERRED); assertThat(hasUser(testUser.id)).isTrue(); assertThat(getUser(testUser.id).isEphemeral()).isTrue(); }); }); // wait for user switch - startUser // User will be removed once switch is complete }, testUser.id); // wait for user removal // User is removed once switch is complete synchronized (mUserRemoveLock) { waitForUserRemovalLocked(testUser.id); } assertThat(hasUser(testUser.id)).isFalse(); } Loading @@ -519,20 +497,20 @@ public final class UserManagerTest { switchUserThenRun(testUser.id, () -> { // While the user switch is happening, call removeUserWhenPossible for the target user. assertThat(mUserManager.removeUserWhenPossible(testUser.getUserHandle(), false)) assertThat(mUserManager.removeUserWhenPossible(testUser.getUserHandle(), /* overrideDevicePolicy= */ false)) .isEqualTo(UserManager.REMOVE_RESULT_DEFERRED); assertThat(hasUser(testUser.id)).isTrue(); assertThat(getUser(testUser.id).isEphemeral()).isTrue(); }); }); // wait for user switch - testUser runThenWaitForUserRemoval(() -> { // Switch back to the starting user. switchUser(startUser); // User will be removed once switch is complete }, testUser.id); // wait for user removal // User is removed once switch is complete synchronized (mUserRemoveLock) { waitForUserRemovalLocked(testUser.id); } assertThat(hasUser(testUser.id)).isFalse(); } Loading @@ -540,12 +518,12 @@ public final class UserManagerTest { @Test public void testRemoveUserWhenPossible_nonCurrentUserRemoved() throws Exception { final UserInfo user1 = createUser("User 1", /* flags= */ 0); synchronized (mUserRemoveLock) { runThenWaitForUserRemoval(() -> { assertThat(mUserManager.removeUserWhenPossible(user1.getUserHandle(), /* overrideDevicePolicy= */ false)) .isEqualTo(UserManager.REMOVE_RESULT_REMOVED); waitForUserRemovalLocked(user1.id); } }, user1.id); // wait for user removal assertThat(hasUser(user1.id)).isFalse(); } Loading @@ -562,12 +540,12 @@ public final class UserManagerTest { final UserInfo workProfileUser = createProfileForUser("Work Profile user", UserManager.USER_TYPE_PROFILE_MANAGED, parentUser.id); synchronized (mUserRemoveLock) { runThenWaitForUserRemoval(() -> { assertThat(mUserManager.removeUserWhenPossible(parentUser.getUserHandle(), /* overrideDevicePolicy= */ false)) .isEqualTo(UserManager.REMOVE_RESULT_REMOVED); waitForUserRemovalLocked(parentUser.id); } }, parentUser.id); // wait for user removal assertThat(hasUser(parentUser.id)).isFalse(); assertThat(hasUser(cloneProfileUser.id)).isFalse(); Loading Loading @@ -1298,9 +1276,7 @@ public final class UserManagerTest { UserInfo user = mUserManager.createUser(userName, 0); if (user != null) { created.incrementAndGet(); synchronized (mUserRemoveLock) { usersToRemove.add(user.id); } mUsersToRemove.add(user.id); } }); } Loading Loading @@ -1462,40 +1438,41 @@ public final class UserManagerTest { }, () -> fail("Could not complete switching to user " + userId)); } private void removeUser(UserHandle user) { synchronized (mUserRemoveLock) { mUserManager.removeUser(user); waitForUserRemovalLocked(user.getIdentifier()); } private void removeUser(UserHandle userHandle) { runThenWaitForUserRemoval( () -> mUserManager.removeUser(userHandle), userHandle == null ? UserHandle.USER_NULL : userHandle.getIdentifier() ); } private void removeUser(int userId) { synchronized (mUserRemoveLock) { mUserManager.removeUser(userId); waitForUserRemovalLocked(userId); } runThenWaitForUserRemoval( () -> mUserManager.removeUser(userId), userId ); } @GuardedBy("mUserRemoveLock") private void waitForUserRemovalLocked(int userId) { long time = System.currentTimeMillis(); while (mUserManager.getUserInfo(userId) != null) { try { mUserRemoveLock.wait(REMOVE_CHECK_INTERVAL_MILLIS); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); return; } if (System.currentTimeMillis() - time > REMOVE_TIMEOUT_MILLIS) { fail("Timeout waiting for removeUser. userId = " + userId); } private void runThenWaitForUserRemoval(Runnable runnable, int userIdToWaitUntilDeleted) { Function<Intent, Boolean> checker = intent -> { UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER, UserHandle.class); return userHandle != null && userHandle.getIdentifier() == userIdToWaitUntilDeleted; }; BlockingBroadcastReceiver blockingBroadcastReceiver = BlockingBroadcastReceiver.create( mContext, Intent.ACTION_USER_REMOVED, checker); blockingBroadcastReceiver.register(); try (blockingBroadcastReceiver) { runnable.run(); } mUsersToRemove.remove(userIdToWaitUntilDeleted); } private UserInfo createUser(String name, int flags) { UserInfo user = mUserManager.createUser(name, flags); if (user != null) { usersToRemove.add(user.id); mUsersToRemove.add(user.id); } return user; } Loading @@ -1503,7 +1480,7 @@ public final class UserManagerTest { private UserInfo createUser(String name, String userType, int flags) { UserInfo user = mUserManager.createUser(name, userType, flags); if (user != null) { usersToRemove.add(user.id); mUsersToRemove.add(user.id); } return user; } Loading @@ -1517,7 +1494,7 @@ public final class UserManagerTest { UserInfo profile = mUserManager.createProfileForUser( name, userType, 0, userHandle, disallowedPackages); if (profile != null) { usersToRemove.add(profile.id); mUsersToRemove.add(profile.id); } return profile; } Loading @@ -1527,7 +1504,7 @@ public final class UserManagerTest { UserInfo profile = mUserManager.createProfileForUserEvenWhenDisallowed( name, userType, 0, userHandle, null); if (profile != null) { usersToRemove.add(profile.id); mUsersToRemove.add(profile.id); } return profile; } Loading @@ -1535,7 +1512,7 @@ public final class UserManagerTest { private UserInfo createRestrictedProfile(String name) { UserInfo profile = mUserManager.createRestrictedProfile(name); if (profile != null) { usersToRemove.add(profile.id); mUsersToRemove.add(profile.id); } return profile; } Loading Loading
services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +72 −95 Original line number Diff line number Diff line Loading @@ -26,10 +26,8 @@ import static org.testng.Assert.assertThrows; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.pm.UserProperties; Loading @@ -41,6 +39,7 @@ import android.platform.test.annotations.Postsubmit; import android.provider.Settings; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; import android.util.ArraySet; import android.util.Slog; import androidx.annotation.Nullable; Loading @@ -48,6 +47,8 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.compatibility.common.util.BlockingBroadcastReceiver; import com.google.common.collect.ImmutableList; import com.google.common.collect.Range; Loading @@ -56,16 +57,14 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; import javax.annotation.concurrent.GuardedBy; /** Test {@link UserManager} functionality. */ @Postsubmit @RunWith(AndroidJUnit4.class) Loading @@ -73,8 +72,6 @@ public final class UserManagerTest { // Taken from UserManagerService private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // 30 years private static final int REMOVE_CHECK_INTERVAL_MILLIS = 500; // 0.5 seconds private static final int REMOVE_TIMEOUT_MILLIS = 60 * 1000; // 60 seconds private static final int SWITCH_USER_TIMEOUT_SECONDS = 40; // 40 seconds // Packages which are used during tests. Loading @@ -86,12 +83,10 @@ public final class UserManagerTest { private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); private final Object mUserRemoveLock = new Object(); private UserManager mUserManager = null; private ActivityManager mActivityManager; private PackageManager mPackageManager; private List<Integer> usersToRemove; private ArraySet<Integer> mUsersToRemove; private UserSwitchWaiter mUserSwitchWaiter; @Before Loading @@ -101,30 +96,16 @@ public final class UserManagerTest { mPackageManager = mContext.getPackageManager(); mUserSwitchWaiter = new UserSwitchWaiter(TAG, SWITCH_USER_TIMEOUT_SECONDS); IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED); mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { case Intent.ACTION_USER_REMOVED: synchronized (mUserRemoveLock) { mUserRemoveLock.notifyAll(); } break; } } }, filter); mUsersToRemove = new ArraySet<>(); removeExistingUsers(); usersToRemove = new ArrayList<>(); } @After public void tearDown() throws Exception { mUserSwitchWaiter.close(); for (Integer userId : usersToRemove) { removeUser(userId); } // Making a copy of mUsersToRemove to avoid ConcurrentModificationException mUsersToRemove.stream().toList().forEach(this::removeUser); } private void removeExistingUsers() { Loading Loading @@ -406,13 +387,11 @@ public final class UserManagerTest { mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_USER, /* value= */ true, asHandle(currentUser)); try { synchronized (mUserRemoveLock) { runThenWaitForUserRemoval(() -> { assertThat(mUserManager.removeUserWhenPossible(user1.getUserHandle(), /* overrideDevicePolicy= */ true)) .isEqualTo(UserManager.REMOVE_RESULT_REMOVED); waitForUserRemovalLocked(user1.id); } }, user1.id); // wait for user removal } finally { mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_USER, /* value= */ false, asHandle(currentUser)); Loading Loading @@ -477,13 +456,12 @@ public final class UserManagerTest { assertThat(hasUser(user1.id)).isTrue(); assertThat(getUser(user1.id).isEphemeral()).isTrue(); runThenWaitForUserRemoval(() -> { // Switch back to the starting user. switchUser(startUser); // User will be removed once switch is complete }, user1.id); // wait for user removal // User is removed once switch is complete synchronized (mUserRemoveLock) { waitForUserRemovalLocked(user1.id); } assertThat(hasUser(user1.id)).isFalse(); } Loading @@ -495,19 +473,19 @@ public final class UserManagerTest { // Switch to the user just created. switchUser(testUser.id); runThenWaitForUserRemoval(() -> { switchUserThenRun(startUser, () -> { // While the user switch is happening, call removeUserWhenPossible for the current user. assertThat(mUserManager.removeUserWhenPossible(testUser.getUserHandle(), false)) // While the switch is happening, call removeUserWhenPossible for the current user. assertThat(mUserManager.removeUserWhenPossible(testUser.getUserHandle(), /* overrideDevicePolicy= */ false)) .isEqualTo(UserManager.REMOVE_RESULT_DEFERRED); assertThat(hasUser(testUser.id)).isTrue(); assertThat(getUser(testUser.id).isEphemeral()).isTrue(); }); }); // wait for user switch - startUser // User will be removed once switch is complete }, testUser.id); // wait for user removal // User is removed once switch is complete synchronized (mUserRemoveLock) { waitForUserRemovalLocked(testUser.id); } assertThat(hasUser(testUser.id)).isFalse(); } Loading @@ -519,20 +497,20 @@ public final class UserManagerTest { switchUserThenRun(testUser.id, () -> { // While the user switch is happening, call removeUserWhenPossible for the target user. assertThat(mUserManager.removeUserWhenPossible(testUser.getUserHandle(), false)) assertThat(mUserManager.removeUserWhenPossible(testUser.getUserHandle(), /* overrideDevicePolicy= */ false)) .isEqualTo(UserManager.REMOVE_RESULT_DEFERRED); assertThat(hasUser(testUser.id)).isTrue(); assertThat(getUser(testUser.id).isEphemeral()).isTrue(); }); }); // wait for user switch - testUser runThenWaitForUserRemoval(() -> { // Switch back to the starting user. switchUser(startUser); // User will be removed once switch is complete }, testUser.id); // wait for user removal // User is removed once switch is complete synchronized (mUserRemoveLock) { waitForUserRemovalLocked(testUser.id); } assertThat(hasUser(testUser.id)).isFalse(); } Loading @@ -540,12 +518,12 @@ public final class UserManagerTest { @Test public void testRemoveUserWhenPossible_nonCurrentUserRemoved() throws Exception { final UserInfo user1 = createUser("User 1", /* flags= */ 0); synchronized (mUserRemoveLock) { runThenWaitForUserRemoval(() -> { assertThat(mUserManager.removeUserWhenPossible(user1.getUserHandle(), /* overrideDevicePolicy= */ false)) .isEqualTo(UserManager.REMOVE_RESULT_REMOVED); waitForUserRemovalLocked(user1.id); } }, user1.id); // wait for user removal assertThat(hasUser(user1.id)).isFalse(); } Loading @@ -562,12 +540,12 @@ public final class UserManagerTest { final UserInfo workProfileUser = createProfileForUser("Work Profile user", UserManager.USER_TYPE_PROFILE_MANAGED, parentUser.id); synchronized (mUserRemoveLock) { runThenWaitForUserRemoval(() -> { assertThat(mUserManager.removeUserWhenPossible(parentUser.getUserHandle(), /* overrideDevicePolicy= */ false)) .isEqualTo(UserManager.REMOVE_RESULT_REMOVED); waitForUserRemovalLocked(parentUser.id); } }, parentUser.id); // wait for user removal assertThat(hasUser(parentUser.id)).isFalse(); assertThat(hasUser(cloneProfileUser.id)).isFalse(); Loading Loading @@ -1298,9 +1276,7 @@ public final class UserManagerTest { UserInfo user = mUserManager.createUser(userName, 0); if (user != null) { created.incrementAndGet(); synchronized (mUserRemoveLock) { usersToRemove.add(user.id); } mUsersToRemove.add(user.id); } }); } Loading Loading @@ -1462,40 +1438,41 @@ public final class UserManagerTest { }, () -> fail("Could not complete switching to user " + userId)); } private void removeUser(UserHandle user) { synchronized (mUserRemoveLock) { mUserManager.removeUser(user); waitForUserRemovalLocked(user.getIdentifier()); } private void removeUser(UserHandle userHandle) { runThenWaitForUserRemoval( () -> mUserManager.removeUser(userHandle), userHandle == null ? UserHandle.USER_NULL : userHandle.getIdentifier() ); } private void removeUser(int userId) { synchronized (mUserRemoveLock) { mUserManager.removeUser(userId); waitForUserRemovalLocked(userId); } runThenWaitForUserRemoval( () -> mUserManager.removeUser(userId), userId ); } @GuardedBy("mUserRemoveLock") private void waitForUserRemovalLocked(int userId) { long time = System.currentTimeMillis(); while (mUserManager.getUserInfo(userId) != null) { try { mUserRemoveLock.wait(REMOVE_CHECK_INTERVAL_MILLIS); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); return; } if (System.currentTimeMillis() - time > REMOVE_TIMEOUT_MILLIS) { fail("Timeout waiting for removeUser. userId = " + userId); } private void runThenWaitForUserRemoval(Runnable runnable, int userIdToWaitUntilDeleted) { Function<Intent, Boolean> checker = intent -> { UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER, UserHandle.class); return userHandle != null && userHandle.getIdentifier() == userIdToWaitUntilDeleted; }; BlockingBroadcastReceiver blockingBroadcastReceiver = BlockingBroadcastReceiver.create( mContext, Intent.ACTION_USER_REMOVED, checker); blockingBroadcastReceiver.register(); try (blockingBroadcastReceiver) { runnable.run(); } mUsersToRemove.remove(userIdToWaitUntilDeleted); } private UserInfo createUser(String name, int flags) { UserInfo user = mUserManager.createUser(name, flags); if (user != null) { usersToRemove.add(user.id); mUsersToRemove.add(user.id); } return user; } Loading @@ -1503,7 +1480,7 @@ public final class UserManagerTest { private UserInfo createUser(String name, String userType, int flags) { UserInfo user = mUserManager.createUser(name, userType, flags); if (user != null) { usersToRemove.add(user.id); mUsersToRemove.add(user.id); } return user; } Loading @@ -1517,7 +1494,7 @@ public final class UserManagerTest { UserInfo profile = mUserManager.createProfileForUser( name, userType, 0, userHandle, disallowedPackages); if (profile != null) { usersToRemove.add(profile.id); mUsersToRemove.add(profile.id); } return profile; } Loading @@ -1527,7 +1504,7 @@ public final class UserManagerTest { UserInfo profile = mUserManager.createProfileForUserEvenWhenDisallowed( name, userType, 0, userHandle, null); if (profile != null) { usersToRemove.add(profile.id); mUsersToRemove.add(profile.id); } return profile; } Loading @@ -1535,7 +1512,7 @@ public final class UserManagerTest { private UserInfo createRestrictedProfile(String name) { UserInfo profile = mUserManager.createRestrictedProfile(name); if (profile != null) { usersToRemove.add(profile.id); mUsersToRemove.add(profile.id); } return profile; } Loading