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