• 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_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