1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.server.pm; 18 19 import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertTrue; 23 24 import android.app.PropertyInvalidatedCache; 25 import android.content.pm.UserInfo; 26 import android.os.Looper; 27 import android.os.ServiceSpecificException; 28 import android.os.UserHandle; 29 import android.os.UserManager; 30 import android.platform.test.annotations.Postsubmit; 31 32 import androidx.test.InstrumentationRegistry; 33 import androidx.test.filters.MediumTest; 34 import androidx.test.runner.AndroidJUnit4; 35 36 import com.android.server.LocalServices; 37 import com.android.server.storage.DeviceStorageMonitorInternal; 38 39 import org.junit.After; 40 import org.junit.Before; 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 import org.mockito.Mockito; 44 45 import java.util.List; 46 47 /** 48 * <p>Run with:<pre> 49 * runtest -c com.android.server.pm.UserManagerServiceCreateProfileTest frameworks-services 50 * </pre> 51 */ 52 @Postsubmit 53 @RunWith(AndroidJUnit4.class) 54 @MediumTest 55 public class UserManagerServiceCreateProfileTest { 56 private UserManagerService mUserManagerService; 57 58 @Before setup()59 public void setup() { 60 // Currently UserManagerService cannot be instantiated twice inside a VM without a cleanup 61 // TODO: Remove once UMS supports proper dependency injection 62 if (Looper.myLooper() == null) { 63 Looper.prepare(); 64 } 65 // Disable binder caches in this process. 66 PropertyInvalidatedCache.disableForTestMode(); 67 68 LocalServices.removeServiceForTest(UserManagerInternal.class); 69 mUserManagerService = new UserManagerService(InstrumentationRegistry.getContext()); 70 71 // The tests assume that the device has one user and its the system user. 72 List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false); 73 assertEquals("Multiple users so this test can't run.", 1, users.size()); 74 assertEquals("Only user present isn't the system user.", 75 UserHandle.USER_SYSTEM, users.get(0).id); 76 } 77 78 @After tearDown()79 public void tearDown() { 80 removeUsers(); 81 } 82 83 /** Tests UMS.getProfileIds() when no specific userType is specified. */ 84 @Test testGetProfiles()85 public void testGetProfiles() { 86 // Pretend we have a secondary user with a profile. 87 UserInfo secondaryUser = addUser(); 88 UserInfo profile = addProfile(secondaryUser); 89 90 // System user should still have no profile so getProfiles should just return 1 user. 91 List<UserInfo> users = 92 mUserManagerService.getProfiles(UserHandle.USER_SYSTEM, /*excludeDying*/ false); 93 assertEquals("Profiles returned where none should exist", 1, users.size()); 94 assertEquals("Missing system user from profile list of system user", 95 UserHandle.USER_SYSTEM, users.get(0).id); 96 97 // Secondary user should have 1 profile, so return that and itself. 98 users = mUserManagerService.getProfiles(secondaryUser.id, /*excludeDying*/ false); 99 assertEquals("Profiles returned where none should exist", 2, users.size()); 100 assertTrue("Missing secondary user id", users.get(0).id == secondaryUser.id 101 || users.get(1).id == secondaryUser.id); 102 assertTrue("Missing profile user id", users.get(0).id == profile.id 103 || users.get(1).id == profile.id); 104 } 105 106 /** Tests UMS.getProfileIds() when a specific userType is specified. */ 107 @Test testGetProfileIds_specifyType()108 public void testGetProfileIds_specifyType() { 109 // Pretend we have a secondary user with a profile. 110 UserInfo secondaryUser = addUser(); 111 UserInfo profile = addProfile(secondaryUser); 112 113 // TODO: When there are multiple profiles types, ensure correct output for mixed types. 114 final String userType1 = USER_TYPE_PROFILE_MANAGED; 115 116 // System user should still have no userType1 profile so getProfileIds should be empty. 117 int[] users = mUserManagerService.getProfileIds(UserHandle.USER_SYSTEM, userType1, false); 118 assertEquals("System user should have no managed profiles", 0, users.length); 119 120 // Secondary user should have one userType1 profile, so return just that. 121 users = mUserManagerService.getProfileIds(secondaryUser.id, userType1, false); 122 assertEquals("Wrong number of profiles", 1, users.length); 123 assertEquals("Wrong profile id", profile.id, users[0]); 124 125 // The profile itself is a userType1 profile, so it should return just itself. 126 users = mUserManagerService.getProfileIds(profile.id, userType1, false); 127 assertEquals("Wrong number of profiles", 1, users.length); 128 assertEquals("Wrong profile id", profile.id, users[0]); 129 } 130 131 @Test testProfileBadge()132 public void testProfileBadge() { 133 // First profile for system user should get badge 0 134 assertEquals("First profile isn't given badge index 0", 0, 135 mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM, 136 USER_TYPE_PROFILE_MANAGED)); 137 138 // Pretend we have a secondary user. 139 UserInfo secondaryUser = addUser(); 140 141 // Check first profile badge for secondary user is also 0. 142 assertEquals("First profile for secondary user isn't given badge index 0", 0, 143 mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id, 144 USER_TYPE_PROFILE_MANAGED)); 145 146 // Shouldn't impact the badge for profile in system user 147 assertEquals("First profile isn't given badge index 0 with secondary user", 0, 148 mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM, 149 USER_TYPE_PROFILE_MANAGED)); 150 151 // Pretend a secondary user has a profile. 152 addProfile(secondaryUser); 153 154 // Shouldn't have impacted the badge for the system user 155 assertEquals("First profile isn't given badge index 0 in secondary user", 0, 156 mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM, 157 USER_TYPE_PROFILE_MANAGED)); 158 } 159 160 @Test testProfileBadgeUnique()161 public void testProfileBadgeUnique() { 162 List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false); 163 UserInfo system = users.get(0); 164 int max = mUserManagerService.getMaxUsersOfTypePerParent(USER_TYPE_PROFILE_MANAGED); 165 if (max < 0) { 166 // Indicates no max. Instead of infinite, we'll just do 10. 167 max = 10; 168 } 169 // Badges should get allocated 0 -> max 170 for (int i = 0; i < max; ++i) { 171 int nextBadge = mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM, 172 USER_TYPE_PROFILE_MANAGED); 173 assertEquals("Wrong badge allocated", i, nextBadge); 174 UserInfo profile = addProfile(system); 175 profile.profileBadge = nextBadge; 176 } 177 } 178 179 @Test testProfileBadgeReuse()180 public void testProfileBadgeReuse() { 181 // Pretend we have a secondary user with a profile. 182 UserInfo secondaryUser = addUser(); 183 UserInfo profile = addProfile(secondaryUser); 184 // Add the profile it to the users being removed. 185 mUserManagerService.addRemovingUserId(profile.id); 186 // We should reuse the badge from the profile being removed. 187 assertEquals("Badge index not reused while removing a user", 0, 188 mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id, 189 USER_TYPE_PROFILE_MANAGED)); 190 191 // Edge case of reuse that only applies if we ever support 3 managed profiles 192 // We should prioritise using lower badge indexes 193 int max = mUserManagerService.getMaxUsersOfTypePerParent(USER_TYPE_PROFILE_MANAGED); 194 if (max < 0 || max > 2) { 195 UserInfo profileBadgeOne = addProfile(secondaryUser); 196 profileBadgeOne.profileBadge = 1; 197 // 0 and 2 are free, we should reuse 0 rather than 2. 198 assertEquals("Lower index not used", 0, 199 mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id, 200 USER_TYPE_PROFILE_MANAGED)); 201 } 202 } 203 204 @Test testCanAddMoreManagedProfiles_removeProfile()205 public void testCanAddMoreManagedProfiles_removeProfile() { 206 // if device is low-ram or doesn't support managed profiles for some other reason, just 207 // skip the test 208 if (!mUserManagerService.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, 209 false /* disallow remove */)) { 210 return; 211 } 212 if (mUserManagerService.getMaxUsersOfTypePerParent(USER_TYPE_PROFILE_MANAGED) < 0) { 213 // Indicates no limit, so we cannot run this test; 214 return; 215 } 216 217 // GIVEN we've reached the limit of managed profiles possible on the system user 218 while (mUserManagerService.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, 219 false /* disallow remove */)) { 220 addProfile(mUserManagerService.getPrimaryUser()); 221 } 222 223 // THEN you should be able to add a new profile if you remove an existing one 224 assertTrue("Cannot add a managed profile by removing another one", 225 mUserManagerService.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, 226 true /* allow remove */)); 227 } 228 229 @Test testCanAddMoreManagedProfiles_removeDisabledProfile()230 public void testCanAddMoreManagedProfiles_removeDisabledProfile() { 231 // if device is low-ram or doesn't support managed profiles for some other reason, just 232 // skip the test 233 if (!mUserManagerService.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, 234 false /* disallow remove */)) { 235 return; 236 } 237 if (mUserManagerService.getMaxUsersOfTypePerParent(USER_TYPE_PROFILE_MANAGED) < 0) { 238 // Indicates no limit, so we cannot run this test; 239 return; 240 } 241 242 // GIVEN we've reached the limit of managed profiles possible on the system user 243 // GIVEN that the profiles are not enabled yet 244 while (mUserManagerService.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, 245 false /* disallow remove */)) { 246 addProfile(mUserManagerService.getPrimaryUser(), true /* disabled */); 247 } 248 249 // THEN you should be able to add a new profile if you remove an existing one 250 assertTrue("Cannot add a managed profile by removing another one", 251 mUserManagerService.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, 252 true /* allow remove */)); 253 } 254 255 @Test testCreateProfileForUser_lowStorageException()256 public void testCreateProfileForUser_lowStorageException() { 257 DeviceStorageMonitorInternal dsmMock = Mockito.mock(DeviceStorageMonitorInternal.class); 258 Mockito.when(dsmMock.isMemoryLow()).thenReturn(true); 259 LocalServices.addService(DeviceStorageMonitorInternal.class, dsmMock); 260 261 try { 262 mUserManagerService.createProfileForUserWithThrow("user2", USER_TYPE_PROFILE_MANAGED, 0, 263 UserHandle.USER_SYSTEM, null); 264 } catch (ServiceSpecificException e) { 265 assertEquals(UserManager.USER_OPERATION_ERROR_LOW_STORAGE, 266 UserManager.UserOperationException.from(e).getUserOperationResult()); 267 } finally { 268 LocalServices.removeServiceForTest(DeviceStorageMonitorInternal.class); 269 } 270 } 271 272 @Test testCreateProfileForUser_unknownParentUser()273 public void testCreateProfileForUser_unknownParentUser() { 274 DeviceStorageMonitorInternal dsmMock = Mockito.mock(DeviceStorageMonitorInternal.class); 275 Mockito.when(dsmMock.isMemoryLow()).thenReturn(false); 276 LocalServices.addService(DeviceStorageMonitorInternal.class, dsmMock); 277 278 try { 279 final int badParentUserId = 1234; 280 mUserManagerService.createProfileForUserWithThrow("profile", USER_TYPE_PROFILE_MANAGED, 281 0, badParentUserId, null); 282 } catch (ServiceSpecificException e) { 283 assertEquals(UserManager.USER_OPERATION_ERROR_UNKNOWN, 284 UserManager.UserOperationException.from(e).getUserOperationResult()); 285 } finally { 286 LocalServices.removeServiceForTest(DeviceStorageMonitorInternal.class); 287 } 288 } 289 290 @Test testCreateManagedProfileForUser_maxManagedUsersException()291 public void testCreateManagedProfileForUser_maxManagedUsersException() { 292 DeviceStorageMonitorInternal dsmMock = Mockito.mock(DeviceStorageMonitorInternal.class); 293 Mockito.when(dsmMock.isMemoryLow()).thenReturn(false); 294 LocalServices.addService(DeviceStorageMonitorInternal.class, dsmMock); 295 296 UserManagerService userManagerServiceSpy = Mockito.spy(mUserManagerService); 297 Mockito.doReturn(false).when(userManagerServiceSpy).canAddMoreManagedProfiles( 298 Mockito.anyInt(), Mockito.anyBoolean()); 299 300 Mockito.doReturn(false).when(userManagerServiceSpy).canAddMoreProfilesToUser( 301 Mockito.anyString(), Mockito.anyInt(), Mockito.anyBoolean()); 302 303 try { 304 userManagerServiceSpy.createProfileForUserWithThrow("profile", 305 USER_TYPE_PROFILE_MANAGED, 0, UserHandle.USER_SYSTEM, null); 306 } catch (ServiceSpecificException e) { 307 assertEquals(UserManager.USER_OPERATION_ERROR_MAX_USERS, 308 UserManager.UserOperationException.from(e).getUserOperationResult()); 309 } finally { 310 LocalServices.removeServiceForTest(DeviceStorageMonitorInternal.class); 311 } 312 } 313 removeUsers()314 private void removeUsers() { 315 List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false); 316 for (UserInfo user: users) { 317 if (user.id != UserHandle.USER_SYSTEM) { 318 mUserManagerService.removeUserInfo(user.id); 319 } 320 } 321 } 322 addProfile(UserInfo user)323 private UserInfo addProfile(UserInfo user) { 324 return addProfile(user, false); 325 } 326 addProfile(UserInfo user, boolean disabled)327 private UserInfo addProfile(UserInfo user, boolean disabled) { 328 user.profileGroupId = user.id; 329 int flags = UserInfo.FLAG_MANAGED_PROFILE; 330 if (disabled) { 331 flags |= UserInfo.FLAG_DISABLED; 332 } 333 UserInfo profile = new UserInfo( 334 mUserManagerService.getNextAvailableId(), "profile", flags); 335 profile.profileGroupId = user.id; 336 mUserManagerService.putUserInfo(profile); 337 return profile; 338 } 339 addUser()340 private UserInfo addUser() { 341 UserInfo secondaryUser = new UserInfo( 342 mUserManagerService.getNextAvailableId(), "secondary", /* flags */ 0); 343 mUserManagerService.putUserInfo(secondaryUser); 344 return secondaryUser; 345 } 346 } 347