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

Commit f6b17da3 authored by Jigar Thakkar's avatar Jigar Thakkar Committed by Android (Google) Code Review
Browse files

Merge changes I2af727ed,I0d44d24d into main

* changes:
  Add tests for private profile delayed locking
  Enable stopping user with delayed locking for private profile
parents 6f601837 91cbc689
Loading
Loading
Loading
Loading
+69 −6
Original line number Diff line number Diff line
@@ -68,6 +68,8 @@ public final class UserProperties implements Parcelable {
            "authAlwaysRequiredToDisableQuietMode";
    private static final String ATTR_DELETE_APP_WITH_PARENT = "deleteAppWithParent";
    private static final String ATTR_ALWAYS_VISIBLE = "alwaysVisible";
    private static final String ATTR_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING =
            "allowStoppingUserWithDelayedLocking";

    private static final String ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY =
            "crossProfileContentSharingStrategy";
@@ -89,7 +91,8 @@ public final class UserProperties implements Parcelable {
            INDEX_SHOW_IN_QUIET_MODE,
            INDEX_SHOW_IN_SHARING_SURFACES,
            INDEX_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE,
            INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY
            INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY,
            INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING,
    })
    @Retention(RetentionPolicy.SOURCE)
    private @interface PropertyIndex {
@@ -110,6 +113,7 @@ public final class UserProperties implements Parcelable {
    private static final int INDEX_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE = 13;
    private static final int INDEX_SHOW_IN_SHARING_SURFACES = 14;
    private static final int INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY = 15;
    private static final int INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING = 16;
    /** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
    private long mPropertiesPresent = 0;

@@ -450,6 +454,7 @@ public final class UserProperties implements Parcelable {
            setCrossProfileIntentResolutionStrategy(orig.getCrossProfileIntentResolutionStrategy());
            setDeleteAppWithParent(orig.getDeleteAppWithParent());
            setAlwaysVisible(orig.getAlwaysVisible());
            setAllowStoppingUserWithDelayedLocking(orig.getAllowStoppingUserWithDelayedLocking());
        }
        if (hasManagePermission) {
            // Add items that require MANAGE_USERS or stronger.
@@ -725,6 +730,11 @@ public final class UserProperties implements Parcelable {
        this.mUpdateCrossProfileIntentFiltersOnOTA = val;
        setPresent(INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA);
    }
    /**
     Indicate if {@link com.android.server.pm.CrossProfileIntentFilter}s need to be updated during
     OTA update between user-parent
     */
    private boolean mUpdateCrossProfileIntentFiltersOnOTA;

    /**
     * Returns whether a profile shares media with its parent user.
@@ -786,12 +796,38 @@ public final class UserProperties implements Parcelable {
    }
    private boolean mAuthAlwaysRequiredToDisableQuietMode;

    /*
     Indicate if {@link com.android.server.pm.CrossProfileIntentFilter}s need to be updated during
     OTA update between user-parent
    /**
     * Returns whether a user (usually a profile) is allowed to leave the CE storage unlocked when
     * stopped.
     *
     * <p> Setting this property to true will enable the user's CE storage to remain unlocked when
     * the user is stopped using
     * {@link com.android.server.am.ActivityManagerService#stopUserWithDelayedLocking(int,
     * boolean, IStopUserCallback)}.
     *
     * <p> When this property is false, delayed locking may still be applicable at a global
     * level for all users via the {@code config_multiuserDelayUserDataLocking}. That is, delayed
     * locking for a user can happen if either the device configuration is set or if this property
     * is set. When both, the config and the property value is false, the user storage is always
     * locked when the user is stopped.
     * @hide
     */
    private boolean mUpdateCrossProfileIntentFiltersOnOTA;

    public boolean getAllowStoppingUserWithDelayedLocking() {
        if (isPresent(INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING)) {
            return mAllowStoppingUserWithDelayedLocking;
        }
        if (mDefaultProperties != null) {
            return mDefaultProperties.mAllowStoppingUserWithDelayedLocking;
        }
        throw new SecurityException(
                "You don't have permission to query allowStoppingUserWithDelayedLocking");
    }
    /** @hide */
    public void setAllowStoppingUserWithDelayedLocking(boolean val) {
        this.mAllowStoppingUserWithDelayedLocking = val;
        setPresent(INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING);
    }
    private boolean mAllowStoppingUserWithDelayedLocking;

    /**
     * Returns the user's {@link CrossProfileIntentFilterAccessControlLevel}.
@@ -899,6 +935,8 @@ public final class UserProperties implements Parcelable {
                + ", mCredentialShareableWithParent=" + isCredentialShareableWithParent()
                + ", mAuthAlwaysRequiredToDisableQuietMode="
                + isAuthAlwaysRequiredToDisableQuietMode()
                + ", mAllowStoppingUserWithDelayedLocking="
                + getAllowStoppingUserWithDelayedLocking()
                + ", mDeleteAppWithParent=" + getDeleteAppWithParent()
                + ", mAlwaysVisible=" + getAlwaysVisible()
                + ", mCrossProfileContentSharingStrategy=" + getCrossProfileContentSharingStrategy()
@@ -929,6 +967,8 @@ public final class UserProperties implements Parcelable {
                + isCredentialShareableWithParent());
        pw.println(prefix + "    mAuthAlwaysRequiredToDisableQuietMode="
                + isAuthAlwaysRequiredToDisableQuietMode());
        pw.println(prefix + "    mAllowStoppingUserWithDelayedLocking="
                + getAllowStoppingUserWithDelayedLocking());
        pw.println(prefix + "    mDeleteAppWithParent=" + getDeleteAppWithParent());
        pw.println(prefix + "    mAlwaysVisible=" + getAlwaysVisible());
        pw.println(prefix + "    mCrossProfileContentSharingStrategy="
@@ -1005,6 +1045,9 @@ public final class UserProperties implements Parcelable {
                case ATTR_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE:
                    setAuthAlwaysRequiredToDisableQuietMode(parser.getAttributeBoolean(i));
                    break;
                case ATTR_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING:
                    setAllowStoppingUserWithDelayedLocking(parser.getAttributeBoolean(i));
                    break;
                case ATTR_DELETE_APP_WITH_PARENT:
                    setDeleteAppWithParent(parser.getAttributeBoolean(i));
                    break;
@@ -1079,6 +1122,10 @@ public final class UserProperties implements Parcelable {
            serializer.attributeBoolean(null, ATTR_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE,
                    mAuthAlwaysRequiredToDisableQuietMode);
        }
        if (isPresent(INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING)) {
            serializer.attributeBoolean(null, ATTR_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING,
                    mAllowStoppingUserWithDelayedLocking);
        }
        if (isPresent(INDEX_DELETE_APP_WITH_PARENT)) {
            serializer.attributeBoolean(null, ATTR_DELETE_APP_WITH_PARENT,
                    mDeleteAppWithParent);
@@ -1110,6 +1157,7 @@ public final class UserProperties implements Parcelable {
        dest.writeBoolean(mMediaSharedWithParent);
        dest.writeBoolean(mCredentialShareableWithParent);
        dest.writeBoolean(mAuthAlwaysRequiredToDisableQuietMode);
        dest.writeBoolean(mAllowStoppingUserWithDelayedLocking);
        dest.writeBoolean(mDeleteAppWithParent);
        dest.writeBoolean(mAlwaysVisible);
        dest.writeInt(mCrossProfileContentSharingStrategy);
@@ -1136,6 +1184,7 @@ public final class UserProperties implements Parcelable {
        mMediaSharedWithParent = source.readBoolean();
        mCredentialShareableWithParent = source.readBoolean();
        mAuthAlwaysRequiredToDisableQuietMode = source.readBoolean();
        mAllowStoppingUserWithDelayedLocking = source.readBoolean();
        mDeleteAppWithParent = source.readBoolean();
        mAlwaysVisible = source.readBoolean();
        mCrossProfileContentSharingStrategy = source.readInt();
@@ -1183,6 +1232,7 @@ public final class UserProperties implements Parcelable {
        private boolean mMediaSharedWithParent = false;
        private boolean mCredentialShareableWithParent = false;
        private boolean mAuthAlwaysRequiredToDisableQuietMode = false;
        private boolean mAllowStoppingUserWithDelayedLocking = false;
        private boolean mDeleteAppWithParent = false;
        private boolean mAlwaysVisible = false;
        private @CrossProfileContentSharingStrategy int mCrossProfileContentSharingStrategy =
@@ -1302,6 +1352,16 @@ public final class UserProperties implements Parcelable {
            return this;
        }

        /** Sets the value for {@link #mAllowStoppingUserWithDelayedLocking}
         * @hide
         */
        public Builder setAllowStoppingUserWithDelayedLocking(
                boolean allowStoppingUserWithDelayedLocking) {
            mAllowStoppingUserWithDelayedLocking =
                    allowStoppingUserWithDelayedLocking;
            return this;
        }

        /** Sets the value for {@link #mDeleteAppWithParent}
         * @hide
         */
@@ -1352,6 +1412,7 @@ public final class UserProperties implements Parcelable {
                    mMediaSharedWithParent,
                    mCredentialShareableWithParent,
                    mAuthAlwaysRequiredToDisableQuietMode,
                    mAllowStoppingUserWithDelayedLocking,
                    mDeleteAppWithParent,
                    mAlwaysVisible,
                    mCrossProfileContentSharingStrategy);
@@ -1372,6 +1433,7 @@ public final class UserProperties implements Parcelable {
            boolean mediaSharedWithParent,
            boolean credentialShareableWithParent,
            boolean authAlwaysRequiredToDisableQuietMode,
            boolean allowStoppingUserWithDelayedLocking,
            boolean deleteAppWithParent,
            boolean alwaysVisible,
            @CrossProfileContentSharingStrategy int crossProfileContentSharingStrategy) {
@@ -1390,6 +1452,7 @@ public final class UserProperties implements Parcelable {
        setCredentialShareableWithParent(credentialShareableWithParent);
        setAuthAlwaysRequiredToDisableQuietMode(
                authAlwaysRequiredToDisableQuietMode);
        setAllowStoppingUserWithDelayedLocking(allowStoppingUserWithDelayedLocking);
        setDeleteAppWithParent(deleteAppWithParent);
        setAlwaysVisible(alwaysVisible);
        setCrossProfileContentSharingStrategy(crossProfileContentSharingStrategy);
+2 −0
Original line number Diff line number Diff line
@@ -17510,6 +17510,8 @@ public class ActivityManagerService extends IActivityManager.Stub
     *         other {@code ActivityManager#USER_OP_*} codes for failure.
     *
     */
    // TODO(b/302662311): Add javadoc changes corresponding to the user property that allows
    // delayed locking behavior once the private space flag is finalized.
    @Override
    public int stopUserWithDelayedLocking(final int userId, boolean force,
            final IStopUserCallback callback) {
+47 −18
Original line number Diff line number Diff line
@@ -356,6 +356,8 @@ class UserController implements Handler.Callback {
     * Once total number of unlocked users reach mMaxRunningUsers, least recently used user
     * will be locked.
     */
    // TODO(b/302662311): Add javadoc changes corresponding to the user property that allows
    // delayed locking behavior once the private space flag is finalized.
    @GuardedBy("mLock")
    private boolean mDelayUserDataLocking;

@@ -365,11 +367,12 @@ class UserController implements Handler.Callback {
    private volatile boolean mAllowUserUnlocking;

    /**
     * Keep track of last active users for mDelayUserDataLocking.
     * The latest stopped user is placed in front while the least recently stopped user in back.
     * Keep track of last active users for delayUserDataLocking.
     * The most recently stopped user with delayed locking is placed in front, while the least
     * recently stopped user in back.
     */
    @GuardedBy("mLock")
    private final ArrayList<Integer> mLastActiveUsers = new ArrayList<>();
    private final ArrayList<Integer> mLastActiveUsersForDelayedLocking = new ArrayList<>();

    /**
     * Map of userId to {@link UserCompletedEventType} event flags, indicating which as-yet-
@@ -1011,20 +1014,21 @@ class UserController implements Handler.Callback {
        Slogf.i(TAG, "stopSingleUserLU userId=" + userId);
        final UserState uss = mStartedUsers.get(userId);
        if (uss == null) {  // User is not started
            // If mDelayUserDataLocking is set and allowDelayedLocking is not set, we need to lock
            // the requested user as the client wants to stop and lock the user. On the other hand,
            // having keyEvictedCallback set will lead into locking user if mDelayUserDataLocking
            // is set as that means client wants to lock the user immediately.
            // If mDelayUserDataLocking is not set, the user was already locked when it was stopped
            // and no further action is necessary.
            if (mDelayUserDataLocking) {
            // If canDelayDataLockingForUser() is true and allowDelayedLocking is false, we need
            // to lock the requested user as the client wants to stop and lock the user. On the
            // other hand, having keyEvictedCallback set will lead into locking user if
            // canDelayDataLockingForUser() is true as that means client wants to lock the user
            // immediately.
            // If canDelayDataLockingForUser() is false, the user was already locked when it was
            // stopped and no further action is necessary.
            if (canDelayDataLockingForUser(userId)) {
                if (allowDelayedLocking && keyEvictedCallback != null) {
                    Slogf.wtf(TAG, "allowDelayedLocking set with KeyEvictedCallback, ignore it"
                            + " and lock user:" + userId, new RuntimeException());
                    allowDelayedLocking = false;
                }
                if (!allowDelayedLocking) {
                    if (mLastActiveUsers.remove(Integer.valueOf(userId))) {
                    if (mLastActiveUsersForDelayedLocking.remove(Integer.valueOf(userId))) {
                        // should lock the user, user is already gone
                        final ArrayList<KeyEvictedCallback> keyEvictedCallbacks;
                        if (keyEvictedCallback != null) {
@@ -1354,14 +1358,21 @@ class UserController implements Handler.Callback {
    @GuardedBy("mLock")
    private int updateUserToLockLU(@UserIdInt int userId, boolean allowDelayedLocking) {
        int userIdToLock = userId;
        if (mDelayUserDataLocking && allowDelayedLocking && !getUserInfo(userId).isEphemeral()
        // TODO: Decouple the delayed locking flows from mMaxRunningUsers or rename the property to
        // state maximum running unlocked users specifically
        if (canDelayDataLockingForUser(userIdToLock) && allowDelayedLocking
                && !getUserInfo(userId).isEphemeral()
                && !hasUserRestriction(UserManager.DISALLOW_RUN_IN_BACKGROUND, userId)) {
            mLastActiveUsers.remove((Integer) userId); // arg should be object, not index
            mLastActiveUsers.add(0, userId);
            int totalUnlockedUsers = mStartedUsers.size() + mLastActiveUsers.size();
            // arg should be object, not index
            mLastActiveUsersForDelayedLocking.remove((Integer) userId);
            mLastActiveUsersForDelayedLocking.add(0, userId);
            int totalUnlockedUsers = mStartedUsers.size()
                    + mLastActiveUsersForDelayedLocking.size();
            if (totalUnlockedUsers > mMaxRunningUsers) { // should lock a user
                userIdToLock = mLastActiveUsers.get(mLastActiveUsers.size() - 1);
                mLastActiveUsers.remove(mLastActiveUsers.size() - 1);
                userIdToLock = mLastActiveUsersForDelayedLocking.get(
                        mLastActiveUsersForDelayedLocking.size() - 1);
                mLastActiveUsersForDelayedLocking
                        .remove(mLastActiveUsersForDelayedLocking.size() - 1);
                Slogf.i(TAG, "finishUserStopped, stopping user:" + userId
                        + " lock user:" + userIdToLock);
            } else {
@@ -1373,6 +1384,24 @@ class UserController implements Handler.Callback {
        return userIdToLock;
    }

    /**
     * Returns whether the user can have its CE storage left unlocked, even when it is stopped,
     * either due to a global device configuration or an individual user's property.
     */
    private boolean canDelayDataLockingForUser(@UserIdInt int userIdToLock) {
        if (allowBiometricUnlockForPrivateProfile()) {
            final UserProperties userProperties = getUserProperties(userIdToLock);
            return (mDelayUserDataLocking || (userProperties != null
                    && userProperties.getAllowStoppingUserWithDelayedLocking()));
        }
        return mDelayUserDataLocking;
    }

    private boolean allowBiometricUnlockForPrivateProfile() {
        return android.os.Flags.allowPrivateProfile()
                && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace();
    }

    /**
     * Determines the list of users that should be stopped together with the specified
     * {@code userId}. The returned list includes {@code userId}.
@@ -3161,7 +3190,7 @@ class UserController implements Handler.Callback {
            pw.println("  mCurrentProfileIds:" + Arrays.toString(mCurrentProfileIds));
            pw.println("  mCurrentUserId:" + mCurrentUserId);
            pw.println("  mTargetUserId:" + mTargetUserId);
            pw.println("  mLastActiveUsers:" + mLastActiveUsers);
            pw.println("  mLastActiveUsersForDelayedLocking:" + mLastActiveUsersForDelayedLocking);
            pw.println("  mDelayUserDataLocking:" + mDelayUserDataLocking);
            pw.println("  mAllowUserUnlocking:" + mAllowUserUnlocking);
            pw.println("  shouldStopUserOnSwitch():" + shouldStopUserOnSwitch());
+13 −1
Original line number Diff line number Diff line
@@ -1519,7 +1519,7 @@ public class UserManagerService extends IUserManager.Stub {

        try {
            if (enableQuietMode) {
                ActivityManager.getService().stopUser(userId, /* force= */ true, null);
                stopUserForQuietMode(userId);
                LocalServices.getService(ActivityManagerInternal.class)
                        .killForegroundAppsForUser(userId);
            } else {
@@ -1547,6 +1547,18 @@ public class UserManagerService extends IUserManager.Stub {
        }
    }

    private void stopUserForQuietMode(int userId) throws RemoteException {
        if (android.os.Flags.allowPrivateProfile()
                && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) {
            // Allow delayed locking since some profile types want to be able to unlock again via
            // biometrics.
            ActivityManager.getService()
                    .stopUserWithDelayedLocking(userId, /* force= */ true, null);
            return;
        }
        ActivityManager.getService().stopUser(userId, /* force= */ true, null);
    }

    private void logQuietModeEnabled(@UserIdInt int userId, boolean enableQuietMode,
            @Nullable String callingPackage) {
        Slogf.i(LOG_TAG,
+1 −0
Original line number Diff line number Diff line
@@ -311,6 +311,7 @@ public final class UserTypeFactory {
                        .setStartWithParent(true)
                        .setCredentialShareableWithParent(true)
                        .setAuthAlwaysRequiredToDisableQuietMode(true)
                        .setAllowStoppingUserWithDelayedLocking(true)
                        .setMediaSharedWithParent(false)
                        .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
                        .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE)
Loading