summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java29
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java37
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java524
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java188
4 files changed, 618 insertions, 160 deletions
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 2a8c88ec05cd..ef8e94e3c739 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -630,7 +630,7 @@ public class UserManagerService extends IUserManager.Stub {
/**
* Set on on devices that support background users (key) running on secondary displays (value).
*/
- // TODO(b/239982558): move such logic to a different class (like UserDisplayAssigner)
+ // TODO(b/244644281): move such logic to a different class (like UserDisplayAssigner)
@Nullable
@GuardedBy("mUsersOnSecondaryDisplays")
private final SparseIntArray mUsersOnSecondaryDisplays;
@@ -710,7 +710,8 @@ public class UserManagerService extends IUserManager.Stub {
@VisibleForTesting
UserManagerService(Context context) {
this(context, /* pm= */ null, /* userDataPreparer= */ null,
- /* packagesLock= */ new Object(), context.getCacheDir(), /* users= */ null);
+ /* packagesLock= */ new Object(), context.getCacheDir(), /* users= */ null,
+ /* usersOnSecondaryDisplays= */ null);
}
/**
@@ -721,13 +722,13 @@ public class UserManagerService extends IUserManager.Stub {
UserManagerService(Context context, PackageManagerService pm, UserDataPreparer userDataPreparer,
Object packagesLock) {
this(context, pm, userDataPreparer, packagesLock, Environment.getDataDirectory(),
- /* users= */ null);
+ /* users= */ null, /* usersOnSecondaryDisplays= */ null);
}
@VisibleForTesting
UserManagerService(Context context, PackageManagerService pm,
UserDataPreparer userDataPreparer, Object packagesLock, File dataDir,
- SparseArray<UserData> users) {
+ SparseArray<UserData> users, @Nullable SparseIntArray usersOnSecondaryDisplays) {
mContext = context;
mPm = pm;
mPackagesLock = packagesLock;
@@ -758,7 +759,13 @@ public class UserManagerService extends IUserManager.Stub {
mUser0Allocations = DBG_ALLOCATION ? new AtomicInteger() : null;
emulateSystemUserModeIfNeeded();
mUsersOnSecondaryDisplaysEnabled = UserManager.isUsersOnSecondaryDisplaysEnabled();
- mUsersOnSecondaryDisplays = mUsersOnSecondaryDisplaysEnabled ? new SparseIntArray() : null;
+ if (mUsersOnSecondaryDisplaysEnabled) {
+ mUsersOnSecondaryDisplays = usersOnSecondaryDisplays == null
+ ? new SparseIntArray() // default behavior
+ : usersOnSecondaryDisplays; // passed by unit test
+ } else {
+ mUsersOnSecondaryDisplays = null;
+ }
}
void systemReady() {
@@ -1720,6 +1727,11 @@ public class UserManagerService extends IUserManager.Stub {
return userId == getCurrentUserId();
}
+ @VisibleForTesting
+ boolean isUsersOnSecondaryDisplaysEnabled() {
+ return mUsersOnSecondaryDisplaysEnabled;
+ }
+
@Override
public boolean isUserVisible(@UserIdInt int userId) {
int callingUserId = UserHandle.getCallingUserId();
@@ -1733,7 +1745,8 @@ public class UserManagerService extends IUserManager.Stub {
return isUserVisibleUnchecked(userId);
}
- private boolean isUserVisibleUnchecked(@UserIdInt int userId) {
+ @VisibleForTesting
+ boolean isUserVisibleUnchecked(@UserIdInt int userId) {
// First check current foreground user and their profiles (on main display)
if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
return true;
@@ -1750,8 +1763,8 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- // TODO(b/239982558): add unit test
- private int getDisplayAssignedToUser(@UserIdInt int userId) {
+ @VisibleForTesting
+ int getDisplayAssignedToUser(@UserIdInt int userId) {
if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
return Display.DEFAULT_DISPLAY;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java
new file mode 100644
index 000000000000..7d7b70ca19f6
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm;
+
+/**
+ * Run as {@code atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerInternalTest}
+ */
+public final class UserManagerInternalTest extends UserManagerServiceOrInternalTestCase {
+
+ @Override
+ protected boolean isUserVisible(int userId) {
+ return mUmi.isUserVisible(userId);
+ }
+
+ @Override
+ protected boolean isUserVisibleOnDisplay(int userId, int displayId) {
+ return mUmi.isUserVisible(userId, displayId);
+ }
+
+ @Override
+ protected int getDisplayAssignedToUser(int userId) {
+ return mUmi.getDisplayAssignedToUser(userId);
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
new file mode 100644
index 000000000000..e021e767e7c8
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm;
+
+import static android.os.UserHandle.USER_NULL;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+
+import androidx.test.annotation.UiThreadTest;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
+import com.android.server.ExtendedMockitoTestCase;
+import com.android.server.LocalServices;
+import com.android.server.am.UserState;
+import com.android.server.pm.UserManagerService.UserData;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+/**
+ * Base class for {@link UserManagerInternalTest} and {@link UserManagerInternalTest}.
+ *
+ * <p>{@link UserManagerService} and its {@link UserManagerInternal} implementation have a
+ * "symbiotic relationship - some methods of the former simply call the latter and vice versa.
+ *
+ * <p>Ideally, only one of them should have the logic, but since that's not the case, this class
+ * provices the infra to make it easier to test both (which in turn would make it easier / safer to
+ * refactor their logic later).
+ */
+abstract class UserManagerServiceOrInternalTestCase extends ExtendedMockitoTestCase {
+
+ private static final String TAG = UserManagerServiceOrInternalTestCase.class.getSimpleName();
+
+ /**
+ * Id for a simple user (that doesn't have profiles).
+ */
+ protected static final int USER_ID = 600;
+
+ /**
+ * Id for another simple user.
+ */
+ protected static final int OTHER_USER_ID = 666;
+
+ /**
+ * Id for a user that has one profile (whose id is {@link #PROFILE_USER_ID}.
+ *
+ * <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
+ */
+ protected static final int PARENT_USER_ID = 642;
+
+ /**
+ * Id for a profile whose parent is {@link #PARENTUSER_ID}.
+ *
+ * <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
+ */
+ protected static final int PROFILE_USER_ID = 643;
+
+ /**
+ * Id of a secondary display (i.e, not {@link android.view.Display.DEFAULT_DISPLAY}).
+ */
+ private static final int SECONDARY_DISPLAY_ID = 42;
+
+ private final Object mPackagesLock = new Object();
+ private final Context mRealContext = androidx.test.InstrumentationRegistry.getInstrumentation()
+ .getTargetContext();
+ private final SparseArray<UserData> mUsers = new SparseArray<>();
+
+ // TODO(b/244644281): manipulating mUsersOnSecondaryDisplays directly leaks implementation
+ // details into the unit test, but it's fine for now - in the long term, this logic should be
+ // refactored into a proper UserDisplayAssignment class.
+ private final SparseIntArray mUsersOnSecondaryDisplays = new SparseIntArray();
+
+ private Context mSpiedContext;
+ private UserManagerService mStandardUms;
+ private UserManagerService mMumdUms;
+ private UserManagerInternal mStandardUmi;
+ private UserManagerInternal mMumdUmi;
+
+ private @Mock PackageManagerService mMockPms;
+ private @Mock UserDataPreparer mMockUserDataPreparer;
+ private @Mock ActivityManagerInternal mActivityManagerInternal;
+
+ /**
+ * Reference to the {@link UserManagerService} being tested.
+ *
+ * <p>By default, such service doesn't support {@code MUMD} (Multiple Users on Multiple
+ * Displays), but that can be changed by calling {@link #enableUsersOnSecondaryDisplays()}.
+ */
+ protected UserManagerService mUms;
+
+ /**
+ * Reference to the {@link UserManagerInternal} being tested.
+ *
+ * <p>By default, such service doesn't support {@code MUMD} (Multiple Users on Multiple
+ * Displays), but that can be changed by calling {@link #enableUsersOnSecondaryDisplays()}.
+ */
+ protected UserManagerInternal mUmi;
+
+ @Override
+ protected void initializeSession(StaticMockitoSessionBuilder builder) {
+ builder
+ .spyStatic(UserManager.class)
+ .spyStatic(LocalServices.class);
+ }
+
+ @Before
+ @UiThreadTest // Needed to initialize main handler
+ public final void setFixtures() {
+ mSpiedContext = spy(mRealContext);
+
+ // Called when WatchedUserStates is constructed
+ doNothing().when(() -> UserManager.invalidateIsUserUnlockedCache());
+
+ // Need to set both UserManagerService instances here, as they need to be run in the
+ // UiThread
+
+ // mMumdUms / mMumdUmi
+ mockIsUsersOnSecondaryDisplaysEnabled(/* usersOnSecondaryDisplaysEnabled= */ true);
+ mMumdUms = new UserManagerService(mSpiedContext, mMockPms, mMockUserDataPreparer,
+ mPackagesLock, mRealContext.getDataDir(), mUsers, mUsersOnSecondaryDisplays);
+ assertWithMessage("UserManagerService.isUsersOnSecondaryDisplaysEnabled()")
+ .that(mMumdUms.isUsersOnSecondaryDisplaysEnabled())
+ .isTrue();
+ mMumdUmi = LocalServices.getService(UserManagerInternal.class);
+ assertWithMessage("LocalServices.getService(UserManagerInternal.class)").that(mMumdUmi)
+ .isNotNull();
+ resetUserManagerInternal();
+
+ // mStandardUms / mStandardUmi
+ mockIsUsersOnSecondaryDisplaysEnabled(/* usersOnSecondaryDisplaysEnabled= */ false);
+ mStandardUms = new UserManagerService(mSpiedContext, mMockPms, mMockUserDataPreparer,
+ mPackagesLock, mRealContext.getDataDir(), mUsers, mUsersOnSecondaryDisplays);
+ assertWithMessage("UserManagerService.isUsersOnSecondaryDisplaysEnabled()")
+ .that(mStandardUms.isUsersOnSecondaryDisplaysEnabled())
+ .isFalse();
+ mStandardUmi = LocalServices.getService(UserManagerInternal.class);
+ assertWithMessage("LocalServices.getService(UserManagerInternal.class)").that(mStandardUmi)
+ .isNotNull();
+ setServiceFixtures(/*usersOnSecondaryDisplaysEnabled= */ false);
+ }
+
+ @After
+ public final void resetUserManagerInternal() {
+ // LocalServices follows the "Highlander rule" - There can be only one!
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Methods whose UMS implementation calls UMI or vice-versa - they're tested in this class, //
+ // but the subclass must provide the proper implementation //
+ //////////////////////////////////////////////////////////////////////////////////////////////
+
+ protected abstract boolean isUserVisible(int userId);
+ protected abstract boolean isUserVisibleOnDisplay(int userId, int displayId);
+ protected abstract int getDisplayAssignedToUser(int userId);
+
+ /////////////////////////////////
+ // Tests for the above methods //
+ /////////////////////////////////
+
+ @Test
+ public void testIsUserVisible_invalidUser() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("isUserVisible(%s)", USER_NULL).that(isUserVisible(USER_NULL)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisible_currentUser() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("isUserVisible(%s)", USER_ID).that(isUserVisible(USER_ID)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisible_nonCurrentUser() {
+ mockCurrentUser(OTHER_USER_ID);
+
+ assertWithMessage("isUserVisible(%s)", USER_ID).that(isUserVisible(USER_ID)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisible_startedProfileOfcurrentUser() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ startDefaultProfile();
+ setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+ assertWithMessage("isUserVisible(%s)", PROFILE_USER_ID).that(isUserVisible(PROFILE_USER_ID))
+ .isTrue();
+ }
+
+ @Test
+ public void testIsUserVisible_stoppedProfileOfcurrentUser() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ stopDefaultProfile();
+
+ assertWithMessage("isUserVisible(%s)", PROFILE_USER_ID).that(isUserVisible(PROFILE_USER_ID))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsUserVisible_bgUserOnSecondaryDisplay() {
+ enableUsersOnSecondaryDisplays();
+ mockCurrentUser(OTHER_USER_ID);
+ assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+ assertWithMessage("isUserVisible(%s)", USER_ID).that(isUserVisible(USER_ID)).isTrue();
+ }
+
+ // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as
+ // isUserVisible() for bg users relies only on the user / display assignments
+
+ @Test
+ public void testIsUserVisibleOnDisplay_invalidUser() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_NULL, DEFAULT_DISPLAY)
+ .that(isUserVisibleOnDisplay(USER_NULL, DEFAULT_DISPLAY)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_currentUserInvalidDisplay() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, INVALID_DISPLAY)
+ .that(isUserVisibleOnDisplay(USER_ID, INVALID_DISPLAY)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_currentUserDefaultDisplay() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, DEFAULT_DISPLAY)
+ .that(isUserVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_currentUserSecondaryDisplay() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID)
+ .that(isUserVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_nonCurrentUserDefaultDisplay() {
+ mockCurrentUser(OTHER_USER_ID);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, DEFAULT_DISPLAY)
+ .that(isUserVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_startedProfileOfcurrentUserInvalidDisplay() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ startDefaultProfile();
+ setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, INVALID_DISPLAY)
+ .that(isUserVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_stoppedProfileOfcurrentUserInvalidDisplay() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ stopDefaultProfile();
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, INVALID_DISPLAY)
+ .that(isUserVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_startedProfileOfcurrentUserDefaultDisplay() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ startDefaultProfile();
+ setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, DEFAULT_DISPLAY)
+ .that(isUserVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_stoppedProfileOfcurrentUserDefaultDisplay() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ stopDefaultProfile();
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, DEFAULT_DISPLAY)
+ .that(isUserVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_startedProfileOfcurrentUserSecondaryDisplay() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ startDefaultProfile();
+ setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID)
+ .that(isUserVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_stoppedProfileOfcurrentUserSecondaryDisplay() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ stopDefaultProfile();
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID)
+ .that(isUserVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_bgUserOnSecondaryDisplay() {
+ enableUsersOnSecondaryDisplays();
+ mockCurrentUser(OTHER_USER_ID);
+ assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID)
+ .that(isUserVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID)).isTrue();
+ }
+
+ // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as
+ // isUserVisibleOnDisplay() for bg users relies only on the user / display assignments
+
+ @Test
+ public void testGetDisplayAssignedToUser_invalidUser() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("getDisplayAssignedToUser(%s)", USER_NULL)
+ .that(getDisplayAssignedToUser(USER_NULL)).isEqualTo(INVALID_DISPLAY);
+ }
+
+ @Test
+ public void testGetDisplayAssignedToUser_currentUser() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("getDisplayAssignedToUser(%s)", USER_ID)
+ .that(getDisplayAssignedToUser(USER_ID)).isEqualTo(DEFAULT_DISPLAY);
+ }
+
+ @Test
+ public void testGetDisplayAssignedToUser_nonCurrentUser() {
+ mockCurrentUser(OTHER_USER_ID);
+
+ assertWithMessage("getDisplayAssignedToUser(%s)", USER_ID)
+ .that(getDisplayAssignedToUser(USER_ID)).isEqualTo(INVALID_DISPLAY);
+ }
+
+ @Test
+ public void testGetDisplayAssignedToUser_startedProfileOfcurrentUser() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ startDefaultProfile();
+ setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+ assertWithMessage("getDisplayAssignedToUser(%s)", PROFILE_USER_ID)
+ .that(getDisplayAssignedToUser(PROFILE_USER_ID)).isEqualTo(DEFAULT_DISPLAY);
+ }
+
+ @Test
+ public void testGetDisplayAssignedToUser_stoppedProfileOfcurrentUser() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ stopDefaultProfile();
+
+ assertWithMessage("getDisplayAssignedToUser(%s)", PROFILE_USER_ID)
+ .that(getDisplayAssignedToUser(PROFILE_USER_ID)).isEqualTo(INVALID_DISPLAY);
+ }
+
+ @Test
+ public void testGetDisplayAssignedToUser_bgUserOnSecondaryDisplay() {
+ enableUsersOnSecondaryDisplays();
+ mockCurrentUser(OTHER_USER_ID);
+ assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+ assertWithMessage("getDisplayAssignedToUser(%s)", USER_ID)
+ .that(getDisplayAssignedToUser(USER_ID)).isEqualTo(SECONDARY_DISPLAY_ID);
+ }
+
+ // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as
+ // getDisplayAssignedToUser() for bg users relies only on the user / display assignments
+
+ ///////////////////////////////////////////
+ // Helper methods exposed to sub-classes //
+ ///////////////////////////////////////////
+
+ /**
+ * Change test fixtures to use a version that supports {@code MUMD} (Multiple Users on Multiple
+ * Displays).
+ */
+ protected void enableUsersOnSecondaryDisplays() {
+ setServiceFixtures(/* usersOnSecondaryDisplaysEnabled= */ true);
+ }
+
+ protected void mockCurrentUser(@UserIdInt int userId) {
+ mockGetLocalService(ActivityManagerInternal.class, mActivityManagerInternal);
+
+ when(mActivityManagerInternal.getCurrentUserId()).thenReturn(userId);
+ }
+
+ protected <T> void mockGetLocalService(Class<T> serviceClass, T service) {
+ doReturn(service).when(() -> LocalServices.getService(serviceClass));
+ }
+
+ protected void addDefaultProfileAndParent() {
+ addUser(PARENT_USER_ID);
+ addProfile(PROFILE_USER_ID, PARENT_USER_ID);
+ }
+
+ protected void addProfile(@UserIdInt int profileId, @UserIdInt int parentId) {
+ TestUserData profileData = new TestUserData(profileId);
+ profileData.info.flags = UserInfo.FLAG_PROFILE;
+ profileData.info.profileGroupId = parentId;
+
+ addUserData(profileData);
+ }
+
+ protected void addUser(@UserIdInt int userId) {
+ TestUserData userData = new TestUserData(userId);
+
+ addUserData(userData);
+ }
+
+ protected void startDefaultProfile() {
+ setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+ }
+
+ protected void stopDefaultProfile() {
+ // TODO(b/244798930): should set it to STATE_STOPPING or STATE_SHUTDOWN instead
+ removeUserState(PROFILE_USER_ID);
+ }
+
+ // NOTE: should only called by tests that indirectly needs to check user assignments (like
+ // isUserVisible), not by tests for the user assignment methods per se.
+ protected void assignUserToDisplay(@UserIdInt int userId, int displayId) {
+ mUsersOnSecondaryDisplays.put(userId, displayId);
+ }
+
+ ///////////////////
+ // Private infra //
+ ///////////////////
+
+ private void setServiceFixtures(boolean usersOnSecondaryDisplaysEnabled) {
+ Log.d(TAG, "Setting fixtures for usersOnSecondaryDisplaysEnabled="
+ + usersOnSecondaryDisplaysEnabled);
+ if (usersOnSecondaryDisplaysEnabled) {
+ mUms = mMumdUms;
+ mUmi = mMumdUmi;
+ } else {
+ mUms = mStandardUms;
+ mUmi = mStandardUmi;
+ }
+ }
+
+ private void mockIsUsersOnSecondaryDisplaysEnabled(boolean enabled) {
+ Log.d(TAG, "Mocking UserManager.isUsersOnSecondaryDisplaysEnabled() to return " + enabled);
+ doReturn(enabled).when(() -> UserManager.isUsersOnSecondaryDisplaysEnabled());
+ }
+
+ private void addUserData(TestUserData userData) {
+ Log.d(TAG, "Adding " + userData);
+ mUsers.put(userData.info.id, userData);
+ }
+
+ private void setUserState(@UserIdInt int userId, int userState) {
+ mUmi.setUserState(userId, userState);
+ }
+
+ private void removeUserState(@UserIdInt int userId) {
+ mUmi.removeUserState(userId);
+ }
+
+ private static final class TestUserData extends UserData {
+
+ @SuppressWarnings("deprecation")
+ TestUserData(@UserIdInt int userId) {
+ info = new UserInfo();
+ info.id = userId;
+ }
+
+ @Override
+ public String toString() {
+ return "TestUserData[" + info.toFullString() + "]";
+ }
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 64931116bd01..b335a34f6f14 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -15,87 +15,20 @@
*/
package com.android.server.pm;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-
import static com.google.common.truth.Truth.assertWithMessage;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
-import android.content.Context;
-import android.content.pm.UserInfo;
import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-import android.util.SparseArray;
-
-import androidx.test.annotation.UiThreadTest;
-import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
-import com.android.server.ExtendedMockitoTestCase;
-import com.android.server.LocalServices;
-import com.android.server.am.UserState;
-import com.android.server.pm.UserManagerService.UserData;
-
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
-import org.mockito.Mock;
/**
* Run as {@code atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerServiceTest}
*/
-public final class UserManagerServiceTest extends ExtendedMockitoTestCase {
-
- private static final String TAG = UserManagerServiceTest.class.getSimpleName();
-
- private final Object mPackagesLock = new Object();
- private final Context mRealContext = androidx.test.InstrumentationRegistry.getInstrumentation()
- .getTargetContext();
- private Context mSpiedContext;
-
- private @Mock PackageManagerService mMockPms;
- private @Mock UserDataPreparer mMockUserDataPreparer;
- private @Mock ActivityManagerInternal mActivityManagerInternal;
-
- private final SparseArray<UserData> mUsers = new SparseArray<>();
- private UserManagerService mUms;
- private UserManagerInternal mUmi;
-
- @Override
- protected void initializeSession(StaticMockitoSessionBuilder builder) {
- builder
- .spyStatic(UserManager.class)
- .spyStatic(LocalServices.class);
- }
-
- @Before
- @UiThreadTest // Needed to initialize main handler
- public void setFixtures() {
- mSpiedContext = spy(mRealContext);
-
- // Called when WatchedUserStates is constructed
- doNothing().when(() -> UserManager.invalidateIsUserUnlockedCache());
-
- mUms = new UserManagerService(mSpiedContext, mMockPms, mMockUserDataPreparer,
- mPackagesLock, mRealContext.getDataDir(), mUsers);
- mUmi = LocalServices.getService(UserManagerInternal.class);
-
- assertWithMessage("LocalServices.getService(UserManagerInternal.class)").that(mUmi)
- .isNotNull();
- }
-
- @After
- public void resetLocalService() {
- // LocalServices follows the "Highlander rule" - There can be only one!
- LocalServices.removeServiceForTest(UserManagerInternal.class);
- }
+public final class UserManagerServiceTest extends UserManagerServiceOrInternalTestCase {
@Test
- public void testgetCurrentUserId_amInternalNotReady() {
+ public void testGetCurrentUserId_amInternalNotReady() {
mockGetLocalService(ActivityManagerInternal.class, null);
assertWithMessage("getCurrentUserId()").that(mUms.getCurrentUserId())
@@ -103,119 +36,70 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase {
}
@Test
- public void testgetCurrentUserId() {
- mockCurrentUser(42);
+ public void testGetCurrentUserId() {
+ mockCurrentUser(USER_ID);
assertWithMessage("getCurrentUserId()").that(mUms.getCurrentUserId())
- .isEqualTo(42);
+ .isEqualTo(USER_ID);
}
@Test
public void testIsCurrentUserOrRunningProfileOfCurrentUser_currentUser() {
- int userId = 42;
- mockCurrentUser(userId);
+ mockCurrentUser(USER_ID);
- assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", userId)
- .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(userId)).isTrue();
+ assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", USER_ID)
+ .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(USER_ID)).isTrue();
}
@Test
public void testIsCurrentUserOrRunningProfileOfCurrentUser_notCurrentUser() {
- int userId = 42;
- mockCurrentUser(108);
+ mockCurrentUser(OTHER_USER_ID);
- assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", userId)
- .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(userId)).isFalse();
+ assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", USER_ID)
+ .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(USER_ID)).isFalse();
}
@Test
public void testIsCurrentUserOrRunningProfileOfCurrentUser_startedProfileOfCurrentUser() {
- int parentId = 108;
- int profileId = 42;
- addUser(parentId);
- addProfile(profileId, parentId);
- mockCurrentUser(parentId);
- setUserState(profileId, UserState.STATE_RUNNING_UNLOCKED);
-
- assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", profileId)
- .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(profileId)).isTrue();
+ addDefaultProfileAndParent();
+ startDefaultProfile();
+ mockCurrentUser(PARENT_USER_ID);
+
+ assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", PROFILE_USER_ID)
+ .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID)).isTrue();
}
@Test
public void testIsCurrentUserOrRunningProfileOfCurrentUser_stoppedProfileOfCurrentUser() {
- int parentId = 108;
- int profileId = 42;
- addUser(parentId);
- addProfile(profileId, parentId);
- mockCurrentUser(parentId);
- // TODO(b/244798930): should set it to STATE_STOPPING or STATE_SHUTDOWN instead
- removeUserState(profileId);
-
- assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", profileId)
- .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(profileId)).isFalse();
+ addDefaultProfileAndParent();
+ stopDefaultProfile();
+ mockCurrentUser(PARENT_USER_ID);
+
+ assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", PROFILE_USER_ID)
+ .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID)).isFalse();
}
@Test
public void testIsCurrentUserOrRunningProfileOfCurrentUser_profileOfNonCurrentUSer() {
- int parentId = 108;
- int profileId = 42;
- int currentUserId = 666;
- addUser(parentId);
- addProfile(profileId, parentId);
- mockCurrentUser(currentUserId);
-
- assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", profileId)
- .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(profileId)).isFalse();
- }
-
- private void mockCurrentUser(@UserIdInt int userId) {
- mockGetLocalService(ActivityManagerInternal.class, mActivityManagerInternal);
-
- when(mActivityManagerInternal.getCurrentUserId()).thenReturn(userId);
- }
-
- private <T> void mockGetLocalService(Class<T> serviceClass, T service) {
- doReturn(service).when(() -> LocalServices.getService(serviceClass));
- }
-
- private void addProfile(@UserIdInt int profileId, @UserIdInt int parentId) {
- TestUserData profileData = new TestUserData(profileId);
- profileData.info.flags = UserInfo.FLAG_PROFILE;
- profileData.info.profileGroupId = parentId;
-
- addUserData(profileData);
- }
-
- private void addUser(@UserIdInt int userId) {
- TestUserData userData = new TestUserData(userId);
+ addDefaultProfileAndParent();
+ mockCurrentUser(OTHER_USER_ID);
- addUserData(userData);
+ assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", PROFILE_USER_ID)
+ .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID)).isFalse();
}
- private void addUserData(TestUserData userData) {
- Log.d(TAG, "Adding " + userData);
- mUsers.put(userData.info.id, userData);
- }
-
- private void setUserState(@UserIdInt int userId, int userState) {
- mUmi.setUserState(userId, userState);
+ @Override
+ protected boolean isUserVisible(int userId) {
+ return mUms.isUserVisibleUnchecked(userId);
}
- private void removeUserState(@UserIdInt int userId) {
- mUmi.removeUserState(userId);
+ @Override
+ protected boolean isUserVisibleOnDisplay(int userId, int displayId) {
+ return mUms.isUserVisibleOnDisplay(userId, displayId);
}
- private static final class TestUserData extends UserData {
-
- @SuppressWarnings("unused")
- TestUserData(@UserIdInt int userId) {
- info = new UserInfo();
- info.id = userId;
- }
-
- @Override
- public String toString() {
- return "TestUserData[" + info.toFullString() + "]";
- }
+ @Override
+ protected int getDisplayAssignedToUser(int userId) {
+ return mUms.getDisplayAssignedToUser(userId);
}
}