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

Commit 4e9eb5f7 authored by Jigar Thakkar's avatar Jigar Thakkar
Browse files

Block private space creation based on device conditions

This change adds logic to disable private space creation when
the below mentioned device conditions are met:

- Device has low RAM (based on ActivityManager.isLowRamDevice)
- Device is a TV, Automotive devices, or a Watch
- The parent user has retriciton DISALLOW_ADD_PRIVATE_PROFILE
- The parent user is non-system user

The change also adds a hidden API (canAddPrivateProfile) that
checks for all the above mentioned conditions. This API can be used
by callers to check if the private space creation is supported
on the device and parent user.

Test: atest UserManagerServiceTest
atest UserManagerTest
Bug: 290333800

Change-Id: Iea123c2e4646980eca6253b2f063799d92320b1a
parent 7f8a7bfd
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -184,3 +184,11 @@ flag {
    description: "Enable Private Space telephony and SMS intent redirection to the main user"
    bug: "325576602"
}

flag {
    name: "block_private_space_creation"
    namespace: "profile_experiences"
    description: "Allow blocking private space creation based on specific conditions"
    bug: "290333800"
    is_fixed_read_only: true
}
+1 −0
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ interface IUserManager {
    boolean isUserSwitcherEnabled(boolean showEvenIfNotActionable, int mUserId);
    boolean isRestricted(int userId);
    boolean canHaveRestrictedProfile(int userId);
    boolean canAddPrivateProfile(int userId);
    int getUserSerialNumber(int userId);
    int getUserHandle(int userSerialNumber);
    int getUserRestrictionSource(String restrictionKey, int userId);
+46 −1
Original line number Diff line number Diff line
@@ -2352,6 +2352,17 @@ public class UserManager {
    @SystemApi
    public static final int USER_OPERATION_ERROR_USER_ACCOUNT_ALREADY_EXISTS = 7;

    /**
     * Indicates user operation failed because user is disabled on the device.
     * @hide
     */
    public static final int USER_OPERATION_ERROR_DISABLED_USER = 8;
    /**
     * Indicates user operation failed because user is disabled on the device.
     * @hide
     */
    public static final int USER_OPERATION_ERROR_PRIVATE_PROFILE = 9;

    /**
     * Result returned from various user operations.
     *
@@ -2366,7 +2377,9 @@ public class UserManager {
            USER_OPERATION_ERROR_CURRENT_USER,
            USER_OPERATION_ERROR_LOW_STORAGE,
            USER_OPERATION_ERROR_MAX_USERS,
            USER_OPERATION_ERROR_USER_ACCOUNT_ALREADY_EXISTS
            USER_OPERATION_ERROR_USER_ACCOUNT_ALREADY_EXISTS,
            USER_OPERATION_ERROR_DISABLED_USER,
            USER_OPERATION_ERROR_PRIVATE_PROFILE,
    })
    public @interface UserOperationResult {}

@@ -2562,6 +2575,17 @@ public class UserManager {
                        .getBoolean(com.android.internal.R.bool.config_omnipresentCommunalUser));
    }

    /**
     * Returns whether the device supports Private Profile
     * @hide
     */
    public static boolean isPrivateProfileEnabled() {
        if (android.multiuser.Flags.blockPrivateSpaceCreation()) {
            return !ActivityManager.isLowRamDeviceStatic();
        }
        return true;
    }

    /**
     * Returns whether multiple admins are enabled on the device
     * @hide
@@ -3154,6 +3178,27 @@ public class UserManager {
        }
    }

    /**
     * Checks if it's possible to add a private profile to the context user
     * @return whether the context user can add a private profile.
     * @hide
     */
    @RequiresPermission(anyOf = {
            Manifest.permission.MANAGE_USERS,
            Manifest.permission.CREATE_USERS},
            conditional = true)
    @UserHandleAware
    public boolean canAddPrivateProfile() {
        if (android.multiuser.Flags.blockPrivateSpaceCreation()) {
            try {
                return mService.canAddPrivateProfile(mUserId);
            } catch (RemoteException re) {
                throw re.rethrowFromSystemServer();
            }
        }
        return true;
    }

    /**
     * Returns whether the context user has at least one restricted profile associated with it.
     * @return whether the user has a restricted profile associated with it
+32 −1
Original line number Diff line number Diff line
@@ -21,10 +21,15 @@ import static android.content.Intent.ACTION_SCREEN_ON;
import static android.content.Intent.EXTRA_USER_ID;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
import static android.content.pm.PackageManager.FEATURE_EMBEDDED;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.os.UserManager.DEV_CREATE_OVERRIDE_PROPERTY;
import static android.os.UserManager.DISALLOW_USER_SWITCH;
import static android.os.UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY;
import static android.os.UserManager.USER_OPERATION_ERROR_UNKNOWN;
import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;

import static com.android.internal.app.SetScreenLockDialogActivity.EXTRA_ORIGIN_USER_ID;
import static com.android.internal.app.SetScreenLockDialogActivity.LAUNCH_REASON_DISABLE_QUIET_MODE;
@@ -1006,6 +1011,13 @@ public class UserManagerService extends IUserManager.Stub {
        emulateSystemUserModeIfNeeded();
    }

    private boolean doesDeviceHardwareSupportPrivateSpace() {
        return !mPm.hasSystemFeature(FEATURE_EMBEDDED, 0)
                && !mPm.hasSystemFeature(FEATURE_WATCH, 0)
                && !mPm.hasSystemFeature(FEATURE_LEANBACK, 0)
                && !mPm.hasSystemFeature(FEATURE_AUTOMOTIVE, 0);
    }

    private static boolean isAutoLockForPrivateSpaceEnabled() {
        return android.os.Flags.allowPrivateProfile()
                && Flags.supportAutolockForPrivateSpace();
@@ -2750,6 +2762,18 @@ public class UserManagerService extends IUserManager.Stub {
        }
    }

    @Override
    public boolean canAddPrivateProfile(@UserIdInt int userId) {
        checkCreateUsersPermission("canHaveRestrictedProfile");
        UserInfo parentUserInfo = getUserInfo(userId);
        return isUserTypeEnabled(USER_TYPE_PROFILE_PRIVATE)
                && canAddMoreProfilesToUser(USER_TYPE_PROFILE_PRIVATE,
                    userId, /* allowedToRemoveOne */ false)
                && (parentUserInfo != null && parentUserInfo.isMain())
                && doesDeviceHardwareSupportPrivateSpace()
                && !hasUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE, userId);
    }

    @Override
    public boolean hasRestrictedProfiles(@UserIdInt int userId) {
        checkManageUsersPermission("hasRestrictedProfiles");
@@ -5308,7 +5332,7 @@ public class UserManagerService extends IUserManager.Stub {
        if (!isUserTypeEnabled(userTypeDetails)) {
            throwCheckedUserOperationException(
                    "Cannot add a user of disabled type " + userType + ".",
                    UserManager.USER_OPERATION_ERROR_MAX_USERS);
                    UserManager.USER_OPERATION_ERROR_DISABLED_USER);
        }

        synchronized (mUsersLock) {
@@ -5341,6 +5365,7 @@ public class UserManagerService extends IUserManager.Stub {
        final boolean isDemo = UserManager.isUserTypeDemo(userType);
        final boolean isManagedProfile = UserManager.isUserTypeManagedProfile(userType);
        final boolean isCommunalProfile = UserManager.isUserTypeCommunalProfile(userType);
        final boolean isPrivateProfile = UserManager.isUserTypePrivateProfile(userType);

        final long ident = Binder.clearCallingIdentity();
        UserInfo userInfo;
@@ -5387,6 +5412,12 @@ public class UserManagerService extends IUserManager.Stub {
                                    + " for user " + parentId,
                            UserManager.USER_OPERATION_ERROR_MAX_USERS);
                }
                if (android.multiuser.Flags.blockPrivateSpaceCreation()
                        && isPrivateProfile && !canAddPrivateProfile(parentId)) {
                    throwCheckedUserOperationException(
                            "Cannot add profile of type " + userType + " for user " + parentId,
                            UserManager.USER_OPERATION_ERROR_PRIVATE_PROFILE);
                }
                if (isRestricted && (parentId != UserHandle.USER_SYSTEM)
                        && !isCreationOverrideEnabled()) {
                    throwCheckedUserOperationException(
+1 −0
Original line number Diff line number Diff line
@@ -292,6 +292,7 @@ public final class UserTypeFactory {
                .setName(USER_TYPE_PROFILE_PRIVATE)
                .setBaseType(FLAG_PROFILE)
                .setMaxAllowedPerParent(1)
                .setEnabled(UserManager.isPrivateProfileEnabled() ? 1 : 0)
                .setLabels(R.string.profile_label_private)
                .setIconBadge(com.android.internal.R.drawable.ic_private_profile_icon_badge)
                .setBadgePlain(com.android.internal.R.drawable.ic_private_profile_badge)
Loading