Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 19df6fda authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes Idfec610d,I68011fd3

* changes:
  Allow setting User Restrictions per user type
  Support custom user types (profiles)
parents 46fab815 d15b2f72
Loading
Loading
Loading
Loading
+3 −12
Original line number Diff line number Diff line
@@ -2391,19 +2391,11 @@ public class UserManager {
     */
    public @Nullable UserInfo createUser(@Nullable String name, @NonNull String userType,
            @UserInfoFlag int flags) {
        UserInfo user = null;
        try {
            user = mService.createUser(name, userType, flags);
            // TODO: Keep this in sync with
            // UserManagerService.LocalService.createUserEvenWhenDisallowed
            if (user != null && !user.isAdmin() && !user.isDemo()) {
                mService.setUserRestriction(DISALLOW_SMS, true, user.id);
                mService.setUserRestriction(DISALLOW_OUTGOING_CALLS, true, user.id);
            }
            return mService.createUser(name, userType, flags);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
        return user;
    }

    /**
@@ -2748,8 +2740,7 @@ public class UserManager {
    /**
     * Assigns admin privileges to the user, if such a user exists.
     *
     * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} and
     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permissions.
     * <p>Note that this does not alter the user's pre-existing user restrictions.
     *
     * @param userId the id of the user to become admin
     * @hide
+1 −0
Original line number Diff line number Diff line
@@ -440,6 +440,7 @@
  <java-symbol type="integer" name="config_multiuserMaxRunningUsers" />
  <java-symbol type="bool" name="config_multiuserDelayUserDataLocking" />
  <java-symbol type="integer" name="config_userTypePackageWhitelistMode"/>
  <java-symbol type="xml" name="config_user_types" />
  <java-symbol type="integer" name="config_safe_media_volume_index" />
  <java-symbol type="integer" name="config_safe_media_volume_usb_mB" />
  <java-symbol type="integer" name="config_mobile_mtu" />
+98 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2019 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<!--
This xml file allows customization of Android multiuser user types.
It is parsed by frameworks/base/services/core/java/com/android/server/pm/UserTypeFactory.java.

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++   IMPORTANT NOTE   ++++++++++++++++++++++++++++++++++++++++
Although device customization is possible here, it is largely untested.
In particular, although this file allows new profile types to be created, and allows modifying the
number of managed profiles allowed on the device, the consequences of doing so is untested.
OEMs are advised to test very carefully any significant customization.
Further support is planned for later releases.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Pre-defined (AOSP) user types can be customized and new types can be defined. The syntax is the
same in both cases.

Currently, only profiles (not full or system users) can be freely customized/defined.
Full users (i.e. non-system, non-profile) users cannot be defined, and the only property of them
that can be customized are the default-restrictions.
System users cannot be customized here; their default-restrictions must be set using
com.android.internal.R.array.config_defaultFirstUserRestrictions.

The following example modifies two AOSP user types (the FULL user android.os.usertype.full.SECONDARY
and the PROFILE user android.os.usertype.profile.MANAGED) and creates a new PROFILE user type
(com.example.profilename):

<user-types>
    <full-type name="android.os.usertype.full.SECONDARY" >
        <default-restrictions no_sms="true" />
    </full-type>

    <profile-type
        name='android.os.usertype.profile.MANAGED'
        max-allowed-per-parent='2'
        icon-badge='@android:drawable/ic_corp_icon_badge_case'
        badge-plain='@android:drawable/ic_corp_badge_case'
        badge-no-background='@android:drawable/ic_corp_badge_no_background' >
        <badge-labels>
            <item res='@android:string/managed_profile_label_badge' />
            <item res='@android:string/managed_profile_label_badge_2' />
        </badge-labels>
        <badge-colors>
            <item res='@android:color/profile_badge_1' />
            <item res='@android:color/profile_badge_2' />
        </badge-colors>
        <default-restrictions no_sms="true" no_outgoing_calls="true" />
    </profile-type>

    <profile-type
        name="com.example.profilename"
        max-allowed-per-parent="2" />
</user-types>

Mandatory attributes:
    name

Supported optional properties (to be used as shown in the example above) are as follows.
For profile and full users:
    default-restrictions (with values defined in UserRestrictionUtils.USER_RESTRICTIONS)
For profile users only:
    max-allowed-per-parent
    icon-badge
    badge-plain
    badge-no-background
    badge-labels
    badge-colors

See UserTypeFactory.java and UserTypeDetails.java for the meaning (and default values) of these
fields.

Any property that is specified overwrites the AOSP default. For example, if there is no
default-restrictions element, then the AOSP defaults for that user type will be used; however, if
there is a default-restrictions element, then the AOSP default restrictions will be completely
ignored and will instead obey this configuration.

If this file is updated, the properties of any pre-existing user types will be updated too.
Note, however, that default-restrictions refers to the restrictions applied at the time of user
creation; therefore, the active restrictions of any pre-existing users will not be updated.

-->
<user-types>
</user-types>
+17 −26
Original line number Diff line number Diff line
@@ -579,15 +579,6 @@ public class UserManagerService extends IUserManager.Stub {
            applyUserRestrictionsLR(UserHandle.USER_SYSTEM);
        }

        UserInfo currentGuestUser = findCurrentGuestUser();
        if (currentGuestUser != null && !hasUserRestriction(
                UserManager.DISALLOW_CONFIG_WIFI, currentGuestUser.id)) {
            // If a guest user currently exists, apply the DISALLOW_CONFIG_WIFI option
            // to it, in case this guest was created in a previous version where this
            // user restriction was not a default guest restriction.
            setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, currentGuestUser.id);
        }

        mContext.registerReceiver(mDisableQuietModeCallback,
                new IntentFilter(ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK),
                null, mHandler);
@@ -1118,11 +1109,6 @@ public class UserManagerService extends IUserManager.Stub {
            info.flags ^= UserInfo.FLAG_ADMIN;
            writeUserLP(getUserDataLU(info.id));
        }

        // Remove non-admin restrictions.
        // Keep synchronized with createUserEvenWhenDisallowed.
        setUserRestriction(UserManager.DISALLOW_SMS, false, userId);
        setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, userId);
    }

    /**
@@ -1602,10 +1588,12 @@ public class UserManagerService extends IUserManager.Stub {
    private void initDefaultGuestRestrictions() {
        synchronized (mGuestRestrictions) {
            if (mGuestRestrictions.isEmpty()) {
                mGuestRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, true);
                mGuestRestrictions.putBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
                mGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true);
                mGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true);
                UserTypeDetails guestType = mUserTypes.get(UserManager.USER_TYPE_FULL_GUEST);
                if (guestType == null) {
                    Slog.wtf(LOG_TAG, "Can't set default guest restrictions: type doesn't exist.");
                    return;
                }
                guestType.addDefaultRestrictionsTo(mGuestRestrictions);
            }
        }
    }
@@ -2494,6 +2482,12 @@ public class UserManagerService extends IUserManager.Stub {
                        mDevicePolicyLocalUserRestrictions, mDevicePolicyGlobalUserRestrictions
                );
            }
            // DISALLOW_CONFIG_WIFI was made a default guest restriction some time during version 6.
            final UserInfo currentGuestUser = findCurrentGuestUser();
            if (currentGuestUser != null && !hasUserRestriction(
                    UserManager.DISALLOW_CONFIG_WIFI, currentGuestUser.id)) {
                setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, currentGuestUser.id);
            }
            userVersion = 7;
        }

@@ -3245,12 +3239,15 @@ public class UserManagerService extends IUserManager.Stub {
                writeUserLP(userData);
            }
            updateUserIds();

            Bundle restrictions = new Bundle();
            // TODO(b/142482943): Generalize this using UserTypeDetails default restrictions.
            if (isGuest) {
                // Guest default restrictions can be modified via setDefaultGuestRestrictions.
                synchronized (mGuestRestrictions) {
                    restrictions.putAll(mGuestRestrictions);
                }
            } else {
                userTypeDetails.addDefaultRestrictionsTo(restrictions);
            }
            synchronized (mRestrictionsLock) {
                mBaseUserRestrictions.append(userId, restrictions);
@@ -4666,14 +4663,8 @@ public class UserManagerService extends IUserManager.Stub {
        @Override
        public UserInfo createUserEvenWhenDisallowed(String name, @NonNull String userType,
                @UserInfoFlag int flags, String[] disallowedPackages) {
            UserInfo user = createUserInternalUnchecked(name, userType, flags,
            return createUserInternalUnchecked(name, userType, flags,
                    UserHandle.USER_NULL, /* preCreated= */ false, disallowedPackages);
            // Keep this in sync with UserManager.createUser
            if (user != null && !user.isAdmin() && !user.isDemo()) {
                setUserRestriction(UserManager.DISALLOW_SMS, true, user.id);
                setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, true, user.id);
            }
            return user;
        }

        @Override
