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