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