+41 −28
Original line number Diff line number Diff line
@@ -19,18 +19,17 @@ package com.android.server.pm;
import android.annotation.ColorRes;
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo.UserInfoFlag;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.UserManager;

import com.android.internal.util.Preconditions;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Contains the details about a multiuser "user type", such as a
@@ -75,8 +74,13 @@ public final class UserTypeDetails {
    /** The {@link UserInfo.UserInfoFlag}s that all users of this type will automatically have. */
    private final @UserInfoFlag int mDefaultUserInfoPropertyFlags;

    // TODO(b/142482943): Hook these up to something and set them for each type.
    private final List<String> mDefaultRestrictions;
    /**
     * List of User Restrictions to apply by default to newly created users of this type.
     * <p>Does not apply to SYSTEM users (since they are not formally created); for them use
     * {@link com.android.internal.R.array#config_defaultFirstUserRestrictions} instead.
     * The Bundle is of the form used by {@link UserRestrictionsUtils}.
     */
    private final @Nullable Bundle mDefaultRestrictions;


    // Fields for profiles only, controlling the nature of their badges.
@@ -99,7 +103,7 @@ public final class UserTypeDetails {
     *
     * <p>Must be set if mIconBadge is set.
     */
    private final int[] mBadgeLabels;
    private final @Nullable int[] mBadgeLabels;

    /**
     * Resource ID ({@link ColorRes}) of the colors badge put on icons.
@@ -110,22 +114,21 @@ public final class UserTypeDetails {
     *
     * <p>Must be set if mIconBadge is set.
     */
    private final int[] mBadgeColors;
    private final @Nullable int[] mBadgeColors;

    private UserTypeDetails(@NonNull String name, boolean enabled, int maxAllowed,
            @UserInfoFlag int baseType, @UserInfoFlag int defaultUserInfoPropertyFlags, int label,
            int maxAllowedPerParent,
            int iconBadge, int badgePlain, int badgeNoBackground,
            int[] badgeLabels, int[] badgeColors,
            ArrayList<String> defaultRestrictions) {
            @Nullable int[] badgeLabels, @Nullable int[] badgeColors,
            @Nullable Bundle defaultRestrictions) {
        this.mName = name;
        this.mEnabled = enabled;
        this.mMaxAllowed = maxAllowed;
        this.mMaxAllowedPerParent = maxAllowedPerParent;
        this.mBaseType = baseType;
        this.mDefaultUserInfoPropertyFlags = defaultUserInfoPropertyFlags;
        this.mDefaultRestrictions =
                Collections.unmodifiableList(new ArrayList<>(defaultRestrictions));
        this.mDefaultRestrictions = defaultRestrictions;

        this.mIconBadge = iconBadge;
        this.mBadgePlain = badgePlain;
@@ -180,7 +183,7 @@ public final class UserTypeDetails {
        return mIconBadge != Resources.ID_NULL;
    }

    /** Resource ID of the badge put on icons. */
    /** Resource ID of the badge to put on icons. */
    public @DrawableRes int getIconBadge() {
        return mIconBadge;
    }
@@ -231,9 +234,14 @@ public final class UserTypeDetails {
        return (mBaseType & UserInfo.FLAG_SYSTEM) != 0;
    }

    // TODO(b/142482943): Hook this up and don't return the original.
    public List<String> getDefaultRestrictions() {
        return mDefaultRestrictions;
    /** Returns a Bundle representing the default user restrictions. */
    @NonNull Bundle getDefaultRestrictions() {
        return UserRestrictionsUtils.clone(mDefaultRestrictions);
    }

    /** Adds the default user restrictions to the given bundle of restrictions. */
    public void addDefaultRestrictionsTo(@NonNull Bundle currentRestrictions) {
        UserRestrictionsUtils.merge(currentRestrictions, mDefaultRestrictions);
    }

    /** Dumps details of the UserTypeDetails. Do not parse this. */
@@ -247,7 +255,8 @@ public final class UserTypeDetails {
        pw.print(prefix); pw.print("mDefaultUserInfoFlags: ");
        pw.println(UserInfo.flagsToString(mDefaultUserInfoPropertyFlags));
        pw.print(prefix); pw.print("mLabel: "); pw.println(mLabel);
        pw.print(prefix); pw.print("mDefaultRestrictions: "); pw.println(mDefaultRestrictions);
        pw.print(prefix); pw.println("mDefaultRestrictions: ");
        UserRestrictionsUtils.dumpRestrictions(pw, prefix + "    ", mDefaultRestrictions);
        pw.print(prefix); pw.print("mIconBadge: "); pw.println(mIconBadge);
        pw.print(prefix); pw.print("mBadgePlain: "); pw.println(mBadgePlain);
        pw.print(prefix); pw.print("mBadgeNoBackground: "); pw.println(mBadgeNoBackground);
@@ -265,14 +274,14 @@ public final class UserTypeDetails {
        private int mMaxAllowed = UNLIMITED_NUMBER_OF_USERS;
        private int mMaxAllowedPerParent = UNLIMITED_NUMBER_OF_USERS;
        private int mDefaultUserInfoPropertyFlags = 0;
        private ArrayList<String> mDefaultRestrictions = new ArrayList<>();
        private @Nullable Bundle mDefaultRestrictions = null;
        private boolean mEnabled = true;
        private int mLabel = Resources.ID_NULL;
        private int[] mBadgeLabels = null;
        private int[] mBadgeColors = null;
        private int mIconBadge = Resources.ID_NULL;
        private int mBadgePlain = Resources.ID_NULL;
        private int mBadgeNoBackground = Resources.ID_NULL;
        private @Nullable int[] mBadgeLabels = null;
        private @Nullable int[] mBadgeColors = null;
        private @DrawableRes int mIconBadge = Resources.ID_NULL;
        private @DrawableRes int mBadgePlain = Resources.ID_NULL;
        private @DrawableRes int mBadgeNoBackground = Resources.ID_NULL;

        public Builder setName(String name) {
            mName = name;
@@ -304,27 +313,27 @@ public final class UserTypeDetails {
            return this;
        }

        public Builder setBadgeLabels(int ... badgeLabels) {
        public Builder setBadgeLabels(@StringRes int ... badgeLabels) {
            mBadgeLabels = badgeLabels;
            return this;
        }

        public Builder setBadgeColors(int ... badgeColors) {
        public Builder setBadgeColors(@ColorRes int ... badgeColors) {
            mBadgeColors = badgeColors;
            return this;
        }

        public Builder setIconBadge(int badgeIcon) {
        public Builder setIconBadge(@DrawableRes int badgeIcon) {
            mIconBadge = badgeIcon;
            return this;
        }

        public Builder setBadgePlain(int badgePlain) {
        public Builder setBadgePlain(@DrawableRes int badgePlain) {
            mBadgePlain = badgePlain;
            return this;
        }

        public Builder setBadgeNoBackground(int badgeNoBackground) {
        public Builder setBadgeNoBackground(@DrawableRes int badgeNoBackground) {
            mBadgeNoBackground = badgeNoBackground;
            return this;
        }
@@ -334,11 +343,15 @@ public final class UserTypeDetails {
            return this;
        }

        public Builder setDefaultRestrictions(ArrayList<String> restrictions) {
        public Builder setDefaultRestrictions(@Nullable Bundle restrictions) {
            mDefaultRestrictions = restrictions;
            return this;
        }

        @UserInfoFlag int getBaseType() {
            return mBaseType;
        }

        public UserTypeDetails createUserTypeDetails() {
            Preconditions.checkArgument(mName != null,
                    "Cannot create a UserTypeDetails with no name.");
Loading