• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.content.pm.UserInfo.FLAG_DEMO;
20 import static android.content.pm.UserInfo.FLAG_EPHEMERAL;
21 import static android.content.pm.UserInfo.FLAG_FULL;
22 import static android.content.pm.UserInfo.FLAG_GUEST;
23 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
24 import static android.content.pm.UserInfo.FLAG_PROFILE;
25 import static android.content.pm.UserInfo.FLAG_RESTRICTED;
26 import static android.content.pm.UserInfo.FLAG_SYSTEM;
27 
28 import static com.android.server.pm.UserTypeDetails.UNLIMITED_NUMBER_OF_USERS;
29 
30 import static org.junit.Assert.assertEquals;
31 import static org.junit.Assert.assertFalse;
32 import static org.junit.Assert.assertNotNull;
33 import static org.junit.Assert.assertNotSame;
34 import static org.junit.Assert.assertTrue;
35 import static org.testng.Assert.assertThrows;
36 
37 import android.content.pm.UserInfo;
38 import android.content.res.Resources;
39 import android.content.res.XmlResourceParser;
40 import android.os.Bundle;
41 import android.os.UserManager;
42 import android.platform.test.annotations.Presubmit;
43 import android.util.ArrayMap;
44 
45 import androidx.test.InstrumentationRegistry;
46 import androidx.test.filters.MediumTest;
47 import androidx.test.runner.AndroidJUnit4;
48 
49 import com.android.frameworks.servicestests.R;
50 
51 import org.junit.Before;
52 import org.junit.Test;
53 import org.junit.runner.RunWith;
54 
55 import java.util.List;
56 
57 /**
58  * Tests for {@link UserTypeDetails} and {@link UserTypeFactory}.
59  *
60  * <p>Run with: atest UserManagerServiceUserTypeTest
61  */
62 @Presubmit
63 @RunWith(AndroidJUnit4.class)
64 @MediumTest
65 public class UserManagerServiceUserTypeTest {
66 
67     private Resources mResources;
68 
69     @Before
setup()70     public void setup() {
71         mResources = InstrumentationRegistry.getTargetContext().getResources();
72     }
73 
74     @Test
testUserTypeBuilder_createUserType()75     public void testUserTypeBuilder_createUserType() {
76         final Bundle restrictions = makeRestrictionsBundle("r1", "r2");
77         final Bundle systemSettings = makeSettingsBundle("s1", "s2");
78         final Bundle secureSettings = makeSettingsBundle("secure_s1", "secure_s2");
79         final List<DefaultCrossProfileIntentFilter> filters = List.of(
80                 new DefaultCrossProfileIntentFilter.Builder(
81                 DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
82                 /* flags= */0,
83                 /* letsPersonalDataIntoProfile= */false).build());
84         final UserTypeDetails type = new UserTypeDetails.Builder()
85                 .setName("a.name")
86                 .setEnabled(1)
87                 .setMaxAllowed(21)
88                 .setBaseType(FLAG_PROFILE)
89                 .setDefaultUserInfoPropertyFlags(FLAG_EPHEMERAL)
90                 .setBadgeLabels(23, 24, 25)
91                 .setBadgeColors(26, 27)
92                 .setIconBadge(28)
93                 .setBadgePlain(29)
94                 .setBadgeNoBackground(30)
95                 .setLabel(31)
96                 .setMaxAllowedPerParent(32)
97                 .setDefaultRestrictions(restrictions)
98                 .setDefaultSystemSettings(systemSettings)
99                 .setDefaultSecureSettings(secureSettings)
100                 .setDefaultCrossProfileIntentFilters(filters)
101                 .createUserTypeDetails();
102 
103         assertEquals("a.name", type.getName());
104         assertTrue(type.isEnabled());
105         assertEquals(21, type.getMaxAllowed());
106         assertEquals(FLAG_PROFILE | FLAG_EPHEMERAL, type.getDefaultUserInfoFlags());
107         assertEquals(28, type.getIconBadge());
108         assertEquals(29, type.getBadgePlain());
109         assertEquals(30, type.getBadgeNoBackground());
110         assertEquals(31, type.getLabel());
111         assertEquals(32, type.getMaxAllowedPerParent());
112 
113         assertTrue(UserRestrictionsUtils.areEqual(restrictions, type.getDefaultRestrictions()));
114         assertNotSame(restrictions, type.getDefaultRestrictions());
115 
116         assertNotSame(systemSettings, type.getDefaultSystemSettings());
117         assertEquals(systemSettings.size(), type.getDefaultSystemSettings().size());
118         for (String key : systemSettings.keySet()) {
119             assertEquals(
120                     systemSettings.getString(key),
121                     type.getDefaultSystemSettings().getString(key));
122         }
123 
124         assertNotSame(secureSettings, type.getDefaultSecureSettings());
125         assertEquals(secureSettings.size(), type.getDefaultSecureSettings().size());
126         for (String key : secureSettings.keySet()) {
127             assertEquals(
128                     secureSettings.getString(key),
129                     type.getDefaultSecureSettings().getString(key));
130         }
131 
132         assertNotSame(filters, type.getDefaultCrossProfileIntentFilters());
133         assertEquals(filters.size(), type.getDefaultCrossProfileIntentFilters().size());
134         for (int i = 0; i < filters.size(); i++) {
135             assertEquals(filters.get(i), type.getDefaultCrossProfileIntentFilters().get(i));
136         }
137 
138         assertEquals(23, type.getBadgeLabel(0));
139         assertEquals(24, type.getBadgeLabel(1));
140         assertEquals(25, type.getBadgeLabel(2));
141         assertEquals(25, type.getBadgeLabel(3));
142         assertEquals(25, type.getBadgeLabel(4));
143         assertEquals(Resources.ID_NULL, type.getBadgeLabel(-1));
144 
145         assertEquals(26, type.getBadgeColor(0));
146         assertEquals(27, type.getBadgeColor(1));
147         assertEquals(27, type.getBadgeColor(2));
148         assertEquals(27, type.getBadgeColor(3));
149         assertEquals(Resources.ID_NULL, type.getBadgeColor(-100));
150 
151         assertTrue(type.hasBadge());
152     }
153 
154     @Test
testUserTypeBuilder_defaults()155     public void testUserTypeBuilder_defaults() {
156         UserTypeDetails type = new UserTypeDetails.Builder()
157                 .setName("name") // Required (no default allowed)
158                 .setBaseType(FLAG_FULL) // Required (no default allowed)
159                 .createUserTypeDetails();
160 
161         assertTrue(type.isEnabled());
162         assertEquals(UNLIMITED_NUMBER_OF_USERS, type.getMaxAllowed());
163         assertEquals(UNLIMITED_NUMBER_OF_USERS, type.getMaxAllowedPerParent());
164         assertEquals(FLAG_FULL, type.getDefaultUserInfoFlags());
165         assertEquals(Resources.ID_NULL, type.getIconBadge());
166         assertEquals(Resources.ID_NULL, type.getBadgePlain());
167         assertEquals(Resources.ID_NULL, type.getBadgeNoBackground());
168         assertEquals(Resources.ID_NULL, type.getBadgeLabel(0));
169         assertEquals(Resources.ID_NULL, type.getBadgeColor(0));
170         assertEquals(Resources.ID_NULL, type.getLabel());
171         assertTrue(type.getDefaultRestrictions().isEmpty());
172         assertTrue(type.getDefaultSystemSettings().isEmpty());
173         assertTrue(type.getDefaultSecureSettings().isEmpty());
174         assertTrue(type.getDefaultCrossProfileIntentFilters().isEmpty());
175 
176         assertFalse(type.hasBadge());
177     }
178 
179     @Test
testUserTypeBuilder_nameIsRequired()180     public void testUserTypeBuilder_nameIsRequired() {
181         assertThrows(IllegalArgumentException.class,
182                 () -> new UserTypeDetails.Builder()
183                         .setMaxAllowed(21)
184                         .setBaseType(FLAG_FULL)
185                         .createUserTypeDetails());
186     }
187 
188     @Test
testUserTypeBuilder_baseTypeIsRequired()189     public void testUserTypeBuilder_baseTypeIsRequired() {
190         assertThrows(IllegalArgumentException.class,
191                 () -> new UserTypeDetails.Builder()
192                         .setName("name")
193                         .createUserTypeDetails());
194     }
195 
196     @Test
testUserTypeBuilder_colorIsRequiredIfBadged()197     public void testUserTypeBuilder_colorIsRequiredIfBadged() {
198         assertThrows(IllegalArgumentException.class,
199                 () -> getMinimalBuilder()
200                         .setIconBadge(1)
201                         .setBadgeLabels(2)
202                         .createUserTypeDetails());
203     }
204 
205     @Test
testUserTypeBuilder_badgeLabelIsRequiredIfBadged()206     public void testUserTypeBuilder_badgeLabelIsRequiredIfBadged() {
207         assertThrows(IllegalArgumentException.class,
208                 () -> getMinimalBuilder()
209                         .setIconBadge(1)
210                         .setBadgeColors(2)
211                         .createUserTypeDetails());
212     }
213 
214     @Test
testCheckUserTypeConsistency()215     public void testCheckUserTypeConsistency() {
216         assertTrue(UserManagerService.checkUserTypeConsistency(FLAG_GUEST));
217         assertTrue(UserManagerService.checkUserTypeConsistency(FLAG_GUEST | FLAG_EPHEMERAL));
218         assertTrue(UserManagerService.checkUserTypeConsistency(FLAG_PROFILE));
219 
220         assertFalse(UserManagerService.checkUserTypeConsistency(FLAG_DEMO | FLAG_RESTRICTED));
221         assertFalse(UserManagerService.checkUserTypeConsistency(FLAG_PROFILE | FLAG_SYSTEM));
222         assertFalse(UserManagerService.checkUserTypeConsistency(FLAG_PROFILE | FLAG_FULL));
223     }
224 
225     @Test
testGetDefaultUserType()226     public void testGetDefaultUserType() {
227         // Simple example.
228         assertEquals(UserManager.USER_TYPE_FULL_RESTRICTED,
229                 UserInfo.getDefaultUserType(FLAG_RESTRICTED));
230 
231         // Type plus a non-type flag.
232         assertEquals(UserManager.USER_TYPE_FULL_GUEST,
233                 UserInfo.getDefaultUserType(FLAG_GUEST | FLAG_EPHEMERAL));
234 
235         // Two types, which is illegal.
236         assertThrows(IllegalArgumentException.class,
237                 () -> UserInfo.getDefaultUserType(FLAG_MANAGED_PROFILE | FLAG_GUEST));
238 
239         // No type, which defaults to {@link UserManager#USER_TYPE_FULL_SECONDARY}.
240         assertEquals(UserManager.USER_TYPE_FULL_SECONDARY,
241                 UserInfo.getDefaultUserType(FLAG_EPHEMERAL));
242     }
243 
244     /** Tests {@link UserTypeFactory#customizeBuilders} for a reasonable xml file. */
245     @Test
testUserTypeFactoryCustomize_profile()246     public void testUserTypeFactoryCustomize_profile() throws Exception {
247         final String userTypeAosp1 = "android.test.1"; // Profile user that is not customized
248         final String userTypeAosp2 = "android.test.2"; // Profile user that is customized
249         final String userTypeOem1 = "custom.test.1"; // Custom-defined profile
250 
251         // Mock some "AOSP defaults".
252         final Bundle restrictions = makeRestrictionsBundle("no_config_vpn", "no_config_tethering");
253         final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
254         builders.put(userTypeAosp1, new UserTypeDetails.Builder()
255                 .setName(userTypeAosp1)
256                 .setBaseType(FLAG_PROFILE)
257                 .setMaxAllowedPerParent(31)
258                 .setDefaultRestrictions(restrictions));
259         builders.put(userTypeAosp2, new UserTypeDetails.Builder()
260                 .setName(userTypeAosp1)
261                 .setBaseType(FLAG_PROFILE)
262                 .setMaxAllowedPerParent(32)
263                 .setIconBadge(401)
264                 .setBadgeColors(402, 403, 404)
265                 .setDefaultRestrictions(restrictions));
266 
267         final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_profile);
268         UserTypeFactory.customizeBuilders(builders, parser);
269 
270         // userTypeAosp1 should not be modified.
271         UserTypeDetails aospType = builders.get(userTypeAosp1).createUserTypeDetails();
272         assertEquals(31, aospType.getMaxAllowedPerParent());
273         assertEquals(Resources.ID_NULL, aospType.getIconBadge());
274         assertTrue(UserRestrictionsUtils.areEqual(restrictions, aospType.getDefaultRestrictions()));
275 
276         // userTypeAosp2 should be modified.
277         aospType = builders.get(userTypeAosp2).createUserTypeDetails();
278         assertEquals(12, aospType.getMaxAllowedPerParent());
279         assertEquals(com.android.internal.R.drawable.ic_corp_icon_badge_case,
280                 aospType.getIconBadge());
281         assertEquals(Resources.ID_NULL, aospType.getBadgePlain()); // No resId for 'garbage'
282         assertEquals(com.android.internal.R.drawable.ic_corp_badge_no_background,
283                 aospType.getBadgeNoBackground());
284         assertEquals(com.android.internal.R.string.managed_profile_label_badge,
285                 aospType.getBadgeLabel(0));
286         assertEquals(com.android.internal.R.string.managed_profile_label_badge_2,
287                 aospType.getBadgeLabel(1));
288         assertEquals(com.android.internal.R.string.managed_profile_label_badge_2,
289                 aospType.getBadgeLabel(2));
290         assertEquals(com.android.internal.R.string.managed_profile_label_badge_2,
291                 aospType.getBadgeLabel(3));
292         assertEquals(com.android.internal.R.color.profile_badge_1,
293                 aospType.getBadgeColor(0));
294         assertEquals(com.android.internal.R.color.profile_badge_2,
295                 aospType.getBadgeColor(1));
296         assertEquals(com.android.internal.R.color.profile_badge_2,
297                 aospType.getBadgeColor(2));
298         assertEquals(com.android.internal.R.color.profile_badge_2,
299                 aospType.getBadgeColor(3));
300         assertTrue(UserRestrictionsUtils.areEqual(
301                 makeRestrictionsBundle("no_remove_user", "no_bluetooth"),
302                 aospType.getDefaultRestrictions()));
303 
304         // userTypeOem1 should be created.
305         UserTypeDetails.Builder customType = builders.get(userTypeOem1);
306         assertNotNull(customType);
307         assertEquals(14, customType.createUserTypeDetails().getMaxAllowedPerParent());
308     }
309 
310     /** Tests {@link UserTypeFactory#customizeBuilders} for customizing a FULL user. */
311     @Test
testUserTypeFactoryCustomize_full()312     public void testUserTypeFactoryCustomize_full() throws Exception {
313         final String userTypeFull = "android.test.1";
314 
315         // Mock "AOSP default".
316         final Bundle restrictions = makeRestrictionsBundle("no_config_vpn", "no_config_tethering");
317         final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
318         builders.put(userTypeFull, new UserTypeDetails.Builder()
319                 .setName(userTypeFull)
320                 .setBaseType(FLAG_FULL)
321                 .setEnabled(0)
322                 .setDefaultRestrictions(restrictions));
323 
324         final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_full);
325         UserTypeFactory.customizeBuilders(builders, parser);
326 
327         UserTypeDetails details = builders.get(userTypeFull).createUserTypeDetails();
328         assertEquals(UNLIMITED_NUMBER_OF_USERS, details.getMaxAllowedPerParent());
329         assertFalse(details.isEnabled());
330         assertTrue(UserRestrictionsUtils.areEqual(
331                 makeRestrictionsBundle("no_remove_user", "no_bluetooth"),
332                 details.getDefaultRestrictions()));
333         assertEquals(Resources.ID_NULL, details.getBadgeColor(0));
334     }
335 
336     /**
337      * Tests {@link UserTypeFactory#customizeBuilders} when custom user type deletes the
338      * badge-colors and restrictions.
339      */
340     @Test
testUserTypeFactoryCustomize_eraseArray()341     public void testUserTypeFactoryCustomize_eraseArray() throws Exception {
342         final String typeName = "android.test";
343 
344         final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
345         builders.put(typeName, new UserTypeDetails.Builder()
346                 .setName(typeName)
347                 .setBaseType(FLAG_PROFILE)
348                 .setMaxAllowedPerParent(1)
349                 .setBadgeColors(501, 502)
350                 .setDefaultRestrictions(makeRestrictionsBundle("r1")));
351 
352         final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_eraseArray);
353         UserTypeFactory.customizeBuilders(builders, parser);
354 
355         UserTypeDetails typeDetails =  builders.get(typeName).createUserTypeDetails();
356         assertEquals(2, typeDetails.getMaxAllowedPerParent());
357         assertEquals(Resources.ID_NULL, typeDetails.getBadgeColor(0));
358         assertEquals(Resources.ID_NULL, typeDetails.getBadgeColor(1));
359         assertTrue(typeDetails.getDefaultRestrictions().isEmpty());
360     }
361 
362     /** Tests {@link UserTypeFactory#customizeBuilders} when custom user type has illegal name. */
363     @Test
testUserTypeFactoryCustomize_illegalOemName()364     public void testUserTypeFactoryCustomize_illegalOemName() throws Exception {
365         final String userTypeAosp = "android.aosp.legal";
366         final String userTypeOem = "android.oem.illegal.name"; // Custom-defined profile
367 
368         final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
369         builders.put(userTypeAosp, new UserTypeDetails.Builder()
370                 .setName(userTypeAosp)
371                 .setBaseType(FLAG_PROFILE)
372                 .setMaxAllowedPerParent(21));
373 
374         final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_illegalOemName);
375 
376         // parser is illegal because non-AOSP user types cannot be prefixed with "android.".
377         assertThrows(IllegalArgumentException.class,
378                 () -> UserTypeFactory.customizeBuilders(builders, parser));
379     }
380 
381     /**
382      * Tests {@link UserTypeFactory#customizeBuilders} when illegally customizing a non-profile as
383      * a profile.
384      */
385     @Test
testUserTypeFactoryCustomize_illegalUserBaseType()386     public void testUserTypeFactoryCustomize_illegalUserBaseType() throws Exception {
387         final String userTypeFull = "android.test";
388 
389         final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
390         builders.put(userTypeFull, new UserTypeDetails.Builder()
391                 .setName(userTypeFull)
392                 .setBaseType(FLAG_FULL)
393                 .setMaxAllowedPerParent(21));
394 
395         XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_illegalUserBaseType);
396 
397         // parser is illegal because userTypeFull is FULL but the tag is for profile-type.
398         assertThrows(IllegalArgumentException.class,
399                 () -> UserTypeFactory.customizeBuilders(builders, parser));
400     }
401 
402     @Test
testUserTypeFactoryVersion_versionMissing()403     public void testUserTypeFactoryVersion_versionMissing() {
404         final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_eraseArray);
405         assertEquals(0, UserTypeFactory.getUserTypeVersion(parser));
406     }
407 
408     @Test
testUserTypeFactoryVersion_versionPresent()409     public void testUserTypeFactoryVersion_versionPresent() {
410         final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_profile);
411         assertEquals(1234, UserTypeFactory.getUserTypeVersion(parser));
412     }
413 
414     @Test
testUserTypeFactoryUpgrades_validUpgrades()415     public void testUserTypeFactoryUpgrades_validUpgrades() {
416         final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
417         builders.put("name", getMinimalBuilder());
418 
419         final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_profile);
420         List<UserTypeFactory.UserTypeUpgrade> upgrades = UserTypeFactory.parseUserUpgrades(builders,
421                 parser);
422 
423         assertFalse(upgrades.isEmpty());
424         UserTypeFactory.UserTypeUpgrade upgrade = upgrades.get(0);
425         assertEquals("android.test.1", upgrade.getFromType());
426         assertEquals("android.test.2", upgrade.getToType());
427         assertEquals(1233, upgrade.getUpToVersion());
428     }
429 
430     @Test
testUserTypeFactoryUpgrades_illegalBaseTypeUpgrade()431     public void testUserTypeFactoryUpgrades_illegalBaseTypeUpgrade() {
432         final String userTypeFull = "android.test.1";
433         final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
434         builders.put(userTypeFull, new UserTypeDetails.Builder()
435                 .setName(userTypeFull)
436                 .setBaseType(FLAG_FULL));
437 
438         final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_full);
439 
440         // parser is illegal because the "to" upgrade type is not a profile, but a full user
441         assertThrows(IllegalArgumentException.class,
442                 () -> UserTypeFactory.parseUserUpgrades(builders, parser));
443     }
444 
445     /** Returns a minimal {@link UserTypeDetails.Builder} that can legitimately be created. */
getMinimalBuilder()446     private UserTypeDetails.Builder getMinimalBuilder() {
447         return new UserTypeDetails.Builder().setName("name").setBaseType(FLAG_FULL);
448     }
449 
450     /** Creates a Bundle of the given String restrictions, each set to true. */
makeRestrictionsBundle(String .... restrictions)451     public static Bundle makeRestrictionsBundle(String ... restrictions) {
452         final Bundle bundle = new Bundle();
453         for (String restriction : restrictions) {
454             bundle.putBoolean(restriction, true);
455         }
456         return bundle;
457     }
458 
459     /** Creates a Bundle of the given settings keys and puts true for the value. */
makeSettingsBundle(String .... settings)460     private static Bundle makeSettingsBundle(String ... settings) {
461         final Bundle bundle = new Bundle();
462         for (String setting : settings) {
463             bundle.putBoolean(setting, true);
464         }
465         return bundle;
466     }
467 }
468