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_ADMIN; 20 import static android.content.pm.UserInfo.FLAG_DEMO; 21 import static android.content.pm.UserInfo.FLAG_EPHEMERAL; 22 import static android.content.pm.UserInfo.FLAG_FULL; 23 import static android.content.pm.UserInfo.FLAG_GUEST; 24 import static android.content.pm.UserInfo.FLAG_MAIN; 25 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE; 26 import static android.content.pm.UserInfo.FLAG_PRIMARY; 27 import static android.content.pm.UserInfo.FLAG_PROFILE; 28 import static android.content.pm.UserInfo.FLAG_RESTRICTED; 29 import static android.content.pm.UserInfo.FLAG_SYSTEM; 30 import static android.os.UserManager.USER_TYPE_FULL_DEMO; 31 import static android.os.UserManager.USER_TYPE_FULL_GUEST; 32 import static android.os.UserManager.USER_TYPE_FULL_RESTRICTED; 33 import static android.os.UserManager.USER_TYPE_FULL_SECONDARY; 34 import static android.os.UserManager.USER_TYPE_FULL_SYSTEM; 35 import static android.os.UserManager.USER_TYPE_PROFILE_CLONE; 36 import static android.os.UserManager.USER_TYPE_PROFILE_COMMUNAL; 37 import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED; 38 import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE; 39 import static android.os.UserManager.USER_TYPE_PROFILE_SUPERVISING; 40 import static android.os.UserManager.USER_TYPE_PROFILE_TEST; 41 import static android.os.UserManager.USER_TYPE_SYSTEM_HEADLESS; 42 43 import static com.android.server.pm.UserTypeDetails.UNLIMITED_NUMBER_OF_USERS; 44 45 import android.content.pm.UserInfo; 46 import android.content.pm.UserProperties; 47 import android.content.res.Resources; 48 import android.content.res.XmlResourceParser; 49 import android.os.Build; 50 import android.os.Bundle; 51 import android.os.UserManager; 52 import android.util.ArrayMap; 53 import android.util.Slog; 54 55 import com.android.internal.R; 56 import com.android.internal.annotations.VisibleForTesting; 57 import com.android.internal.util.XmlUtils; 58 59 import org.xmlpull.v1.XmlPullParserException; 60 61 import java.io.IOException; 62 import java.util.ArrayList; 63 import java.util.List; 64 import java.util.function.Consumer; 65 66 /** 67 * Class for creating all {@link UserTypeDetails} on the device. 68 * 69 * This class is responsible both for defining the AOSP use types, as well as reading in customized 70 * user types from {@link com.android.internal.R.xml#config_user_types}. 71 * 72 * Tests are located in {@link UserManagerServiceUserTypeTest}. 73 * @hide 74 */ 75 public final class UserTypeFactory { 76 77 private static final String LOG_TAG = "UserTypeFactory"; 78 79 /** This is a utility class, so no instantiable constructor. */ UserTypeFactory()80 private UserTypeFactory() {} 81 82 /** 83 * Obtains the user types (built-in and customized) for this device. 84 * 85 * @return mapping from the name of each user type to its {@link UserTypeDetails} object 86 */ getUserTypes()87 public static ArrayMap<String, UserTypeDetails> getUserTypes() { 88 final ArrayMap<String, UserTypeDetails.Builder> builders = getDefaultBuilders(); 89 90 try (XmlResourceParser parser = 91 Resources.getSystem().getXml(com.android.internal.R.xml.config_user_types)) { 92 customizeBuilders(builders, parser); 93 } 94 95 final ArrayMap<String, UserTypeDetails> types = new ArrayMap<>(builders.size()); 96 for (int i = 0; i < builders.size(); i++) { 97 types.put(builders.keyAt(i), builders.valueAt(i).createUserTypeDetails()); 98 } 99 return types; 100 } 101 getDefaultBuilders()102 private static ArrayMap<String, UserTypeDetails.Builder> getDefaultBuilders() { 103 final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>(); 104 105 builders.put(USER_TYPE_PROFILE_MANAGED, getDefaultTypeProfileManaged()); 106 builders.put(USER_TYPE_FULL_SYSTEM, getDefaultTypeFullSystem()); 107 builders.put(USER_TYPE_FULL_SECONDARY, getDefaultTypeFullSecondary()); 108 builders.put(USER_TYPE_FULL_GUEST, getDefaultTypeFullGuest()); 109 builders.put(USER_TYPE_FULL_DEMO, getDefaultTypeFullDemo()); 110 builders.put(USER_TYPE_FULL_RESTRICTED, getDefaultTypeFullRestricted()); 111 builders.put(USER_TYPE_SYSTEM_HEADLESS, getDefaultTypeSystemHeadless()); 112 builders.put(USER_TYPE_PROFILE_CLONE, getDefaultTypeProfileClone()); 113 builders.put(USER_TYPE_PROFILE_COMMUNAL, getDefaultTypeProfileCommunal()); 114 builders.put(USER_TYPE_PROFILE_PRIVATE, getDefaultTypeProfilePrivate()); 115 builders.put(USER_TYPE_PROFILE_SUPERVISING, getDefaultTypeProfileSupervising()); 116 if (Build.IS_DEBUGGABLE) { 117 builders.put(USER_TYPE_PROFILE_TEST, getDefaultTypeProfileTest()); 118 } 119 120 return builders; 121 } 122 123 /** 124 * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_CLONE} 125 * configuration. 126 */ 127 // TODO(b/182396009): Add default restrictions, if needed for clone user type. getDefaultTypeProfileClone()128 private static UserTypeDetails.Builder getDefaultTypeProfileClone() { 129 return new UserTypeDetails.Builder() 130 .setName(USER_TYPE_PROFILE_CLONE) 131 .setBaseType(FLAG_PROFILE) 132 .setMaxAllowedPerParent(1) 133 .setProfileParentRequired(true) 134 .setLabels(R.string.profile_label_clone) 135 .setIconBadge(com.android.internal.R.drawable.ic_clone_icon_badge) 136 .setBadgePlain(com.android.internal.R.drawable.ic_clone_badge) 137 // Clone doesn't use BadgeNoBackground, so just set to BadgePlain as a placeholder. 138 .setBadgeNoBackground(com.android.internal.R.drawable.ic_clone_badge) 139 .setStatusBarIcon(Resources.ID_NULL) 140 .setBadgeLabels( 141 com.android.internal.R.string.clone_profile_label_badge) 142 .setBadgeColors( 143 com.android.internal.R.color.system_neutral2_800) 144 .setDarkThemeBadgeColors( 145 com.android.internal.R.color.system_neutral2_900) 146 .setAccessibilityString(com.android.internal 147 .R.string.accessibility_label_clone_profile) 148 .setDefaultRestrictions(null) 149 .setDefaultCrossProfileIntentFilters(getDefaultCloneCrossProfileIntentFilter()) 150 .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings()) 151 .setDefaultUserProperties(new UserProperties.Builder() 152 .setStartWithParent(true) 153 .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_WITH_PARENT) 154 .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_WITH_PARENT) 155 .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT) 156 .setUseParentsContacts(true) 157 .setUpdateCrossProfileIntentFiltersOnOTA(true) 158 .setCrossProfileIntentFilterAccessControl( 159 UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM) 160 .setCrossProfileIntentResolutionStrategy(UserProperties 161 .CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING) 162 .setShowInQuietMode( 163 UserProperties.SHOW_IN_QUIET_MODE_DEFAULT) 164 .setShowInSharingSurfaces( 165 UserProperties.SHOW_IN_SHARING_SURFACES_WITH_PARENT) 166 .setMediaSharedWithParent(true) 167 .setCredentialShareableWithParent(true) 168 .setDeleteAppWithParent(true) 169 .setCrossProfileContentSharingStrategy(UserProperties 170 .CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT)); 171 } 172 173 /** 174 * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_MANAGED} 175 * configuration. 176 */ getDefaultTypeProfileManaged()177 private static UserTypeDetails.Builder getDefaultTypeProfileManaged() { 178 return new UserTypeDetails.Builder() 179 .setName(USER_TYPE_PROFILE_MANAGED) 180 .setBaseType(FLAG_PROFILE) 181 .setDefaultUserInfoPropertyFlags(FLAG_MANAGED_PROFILE) 182 .setMaxAllowedPerParent(1) 183 .setProfileParentRequired(true) 184 .setLabels( 185 R.string.profile_label_work, 186 R.string.profile_label_work_2, 187 R.string.profile_label_work_3) 188 .setIconBadge(com.android.internal.R.drawable.ic_corp_icon_badge_case) 189 .setBadgePlain(com.android.internal.R.drawable.ic_corp_badge_case) 190 .setBadgeNoBackground(com.android.internal.R.drawable.ic_corp_badge_no_background) 191 .setStatusBarIcon(com.android.internal.R.drawable.stat_sys_managed_profile_status) 192 .setBadgeLabels( 193 com.android.internal.R.string.managed_profile_label_badge, 194 com.android.internal.R.string.managed_profile_label_badge_2, 195 com.android.internal.R.string.managed_profile_label_badge_3) 196 .setBadgeColors( 197 com.android.internal.R.color.profile_badge_1, 198 com.android.internal.R.color.profile_badge_2, 199 com.android.internal.R.color.profile_badge_3) 200 .setDarkThemeBadgeColors( 201 com.android.internal.R.color.profile_badge_1_dark, 202 com.android.internal.R.color.profile_badge_2_dark, 203 com.android.internal.R.color.profile_badge_3_dark) 204 .setAccessibilityString(com.android.internal 205 .R.string.accessibility_label_managed_profile) 206 .setDefaultRestrictions(getDefaultProfileRestrictions()) 207 .setDefaultSecureSettings(getDefaultManagedProfileSecureSettings()) 208 .setDefaultCrossProfileIntentFilters(getDefaultManagedCrossProfileIntentFilter()) 209 .setDefaultUserProperties(new UserProperties.Builder() 210 .setStartWithParent(true) 211 .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE) 212 .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE) 213 .setShowInQuietMode( 214 UserProperties.SHOW_IN_QUIET_MODE_PAUSED) 215 .setShowInSharingSurfaces( 216 UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE) 217 .setAuthAlwaysRequiredToDisableQuietMode(false) 218 .setCredentialShareableWithParent(true)); 219 } 220 221 /** 222 * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_TEST} 223 * configuration (for userdebug builds). For now it just uses managed profile badges. 224 */ getDefaultTypeProfileTest()225 private static UserTypeDetails.Builder getDefaultTypeProfileTest() { 226 final Bundle restrictions = getDefaultProfileRestrictions(); 227 restrictions.putBoolean(UserManager.DISALLOW_FUN, true); 228 229 return new UserTypeDetails.Builder() 230 .setName(USER_TYPE_PROFILE_TEST) 231 .setBaseType(FLAG_PROFILE) 232 .setMaxAllowedPerParent(2) 233 .setProfileParentRequired(true) 234 .setLabels( 235 R.string.profile_label_test, 236 R.string.profile_label_test, 237 R.string.profile_label_test) 238 .setIconBadge(com.android.internal.R.drawable.ic_test_icon_badge_experiment) 239 .setBadgePlain(com.android.internal.R.drawable.ic_test_badge_experiment) 240 .setBadgeNoBackground(com.android.internal.R.drawable.ic_test_badge_no_background) 241 .setStatusBarIcon(com.android.internal.R.drawable.ic_test_badge_experiment) 242 .setBadgeLabels( 243 com.android.internal.R.string.managed_profile_label_badge, 244 com.android.internal.R.string.managed_profile_label_badge_2, 245 com.android.internal.R.string.managed_profile_label_badge_3) 246 .setBadgeColors( 247 com.android.internal.R.color.profile_badge_1, 248 com.android.internal.R.color.profile_badge_2, 249 com.android.internal.R.color.profile_badge_3) 250 .setDarkThemeBadgeColors( 251 com.android.internal.R.color.profile_badge_1_dark, 252 com.android.internal.R.color.profile_badge_2_dark, 253 com.android.internal.R.color.profile_badge_3_dark) 254 .setDefaultRestrictions(restrictions) 255 .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings()); 256 } 257 258 /** 259 * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_COMMUNAL} 260 * configuration. For now it just uses managed profile badges. 261 */ getDefaultTypeProfileCommunal()262 private static UserTypeDetails.Builder getDefaultTypeProfileCommunal() { 263 return new UserTypeDetails.Builder() 264 .setName(USER_TYPE_PROFILE_COMMUNAL) 265 .setBaseType(FLAG_PROFILE) 266 .setMaxAllowed(1) 267 .setProfileParentRequired(false) 268 .setEnabled(UserManager.isCommunalProfileEnabled() ? 1 : 0) 269 .setLabels(R.string.profile_label_communal) 270 .setIconBadge(com.android.internal.R.drawable.ic_test_icon_badge_experiment) 271 .setBadgePlain(com.android.internal.R.drawable.ic_test_badge_experiment) 272 .setBadgeNoBackground(com.android.internal.R.drawable.ic_test_badge_no_background) 273 .setStatusBarIcon(com.android.internal.R.drawable.ic_test_badge_experiment) 274 .setBadgeLabels( 275 com.android.internal.R.string.managed_profile_label_badge, 276 com.android.internal.R.string.managed_profile_label_badge_2, 277 com.android.internal.R.string.managed_profile_label_badge_3) 278 .setBadgeColors( 279 com.android.internal.R.color.profile_badge_1, 280 com.android.internal.R.color.profile_badge_2, 281 com.android.internal.R.color.profile_badge_3) 282 .setDarkThemeBadgeColors( 283 com.android.internal.R.color.profile_badge_1_dark, 284 com.android.internal.R.color.profile_badge_2_dark, 285 com.android.internal.R.color.profile_badge_3_dark) 286 .setDefaultRestrictions(getDefaultProfileRestrictions()) 287 .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings()) 288 .setDefaultUserProperties(new UserProperties.Builder() 289 .setStartWithParent(false) 290 .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE) 291 .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE) 292 .setCredentialShareableWithParent(false) 293 .setAlwaysVisible(true)); 294 } 295 296 /** 297 * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_PRIVATE} 298 * configuration. 299 */ getDefaultTypeProfilePrivate()300 private static UserTypeDetails.Builder getDefaultTypeProfilePrivate() { 301 return new UserTypeDetails.Builder() 302 .setName(USER_TYPE_PROFILE_PRIVATE) 303 .setBaseType(FLAG_PROFILE) 304 .setProfileParentRequired(true) 305 .setMaxAllowedPerParent(1) 306 .setEnabled(UserManager.isPrivateProfileEnabled() ? 1 : 0) 307 .setLabels(R.string.profile_label_private) 308 .setIconBadge(com.android.internal.R.drawable.ic_private_profile_icon_badge) 309 .setBadgePlain(com.android.internal.R.drawable.ic_private_profile_badge) 310 // Private Profile doesn't use BadgeNoBackground, so just set to BadgePlain 311 // as a placeholder. 312 .setBadgeNoBackground(com.android.internal.R.drawable.ic_private_profile_badge) 313 .setStatusBarIcon(com.android.internal.R.drawable.stat_sys_private_profile_status) 314 .setBadgeLabels( 315 com.android.internal.R.string.private_profile_label_badge) 316 .setBadgeColors( 317 R.color.black) 318 .setDarkThemeBadgeColors( 319 R.color.white) 320 .setAccessibilityString(com.android.internal 321 .R.string.accessibility_label_private_profile) 322 .setDefaultRestrictions(getDefaultPrivateProfileRestrictions()) 323 .setDefaultCrossProfileIntentFilters(getDefaultPrivateCrossProfileIntentFilter()) 324 .setDefaultUserProperties(new UserProperties.Builder() 325 .setStartWithParent(true) 326 .setCredentialShareableWithParent(true) 327 .setAuthAlwaysRequiredToDisableQuietMode(true) 328 .setAllowStoppingUserWithDelayedLocking(true) 329 .setMediaSharedWithParent(false) 330 .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE) 331 .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE) 332 .setShowInQuietMode( 333 UserProperties.SHOW_IN_QUIET_MODE_HIDDEN) 334 .setShowInSharingSurfaces( 335 UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE) 336 .setCrossProfileIntentFilterAccessControl( 337 UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM) 338 .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT) 339 .setCrossProfileContentSharingStrategy( 340 UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT) 341 .setProfileApiVisibility( 342 UserProperties.PROFILE_API_VISIBILITY_HIDDEN) 343 .setItemsRestrictedOnHomeScreen(true) 344 .setUpdateCrossProfileIntentFiltersOnOTA(true)); 345 } 346 347 /** 348 * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_SUPERVISING} 349 * configuration. 350 */ getDefaultTypeProfileSupervising()351 private static UserTypeDetails.Builder getDefaultTypeProfileSupervising() { 352 return new UserTypeDetails.Builder() 353 .setName(USER_TYPE_PROFILE_SUPERVISING) 354 .setBaseType(FLAG_PROFILE) 355 .setMaxAllowed(1) 356 .setProfileParentRequired(false) 357 .setEnabled(android.multiuser.Flags.allowSupervisingProfile() ? 1 : 0) 358 .setLabels(R.string.profile_label_supervising) 359 .setDefaultRestrictions(getDefaultSupervisingProfileRestrictions()) 360 .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings()) 361 .setDefaultUserProperties(new UserProperties.Builder() 362 .setStartWithParent(false) 363 .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_NO) 364 .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_NO) 365 .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_HIDDEN) 366 .setCredentialShareableWithParent(false) 367 .setAlwaysVisible(true)); 368 } 369 370 /** 371 * Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_SECONDARY} 372 * configuration. 373 */ getDefaultTypeFullSecondary()374 private static UserTypeDetails.Builder getDefaultTypeFullSecondary() { 375 return new UserTypeDetails.Builder() 376 .setName(USER_TYPE_FULL_SECONDARY) 377 .setBaseType(FLAG_FULL) 378 .setMaxAllowed(UNLIMITED_NUMBER_OF_USERS) 379 .setDefaultRestrictions(getDefaultSecondaryUserRestrictions()); 380 } 381 382 /** 383 * Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_GUEST} configuration. 384 */ getDefaultTypeFullGuest()385 private static UserTypeDetails.Builder getDefaultTypeFullGuest() { 386 final boolean ephemeralGuests = Resources.getSystem() 387 .getBoolean(com.android.internal.R.bool.config_guestUserEphemeral); 388 final int flags = FLAG_GUEST | (ephemeralGuests ? FLAG_EPHEMERAL : 0); 389 390 return new UserTypeDetails.Builder() 391 .setName(USER_TYPE_FULL_GUEST) 392 .setBaseType(FLAG_FULL) 393 .setDefaultUserInfoPropertyFlags(flags) 394 .setMaxAllowed(1) 395 .setDefaultRestrictions(getDefaultGuestUserRestrictions()); 396 } 397 398 /** 399 * Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_DEMO} configuration. 400 */ getDefaultTypeFullDemo()401 private static UserTypeDetails.Builder getDefaultTypeFullDemo() { 402 return new UserTypeDetails.Builder() 403 .setName(USER_TYPE_FULL_DEMO) 404 .setBaseType(FLAG_FULL) 405 .setDefaultUserInfoPropertyFlags(FLAG_DEMO) 406 .setMaxAllowed(UNLIMITED_NUMBER_OF_USERS) 407 .setDefaultRestrictions(null); 408 } 409 410 /** 411 * Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_RESTRICTED} 412 * configuration. 413 */ getDefaultTypeFullRestricted()414 private static UserTypeDetails.Builder getDefaultTypeFullRestricted() { 415 return new UserTypeDetails.Builder() 416 .setName(USER_TYPE_FULL_RESTRICTED) 417 .setBaseType(FLAG_FULL) 418 .setDefaultUserInfoPropertyFlags(FLAG_RESTRICTED) 419 .setMaxAllowed(UNLIMITED_NUMBER_OF_USERS) 420 .setProfileParentRequired(false) // they have a "parent", but not a profile parent 421 // NB: UserManagerService.createRestrictedProfile() applies hardcoded restrictions. 422 .setDefaultRestrictions(null); 423 } 424 425 /** 426 * Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_SYSTEM} configuration. 427 */ getDefaultTypeFullSystem()428 private static UserTypeDetails.Builder getDefaultTypeFullSystem() { 429 return new UserTypeDetails.Builder() 430 .setName(USER_TYPE_FULL_SYSTEM) 431 .setBaseType(FLAG_SYSTEM | FLAG_FULL) 432 .setDefaultUserInfoPropertyFlags(FLAG_PRIMARY | FLAG_ADMIN | FLAG_MAIN) 433 .setMaxAllowed(1); 434 } 435 436 /** 437 * Returns the Builder for the default {@link UserManager#USER_TYPE_SYSTEM_HEADLESS} 438 * configuration. 439 */ getDefaultTypeSystemHeadless()440 private static UserTypeDetails.Builder getDefaultTypeSystemHeadless() { 441 return new UserTypeDetails.Builder() 442 .setName(USER_TYPE_SYSTEM_HEADLESS) 443 .setBaseType(FLAG_SYSTEM) 444 .setDefaultUserInfoPropertyFlags(FLAG_PRIMARY | FLAG_ADMIN) 445 .setMaxAllowed(1); 446 } 447 getDefaultSecondaryUserRestrictions()448 private static Bundle getDefaultSecondaryUserRestrictions() { 449 final Bundle restrictions = new Bundle(); 450 restrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true); 451 restrictions.putBoolean(UserManager.DISALLOW_SMS, true); 452 return restrictions; 453 } 454 getDefaultGuestUserRestrictions()455 private static Bundle getDefaultGuestUserRestrictions() { 456 // Guest inherits the secondary user's restrictions, plus has some extra ones. 457 final Bundle restrictions = getDefaultSecondaryUserRestrictions(); 458 restrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, true); 459 restrictions.putBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true); 460 restrictions.putBoolean(UserManager.DISALLOW_CONFIG_CREDENTIALS, true); 461 return restrictions; 462 } 463 getDefaultProfileRestrictions()464 private static Bundle getDefaultProfileRestrictions() { 465 final Bundle restrictions = new Bundle(); 466 restrictions.putBoolean(UserManager.DISALLOW_WALLPAPER, true); 467 return restrictions; 468 } 469 470 @VisibleForTesting getDefaultPrivateProfileRestrictions()471 static Bundle getDefaultPrivateProfileRestrictions() { 472 final Bundle restrictions = getDefaultProfileRestrictions(); 473 restrictions.putBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING, true); 474 return restrictions; 475 } 476 getDefaultSupervisingProfileRestrictions()477 private static Bundle getDefaultSupervisingProfileRestrictions() { 478 final Bundle restrictions = getDefaultProfileRestrictions(); 479 restrictions.putBoolean(UserManager.DISALLOW_INSTALL_APPS, true); 480 return restrictions; 481 } 482 getDefaultManagedProfileSecureSettings()483 private static Bundle getDefaultManagedProfileSecureSettings() { 484 // Only add String values to the bundle, settings are written as Strings eventually 485 final Bundle settings = new Bundle(); 486 settings.putString( 487 android.provider.Settings.Secure.MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, "1"); 488 settings.putString( 489 android.provider.Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED, "1"); 490 return settings; 491 } 492 493 private static List<DefaultCrossProfileIntentFilter> getDefaultManagedCrossProfileIntentFilter()494 getDefaultManagedCrossProfileIntentFilter() { 495 return DefaultCrossProfileIntentFiltersUtils.getDefaultManagedProfileFilters(); 496 } 497 getDefaultCloneCrossProfileIntentFilter()498 private static List<DefaultCrossProfileIntentFilter> getDefaultCloneCrossProfileIntentFilter() { 499 return DefaultCrossProfileIntentFiltersUtils.getDefaultCloneProfileFilters(); 500 } 501 getDefaultPrivateCrossProfileIntentFilter()502 private static List<DefaultCrossProfileIntentFilter> getDefaultPrivateCrossProfileIntentFilter() 503 { 504 return DefaultCrossProfileIntentFiltersUtils.getDefaultPrivateProfileFilters(); 505 } 506 507 /** Gets a default bundle, keyed by Settings.Secure String names, for non-managed profiles. */ getDefaultNonManagedProfileSecureSettings()508 private static Bundle getDefaultNonManagedProfileSecureSettings() { 509 final Bundle settings = new Bundle(); 510 // Non-managed profiles go through neither SetupWizard nor DPC flows, so we automatically 511 // mark them as setup. 512 settings.putString(android.provider.Settings.Secure.USER_SETUP_COMPLETE, "1"); 513 return settings; 514 } 515 516 /** 517 * Reads the given xml parser to obtain device user-type customization, and updates the given 518 * map of {@link UserTypeDetails.Builder}s accordingly. 519 * <p> 520 * The xml file can specify the attributes according to the set... methods below. 521 */ 522 // TODO(b/176973369): Add parsing logic to support custom settings/filters 523 // in config_user_types.xml 524 @VisibleForTesting customizeBuilders(ArrayMap<String, UserTypeDetails.Builder> builders, XmlResourceParser parser)525 static void customizeBuilders(ArrayMap<String, UserTypeDetails.Builder> builders, 526 XmlResourceParser parser) { 527 try { 528 XmlUtils.beginDocument(parser, "user-types"); 529 for (XmlUtils.nextElement(parser); 530 parser.getEventType() != XmlResourceParser.END_DOCUMENT; 531 XmlUtils.nextElement(parser)) { 532 final boolean isProfile; 533 final String elementName = parser.getName(); 534 if ("profile-type".equals(elementName)) { 535 isProfile = true; 536 } else if ("full-type".equals(elementName)) { 537 isProfile = false; 538 } else if ("change-user-type".equals(elementName)) { 539 // parsed in parseUserUpgrades 540 XmlUtils.skipCurrentTag(parser); 541 continue; 542 } else { 543 Slog.w(LOG_TAG, "Skipping unknown element " + elementName + " in " 544 + parser.getPositionDescription()); 545 XmlUtils.skipCurrentTag(parser); 546 continue; 547 } 548 549 String typeName = parser.getAttributeValue(null, "name"); 550 if (typeName == null || typeName.equals("")) { 551 Slog.w(LOG_TAG, "Skipping user type with no name in " 552 + parser.getPositionDescription()); 553 XmlUtils.skipCurrentTag(parser); 554 continue; 555 } 556 typeName = typeName.intern(); 557 558 UserTypeDetails.Builder builder; 559 if (typeName.startsWith("android.")) { 560 // typeName refers to a AOSP-defined type which we are modifying. 561 Slog.i(LOG_TAG, "Customizing user type " + typeName); 562 builder = builders.get(typeName); 563 if (builder == null) { 564 throw new IllegalArgumentException("Illegal custom user type name " 565 + typeName + ": Non-AOSP user types cannot start with 'android.'"); 566 } 567 final boolean isValid = 568 (isProfile && builder.getBaseType() == UserInfo.FLAG_PROFILE) 569 || (!isProfile && builder.getBaseType() == UserInfo.FLAG_FULL); 570 if (!isValid) { 571 throw new IllegalArgumentException("Wrong base type to customize user type " 572 + "(" + typeName + "), which is type " 573 + UserInfo.flagsToString(builder.getBaseType())); 574 } 575 } else if (isProfile) { 576 // typeName refers to a new OEM-defined profile type which we are defining. 577 Slog.i(LOG_TAG, "Creating custom user type " + typeName); 578 builder = new UserTypeDetails.Builder(); 579 builder.setName(typeName); 580 builder.setBaseType(FLAG_PROFILE); 581 // Custom parentless profiles are not yet supported. 582 builder.setProfileParentRequired(true); 583 builders.put(typeName, builder); 584 } else { 585 throw new IllegalArgumentException("Creation of non-profile user type " 586 + "(" + typeName + ") is not currently supported."); 587 } 588 589 // Process the attributes (other than name). 590 if (isProfile) { 591 setIntAttribute(parser, "max-allowed-per-parent", 592 builder::setMaxAllowedPerParent); 593 setResAttribute(parser, "icon-badge", builder::setIconBadge); 594 setResAttribute(parser, "badge-plain", builder::setBadgePlain); 595 setResAttribute(parser, "badge-no-background", builder::setBadgeNoBackground); 596 setResAttribute(parser, "status-bar-icon", builder::setStatusBarIcon); 597 } 598 599 setIntAttribute(parser, "enabled", builder::setEnabled); 600 setIntAttribute(parser, "max-allowed", builder::setMaxAllowed); 601 602 // Process child elements. 603 final int depth = parser.getDepth(); 604 while (XmlUtils.nextElementWithin(parser, depth)) { 605 final String childName = parser.getName(); 606 if ("default-restrictions".equals(childName)) { 607 final Bundle restrictions = UserRestrictionsUtils 608 .readRestrictions(XmlUtils.makeTyped(parser)); 609 builder.setDefaultRestrictions(restrictions); 610 } else if (isProfile && "badge-labels".equals(childName)) { 611 setResAttributeArray(parser, builder::setBadgeLabels); 612 } else if (isProfile && "badge-colors".equals(childName)) { 613 setResAttributeArray(parser, builder::setBadgeColors); 614 } else if (isProfile && "badge-colors-dark".equals(childName)) { 615 setResAttributeArray(parser, builder::setDarkThemeBadgeColors); 616 } else if ("user-properties".equals(childName)) { 617 builder.getDefaultUserProperties() 618 .updateFromXml(XmlUtils.makeTyped(parser)); 619 } else { 620 Slog.w(LOG_TAG, "Unrecognized tag " + childName + " in " 621 + parser.getPositionDescription()); 622 } 623 } 624 } 625 } catch (XmlPullParserException | IOException e) { 626 Slog.w(LOG_TAG, "Cannot read user type configuration file.", e); 627 } 628 } 629 630 /** 631 * If the given attribute exists, gets the int stored in it and performs the given fcn using it. 632 * The stored value must be an int or NumberFormatException will be thrown. 633 * 634 * @param parser xml parser from which to read the attribute 635 * @param attributeName name of the attribute 636 * @param fcn one-int-argument function, 637 * like {@link UserTypeDetails.Builder#setMaxAllowedPerParent(int)} 638 */ setIntAttribute(XmlResourceParser parser, String attributeName, Consumer<Integer> fcn)639 private static void setIntAttribute(XmlResourceParser parser, String attributeName, 640 Consumer<Integer> fcn) { 641 final String intValue = parser.getAttributeValue(null, attributeName); 642 if (intValue == null) { 643 return; 644 } 645 try { 646 fcn.accept(Integer.parseInt(intValue)); 647 } catch (NumberFormatException e) { 648 Slog.e(LOG_TAG, "Cannot parse value of '" + intValue + "' for " + attributeName 649 + " in " + parser.getPositionDescription(), e); 650 throw e; 651 } 652 } 653 654 /** 655 * If the given attribute exists, gets the resId stored in it (or 0 if it is not a valid resId) 656 * and performs the given fcn using it. 657 * 658 * @param parser xml parser from which to read the attribute 659 * @param attributeName name of the attribute 660 * @param fcn one-argument function, like {@link UserTypeDetails.Builder#setIconBadge(int)} 661 */ setResAttribute(XmlResourceParser parser, String attributeName, Consumer<Integer> fcn)662 private static void setResAttribute(XmlResourceParser parser, String attributeName, 663 Consumer<Integer> fcn) { 664 if (parser.getAttributeValue(null, attributeName) == null) { 665 // Attribute is not present, i.e. use the default value. 666 return; 667 } 668 final int resId = parser.getAttributeResourceValue(null, attributeName, Resources.ID_NULL); 669 fcn.accept(resId); 670 } 671 672 /** 673 * Gets the resIds stored in "item" elements (in their "res" attribute) at the current depth. 674 * Then performs the given fcn using the int[] array of these resIds. 675 * <p> 676 * Each xml element is expected to be of the form {@code <item res="someResValue" />}. 677 * 678 * @param parser xml parser from which to read the elements and their attributes 679 * @param fcn function, like {@link UserTypeDetails.Builder#setBadgeColors(int...)} 680 */ setResAttributeArray(XmlResourceParser parser, Consumer<int[]> fcn)681 private static void setResAttributeArray(XmlResourceParser parser, Consumer<int[]> fcn) 682 throws IOException, XmlPullParserException { 683 684 ArrayList<Integer> resList = new ArrayList<>(); 685 final int depth = parser.getDepth(); 686 while (XmlUtils.nextElementWithin(parser, depth)) { 687 final String elementName = parser.getName(); 688 if (!"item".equals(elementName)) { 689 Slog.w(LOG_TAG, "Skipping unknown child element " + elementName + " in " 690 + parser.getPositionDescription()); 691 XmlUtils.skipCurrentTag(parser); 692 continue; 693 } 694 final int resId = parser.getAttributeResourceValue(null, "res", -1); 695 if (resId == -1) { 696 continue; 697 } 698 resList.add(resId); 699 } 700 701 int[] result = new int[resList.size()]; 702 for (int i = 0; i < resList.size(); i++) { 703 result[i] = resList.get(i); 704 } 705 fcn.accept(result); 706 } 707 708 /** 709 * Returns the user type version of the config XML file. 710 * @return user type version defined in XML file, 0 if none. 711 */ getUserTypeVersion()712 public static int getUserTypeVersion() { 713 try (XmlResourceParser parser = 714 Resources.getSystem().getXml(com.android.internal.R.xml.config_user_types)) { 715 return getUserTypeVersion(parser); 716 } 717 } 718 719 @VisibleForTesting getUserTypeVersion(XmlResourceParser parser)720 static int getUserTypeVersion(XmlResourceParser parser) { 721 int version = 0; 722 723 try { 724 XmlUtils.beginDocument(parser, "user-types"); 725 String versionValue = parser.getAttributeValue(null, "version"); 726 if (versionValue != null) { 727 try { 728 version = Integer.parseInt(versionValue); 729 } catch (NumberFormatException e) { 730 Slog.e(LOG_TAG, "Cannot parse value of '" + versionValue + "' for version in " 731 + parser.getPositionDescription(), e); 732 throw e; 733 } 734 } 735 } catch (XmlPullParserException | IOException e) { 736 Slog.w(LOG_TAG, "Cannot read user type configuration file.", e); 737 } 738 739 return version; 740 } 741 742 /** 743 * Obtains the user type upgrades for this device. 744 * @return The list of user type upgrades. 745 */ getUserTypeUpgrades()746 public static List<UserTypeUpgrade> getUserTypeUpgrades() { 747 final List<UserTypeUpgrade> userUpgrades; 748 try (XmlResourceParser parser = 749 Resources.getSystem().getXml(com.android.internal.R.xml.config_user_types)) { 750 userUpgrades = parseUserUpgrades(getDefaultBuilders(), parser); 751 } 752 return userUpgrades; 753 } 754 755 @VisibleForTesting parseUserUpgrades( ArrayMap<String, UserTypeDetails.Builder> builders, XmlResourceParser parser)756 static List<UserTypeUpgrade> parseUserUpgrades( 757 ArrayMap<String, UserTypeDetails.Builder> builders, XmlResourceParser parser) { 758 final List<UserTypeUpgrade> userUpgrades = new ArrayList<>(); 759 760 try { 761 XmlUtils.beginDocument(parser, "user-types"); 762 for (XmlUtils.nextElement(parser); 763 parser.getEventType() != XmlResourceParser.END_DOCUMENT; 764 XmlUtils.nextElement(parser)) { 765 final String elementName = parser.getName(); 766 if ("change-user-type".equals(elementName)) { 767 final String fromType = parser.getAttributeValue(null, "from"); 768 final String toType = parser.getAttributeValue(null, "to"); 769 // Check that the base type doesn't change. 770 // Currently, only the base type of PROFILE is supported. 771 validateUserTypeIsProfile(fromType, builders); 772 validateUserTypeIsProfile(toType, builders); 773 774 final int maxVersionToConvert; 775 try { 776 maxVersionToConvert = Integer.parseInt( 777 parser.getAttributeValue(null, "whenVersionLeq")); 778 } catch (NumberFormatException e) { 779 Slog.e(LOG_TAG, "Cannot parse value of whenVersionLeq in " 780 + parser.getPositionDescription(), e); 781 throw e; 782 } 783 784 UserTypeUpgrade userTypeUpgrade = new UserTypeUpgrade(fromType, toType, 785 maxVersionToConvert); 786 userUpgrades.add(userTypeUpgrade); 787 continue; 788 } else { 789 XmlUtils.skipCurrentTag(parser); 790 continue; 791 } 792 } 793 } catch (XmlPullParserException | IOException e) { 794 Slog.w(LOG_TAG, "Cannot read user type configuration file.", e); 795 } 796 797 return userUpgrades; 798 } 799 validateUserTypeIsProfile(String userType, ArrayMap<String, UserTypeDetails.Builder> builders)800 private static void validateUserTypeIsProfile(String userType, 801 ArrayMap<String, UserTypeDetails.Builder> builders) { 802 UserTypeDetails.Builder builder = builders.get(userType); 803 if (builder != null && builder.getBaseType() != FLAG_PROFILE) { 804 throw new IllegalArgumentException("Illegal upgrade of user type " + userType 805 + " : Can only upgrade profiles user types"); 806 } 807 } 808 809 /** 810 * Contains details required for an upgrade operation for {@link UserTypeDetails}; 811 */ 812 public static class UserTypeUpgrade { 813 private final String mFromType; 814 private final String mToType; 815 private final int mUpToVersion; 816 UserTypeUpgrade(String fromType, String toType, int upToVersion)817 public UserTypeUpgrade(String fromType, String toType, int upToVersion) { 818 mFromType = fromType; 819 mToType = toType; 820 mUpToVersion = upToVersion; 821 } 822 getFromType()823 public String getFromType() { 824 return mFromType; 825 } 826 getToType()827 public String getToType() { 828 return mToType; 829 } 830 getUpToVersion()831 public int getUpToVersion() { 832 return mUpToVersion; 833 } 834 } 835 } 836