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