blob: af9898e331eb81c89a5827cc558d7da9e5be0361 [file] [log] [blame]
/*
* Copyright (C) 2020 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 android.multiuser.cts;
import static android.Manifest.permission.CREATE_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.QUERY_USERS;
import static android.content.pm.PackageManager.FEATURE_MANAGED_USERS;
import static android.multiuser.cts.PermissionHelper.adoptShellPermissionIdentity;
import static android.multiuser.cts.TestingUtils.getBooleanProperty;
import static android.os.UserManager.USER_OPERATION_SUCCESS;
import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assume.assumeTrue;
import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.NewUserRequest;
import android.os.NewUserResponse;
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.SystemUserOnly;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.EnsureHasPermission;
import com.android.bedstead.harrier.annotations.RequireFeature;
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.users.UserReference;
import com.android.bedstead.nene.users.UserType;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@RunWith(BedsteadJUnit4.class)
public final class UserManagerTest {
@ClassRule
@Rule
public static final DeviceState sDeviceState = new DeviceState();
private static final Context sContext = TestApis.context().instrumentedContext();
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
private UserManager mUserManager;
private final String mAccountName = "test_account_name";
private final String mAccountType = "test_account_type";
@Before
public void setUp() {
mUserManager = sContext.getSystemService(UserManager.class);
assertWithMessage("UserManager service").that(mUserManager).isNotNull();
}
private void removeUser(UserHandle userHandle) {
if (userHandle == null) {
return;
}
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
assertThat(mUserManager.removeUser(userHandle)).isTrue();
}
}
/**
* Verify that the isUserAGoat() method always returns false for API level 30. This is
* because apps targeting R no longer have access to package queries by default.
*/
@Test
public void testUserGoat_api30() {
assertWithMessage("isUserAGoat()").that(mUserManager.isUserAGoat()).isFalse();
}
@Test
public void testIsHeadlessSystemUserMode() throws Exception {
boolean expected = getBooleanProperty(mInstrumentation,
"ro.fw.mu.headless_system_user");
assertWithMessage("isHeadlessSystemUserMode()")
.that(UserManager.isHeadlessSystemUserMode()).isEqualTo(expected);
}
@Test
public void testIsUserForeground_currentUser() throws Exception {
assertWithMessage("isUserForeground() for current user")
.that(mUserManager.isUserForeground()).isTrue();
}
// TODO(b/173541467): add testIsUserForeground_backgroundUser()
// TODO(b/179163496): add testIsUserForeground_ tests for profile users
@Test
@SystemUserOnly(reason = "Profiles are only supported on system user.")
public void testCloneProfile() throws Exception {
UserHandle userHandle = null;
// Need CREATE_USERS permission to create user in test
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
Set<String> disallowedPackages = new HashSet<String>();
userHandle = mUserManager.createProfile(
"Clone profile", UserManager.USER_TYPE_PROFILE_CLONE, disallowedPackages);
assertThat(userHandle).isNotNull();
final Context userContext = sContext.createPackageContextAsUser("system", 0,
userHandle);
final UserManager cloneUserManager = userContext.getSystemService(UserManager.class);
assertThat(cloneUserManager.isMediaSharedWithParent()).isTrue();
assertThat(cloneUserManager.isCredentialSharedWithParent()).isTrue();
assertThat(cloneUserManager.isCloneProfile()).isTrue();
assertThat(cloneUserManager.isProfile()).isTrue();
assertThat(cloneUserManager.isUserOfType(UserManager.USER_TYPE_PROFILE_CLONE)).isTrue();
final List<UserInfo> list = mUserManager.getUsers(true, true, true);
final UserHandle finalUserHandle = userHandle;
final List<UserInfo> cloneUsers = list.stream().filter(
user -> (user.id == finalUserHandle.getIdentifier()
&& user.isCloneProfile()))
.collect(Collectors.toList());
assertThat(cloneUsers.size()).isEqualTo(1);
} finally {
removeUser(userHandle);
}
}
@Test
@SystemUserOnly(reason = "Profiles are only supported on system user.")
@EnsureHasPermission({CREATE_USERS, QUERY_USERS})
public void testManagedProfile() throws Exception {
UserHandle userHandle = null;
try {
userHandle = mUserManager.createProfile(
"Managed profile", UserManager.USER_TYPE_PROFILE_MANAGED, new HashSet<>());
assertThat(userHandle).isNotNull();
final UserManager umOfProfile = sContext
.createPackageContextAsUser("android", 0, userHandle)
.getSystemService(UserManager.class);
// TODO(b/222584163): Remove the if{} clause after v33 Sdk bump.
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S_V2) {
assertThat(umOfProfile.isManagedProfile()).isTrue();
}
assertThat(umOfProfile.isManagedProfile(userHandle.getIdentifier())).isTrue();
assertThat(umOfProfile.isProfile()).isTrue();
assertThat(umOfProfile.isUserOfType(UserManager.USER_TYPE_PROFILE_MANAGED)).isTrue();
} finally {
removeUser(userHandle);
}
}
@Test
@EnsureHasPermission({QUERY_USERS})
public void testSystemUser() throws Exception {
final UserManager umOfSys = sContext
.createPackageContextAsUser("android", 0, UserHandle.SYSTEM)
.getSystemService(UserManager.class);
assertThat(umOfSys.isSystemUser()).isTrue();
// We cannot demand what type of user SYSTEM is, but we can say some things it isn't.
assertThat(umOfSys.isUserOfType(UserManager.USER_TYPE_PROFILE_CLONE)).isFalse();
assertThat(umOfSys.isUserOfType(UserManager.USER_TYPE_PROFILE_MANAGED)).isFalse();
assertThat(umOfSys.isUserOfType(UserManager.USER_TYPE_FULL_GUEST)).isFalse();
assertThat(umOfSys.isProfile()).isFalse();
assertThat(umOfSys.isManagedProfile()).isFalse();
assertThat(umOfSys.isManagedProfile(UserHandle.USER_SYSTEM)).isFalse();
assertThat(umOfSys.isCloneProfile()).isFalse();
}
@Test
@SystemUserOnly(reason = "Restricted users are only supported on system user.")
public void testRestrictedUser() throws Exception {
UserHandle user = null;
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
// Check that the SYSTEM user is not restricted.
assertThat(mUserManager.isRestrictedProfile()).isFalse();
assertThat(mUserManager.isRestrictedProfile(UserHandle.SYSTEM)).isFalse();
assertThat(mUserManager.getRestrictedProfileParent()).isNull();
final UserInfo info = mUserManager.createRestrictedProfile("Restricted user");
// If the device supports Restricted users, it must report it correctly.
assumeTrue("Couldn't create a restricted profile", info != null);
user = UserHandle.of(info.id);
assertThat(mUserManager.isRestrictedProfile(user)).isTrue();
final Context userContext = sContext.createPackageContextAsUser("system", 0, user);
final UserManager userUm = userContext.getSystemService(UserManager.class);
// TODO(b/222584163): Remove the if{} clause after v33 Sdk bump.
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S_V2) {
assertThat(userUm.isRestrictedProfile()).isTrue();
}
assertThat(userUm.getRestrictedProfileParent().isSystem()).isTrue();
} finally {
removeUser(user);
}
}
private NewUserRequest newUserRequest() {
final PersistableBundle accountOptions = new PersistableBundle();
accountOptions.putString("test_account_option_key", "test_account_option_value");
return new NewUserRequest.Builder()
.setName("test_user")
.setUserType(USER_TYPE_FULL_SECONDARY)
.setUserIcon(Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565))
.setAccountName(mAccountName)
.setAccountType(mAccountType)
.setAccountOptions(accountOptions)
.build();
}
@Test
public void testSomeUserHasAccount() {
UserHandle user = null;
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
assertThat(mUserManager.someUserHasAccount(mAccountName, mAccountType)).isFalse();
user = mUserManager.createUser(newUserRequest()).getUser();
assertThat(mUserManager.someUserHasAccount(mAccountName, mAccountType)).isTrue();
} finally {
removeUser(user);
}
}
@Test
public void testSomeUserHasAccount_shouldIgnoreToBeRemovedUsers() {
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
final NewUserResponse response = mUserManager.createUser(newUserRequest());
assertThat(response.getOperationResult()).isEqualTo(USER_OPERATION_SUCCESS);
mUserManager.removeUser(response.getUser());
assertThat(mUserManager.someUserHasAccount(mAccountName, mAccountType)).isFalse();
}
}
@Test
public void testCreateUser_withNewUserRequest_shouldCreateUserWithCorrectProperties()
throws PackageManager.NameNotFoundException {
UserHandle user = null;
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
final NewUserRequest request = newUserRequest();
final NewUserResponse response = mUserManager.createUser(request);
user = response.getUser();
assertThat(response.getOperationResult()).isEqualTo(USER_OPERATION_SUCCESS);
assertThat(response.isSuccessful()).isTrue();
assertThat(user).isNotNull();
UserManager userManagerOfNewUser = sContext
.createPackageContextAsUser("android", 0, user)
.getSystemService(UserManager.class);
assertThat(userManagerOfNewUser.getUserName()).isEqualTo(request.getName());
// TODO(b/222584163): Remove the if{} clause after v33 Sdk bump.
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S_V2) {
assertThat(userManagerOfNewUser.isUserNameSet()).isTrue();
}
assertThat(userManagerOfNewUser.getUserType()).isEqualTo(request.getUserType());
assertThat(userManagerOfNewUser.isUserOfType(request.getUserType())).isEqualTo(true);
// We can not test userIcon and accountOptions,
// because getters require MANAGE_USERS permission.
// And we are already testing accountName and accountType
// are set correctly in testSomeUserHasAccount method.
} finally {
removeUser(user);
}
}
@Test
public void testCreateUser_withNewUserRequest_shouldNotAllowDuplicateUserAccounts() {
UserHandle user1 = null;
UserHandle user2 = null;
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
final NewUserResponse response1 = mUserManager.createUser(newUserRequest());
user1 = response1.getUser();
assertThat(response1.getOperationResult()).isEqualTo(USER_OPERATION_SUCCESS);
assertThat(response1.isSuccessful()).isTrue();
assertThat(user1).isNotNull();
final NewUserResponse response2 = mUserManager.createUser(newUserRequest());
user2 = response2.getUser();
assertThat(response2.getOperationResult()).isEqualTo(
UserManager.USER_OPERATION_ERROR_USER_ACCOUNT_ALREADY_EXISTS);
assertThat(response2.isSuccessful()).isFalse();
assertThat(user2).isNull();
} finally {
removeUser(user1);
removeUser(user2);
}
}
@Test
@AppModeFull
@RequireFeature(FEATURE_MANAGED_USERS)
@EnsureHasPermission(INTERACT_ACROSS_USERS)
public void getProfileParent_withNewlyCreatedProfile() {
final UserReference parent = TestApis.users().instrumented();
try (UserReference profile = TestApis.users().createUser()
.parent(parent)
.type(TestApis.users().supportedType(UserType.MANAGED_PROFILE_TYPE_NAME))
.createAndStart()) {
assertThat(mUserManager.getProfileParent(profile.userHandle()))
.isEqualTo(parent.userHandle());
}
}
@Test
@AppModeFull
@EnsureHasPermission(INTERACT_ACROSS_USERS)
public void getProfileParent_returnsNullForNonProfile() {
assertThat(mUserManager.getProfileParent(TestApis.users().system().userHandle())).isNull();
}
@Test
@EnsureHasPermission({CREATE_USERS, QUERY_USERS})
public void testGetRemainingCreatableUserCount() {
final int maxAllowedIterations = 15;
final String userType = USER_TYPE_FULL_SECONDARY;
final NewUserRequest request = new NewUserRequest.Builder().build();
final ArrayDeque<UserHandle> usersCreated = new ArrayDeque<>();
try {
final int initialRemainingCount = mUserManager.getRemainingCreatableUserCount(userType);
assertThat(initialRemainingCount).isAtLeast(0);
final int numUsersToAdd = Math.min(maxAllowedIterations, initialRemainingCount);
for (int i = 0; i < numUsersToAdd; i++) {
usersCreated.push(mUserManager.createUser(request).getUser());
assertThat(mUserManager.getRemainingCreatableUserCount(userType))
.isEqualTo(initialRemainingCount - usersCreated.size());
}
for (int i = 0; i < numUsersToAdd; i++) {
mUserManager.removeUser(usersCreated.pop());
assertThat(mUserManager.getRemainingCreatableUserCount(userType))
.isEqualTo(initialRemainingCount - usersCreated.size());
}
} finally {
usersCreated.forEach(this::removeUser);
}
}
@Test
@EnsureHasPermission({CREATE_USERS, QUERY_USERS})
public void testGetRemainingCreatableProfileCount() {
final int maxAllowedIterations = 15;
final String type = USER_TYPE_PROFILE_MANAGED;
final ArrayDeque<UserHandle> profilesCreated = new ArrayDeque<>();
final Set<String> disallowedPackages = new HashSet<>();
try {
final int initialRemainingCount =
mUserManager.getRemainingCreatableProfileCount(type);
assertThat(initialRemainingCount).isAtLeast(0);
final int numUsersToAdd = Math.min(maxAllowedIterations, initialRemainingCount);
for (int i = 0; i < numUsersToAdd; i++) {
profilesCreated.push(mUserManager.createProfile(null, type, disallowedPackages));
assertThat(mUserManager.getRemainingCreatableProfileCount(type))
.isEqualTo(initialRemainingCount - profilesCreated.size());
}
for (int i = 0; i < numUsersToAdd; i++) {
mUserManager.removeUser(profilesCreated.pop());
assertThat(mUserManager.getRemainingCreatableProfileCount(type))
.isEqualTo(initialRemainingCount - profilesCreated.size());
}
} finally {
profilesCreated.forEach(this::removeUser);
}
}
}