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

Commit 299bb02c authored by Olivier Nshimiye's avatar Olivier Nshimiye
Browse files

Add profile_api_visibility user property

This property will be used to check if the profile should be returned in
APIs without the need of an additional permission(SEE_HIDDEN_PROFILES)

Bug: 316362775
Test: atest FrameworksServicesTests:UserManagerServiceUserPropertiesTest
Test: atest FrameworksServicesTests:UserManagerServiceUserTypeTest
Change-Id: Ice3f592f3bcaaa346bc5cc828aa9cf8b3488300d
parent f24232b9
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -4228,6 +4228,7 @@ package android.content.pm {
  public final class UserProperties implements android.os.Parcelable {
    method public int describeContents();
    method public int getCrossProfileContentSharingStrategy();
    method @FlaggedApi("android.multiuser.support_hiding_profiles") @NonNull public int getProfileApiVisibility();
    method public int getShowInQuietMode();
    method public int getShowInSharingSurfaces();
    method public boolean isCredentialShareableWithParent();
@@ -4237,6 +4238,9 @@ package android.content.pm {
    field public static final int CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT = 1; // 0x1
    field public static final int CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION = 0; // 0x0
    field public static final int CROSS_PROFILE_CONTENT_SHARING_UNKNOWN = -1; // 0xffffffff
    field @FlaggedApi("android.multiuser.support_hiding_profiles") public static final int PROFILE_API_VISIBILITY_HIDDEN = 1; // 0x1
    field @FlaggedApi("android.multiuser.support_hiding_profiles") public static final int PROFILE_API_VISIBILITY_UNKNOWN = -1; // 0xffffffff
    field @FlaggedApi("android.multiuser.support_hiding_profiles") public static final int PROFILE_API_VISIBILITY_VISIBLE = 0; // 0x0
    field public static final int SHOW_IN_QUIET_MODE_DEFAULT = 2; // 0x2
    field public static final int SHOW_IN_QUIET_MODE_HIDDEN = 1; // 0x1
    field public static final int SHOW_IN_QUIET_MODE_PAUSED = 0; // 0x0
+103 −3
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package android.content.pm;

import static android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES;

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -73,7 +76,7 @@ public final class UserProperties implements Parcelable {

    private static final String ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY =
            "crossProfileContentSharingStrategy";

    private static final String ATTR_PROFILE_API_VISIBILITY = "profileApiVisibility";
    /** Index values of each property (to indicate whether they are present in this object). */
    @IntDef(prefix = "INDEX_", value = {
            INDEX_SHOW_IN_LAUNCHER,
@@ -93,6 +96,7 @@ public final class UserProperties implements Parcelable {
            INDEX_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE,
            INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY,
            INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING,
            INDEX_PROFILE_API_VISIBILITY
    })
    @Retention(RetentionPolicy.SOURCE)
    private @interface PropertyIndex {
@@ -114,6 +118,7 @@ public final class UserProperties implements Parcelable {
    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;
    private static final int INDEX_PROFILE_API_VISIBILITY = 17;
    /** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
    private long mPropertiesPresent = 0;

@@ -450,6 +455,41 @@ public final class UserProperties implements Parcelable {
    @SuppressLint("UnflaggedApi") // b/306636213
    public static final int CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT = 1;

    /**
     * Possible values for the profile visibility in public API surfaces. This indicates whether or
     * not the information linked to the profile (userId, package names) should not be returned in
     * API surfaces if a user is marked as hidden.
     *
     * @hide
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = "PROFILE_API_VISIBILITY_",
            value = {
                    PROFILE_API_VISIBILITY_UNKNOWN,
                    PROFILE_API_VISIBILITY_VISIBLE,
                    PROFILE_API_VISIBILITY_HIDDEN,
            }
    )
    public @interface ProfileApiVisibility {
    }
    /*
    * The api visibility value for this profile user is undefined or unknown.
     */
    @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
    public static final int PROFILE_API_VISIBILITY_UNKNOWN = -1;

    /**
     * Indicates that information about this profile user should be shown in API surfaces.
     */
    @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
    public static final int PROFILE_API_VISIBILITY_VISIBLE = 0;

    /**
     * Indicates that information about this profile should be not be visible in API surfaces.
     */
    @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
    public static final int PROFILE_API_VISIBILITY_HIDDEN = 1;


    /**
     * Creates a UserProperties (intended for the SystemServer) that stores a reference to the given
@@ -510,6 +550,9 @@ public final class UserProperties implements Parcelable {
        setShowInQuietMode(orig.getShowInQuietMode());
        setShowInSharingSurfaces(orig.getShowInSharingSurfaces());
        setCrossProfileContentSharingStrategy(orig.getCrossProfileContentSharingStrategy());
        if (android.multiuser.Flags.supportHidingProfiles()) {
            setProfileApiVisibility(orig.getProfileApiVisibility());
        }
    }

    /**
@@ -951,9 +994,31 @@ public final class UserProperties implements Parcelable {
    }
    private @CrossProfileContentSharingStrategy int mCrossProfileContentSharingStrategy;

    /**
     * Returns the visibility of the profile user in API surfaces. Any information linked to the
     * profile (userId, package names) should be hidden API surfaces if a user is marked as hidden.
     */
    @NonNull
    @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
    public @ProfileApiVisibility int getProfileApiVisibility() {
        if (isPresent(INDEX_PROFILE_API_VISIBILITY)) return mProfileApiVisibility;
        if (mDefaultProperties != null) return mDefaultProperties.mProfileApiVisibility;
        throw new SecurityException("You don't have permission to query profileApiVisibility");
    }
    /** @hide */
    @NonNull
    @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
    public void setProfileApiVisibility(@ProfileApiVisibility int profileApiVisibility) {
        this.mProfileApiVisibility = profileApiVisibility;
        setPresent(INDEX_PROFILE_API_VISIBILITY);
    }
    private @ProfileApiVisibility int mProfileApiVisibility;

    @Override
    public String toString() {
        String profileApiVisibility =
                android.multiuser.Flags.supportHidingProfiles() ? ", mProfileApiVisibility="
                        + getProfileApiVisibility() : "";
        // Please print in increasing order of PropertyIndex.
        return "UserProperties{"
                + "mPropertiesPresent=" + Long.toBinaryString(mPropertiesPresent)
@@ -977,6 +1042,7 @@ public final class UserProperties implements Parcelable {
                + ", mDeleteAppWithParent=" + getDeleteAppWithParent()
                + ", mAlwaysVisible=" + getAlwaysVisible()
                + ", mCrossProfileContentSharingStrategy=" + getCrossProfileContentSharingStrategy()
                + profileApiVisibility
                + "}";
    }

@@ -1010,6 +1076,9 @@ public final class UserProperties implements Parcelable {
        pw.println(prefix + "    mAlwaysVisible=" + getAlwaysVisible());
        pw.println(prefix + "    mCrossProfileContentSharingStrategy="
                + getCrossProfileContentSharingStrategy());
        if (android.multiuser.Flags.supportHidingProfiles()) {
            pw.println(prefix + "    mProfileApiVisibility=" + getProfileApiVisibility());
        }
    }

    /**
@@ -1093,6 +1162,12 @@ public final class UserProperties implements Parcelable {
                    break;
                case ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY:
                    setCrossProfileContentSharingStrategy(parser.getAttributeInt(i));
                    break;
                case ATTR_PROFILE_API_VISIBILITY:
                    if (android.multiuser.Flags.supportHidingProfiles()) {
                        setProfileApiVisibility(parser.getAttributeInt(i));
                    }
                    break;
                default:
                    Slog.w(LOG_TAG, "Skipping unknown property " + attributeName);
            }
@@ -1175,6 +1250,12 @@ public final class UserProperties implements Parcelable {
            serializer.attributeInt(null, ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY,
                    mCrossProfileContentSharingStrategy);
        }
        if (isPresent(INDEX_PROFILE_API_VISIBILITY)) {
            if (android.multiuser.Flags.supportHidingProfiles()) {
                serializer.attributeInt(null, ATTR_PROFILE_API_VISIBILITY,
                        mProfileApiVisibility);
            }
        }
    }

    // For use only with an object that has already had any permission-lacking fields stripped out.
@@ -1198,6 +1279,7 @@ public final class UserProperties implements Parcelable {
        dest.writeBoolean(mDeleteAppWithParent);
        dest.writeBoolean(mAlwaysVisible);
        dest.writeInt(mCrossProfileContentSharingStrategy);
        dest.writeInt(mProfileApiVisibility);
    }

    /**
@@ -1225,6 +1307,7 @@ public final class UserProperties implements Parcelable {
        mDeleteAppWithParent = source.readBoolean();
        mAlwaysVisible = source.readBoolean();
        mCrossProfileContentSharingStrategy = source.readInt();
        mProfileApiVisibility = source.readInt();
    }

    @Override
@@ -1274,6 +1357,7 @@ public final class UserProperties implements Parcelable {
        private boolean mAlwaysVisible = false;
        private @CrossProfileContentSharingStrategy int mCrossProfileContentSharingStrategy =
                CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION;
        private @ProfileApiVisibility int mProfileApiVisibility = 0;

        /**
         * @hide
@@ -1428,6 +1512,17 @@ public final class UserProperties implements Parcelable {
            return this;
        }

        /**
         * Sets the value for {@link #mProfileApiVisibility}
         * @hide
         */
        @NonNull
        @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
        public Builder setProfileApiVisibility(@ProfileApiVisibility int profileApiVisibility){
            mProfileApiVisibility = profileApiVisibility;
            return this;
        }

        /** Builds a UserProperties object with *all* values populated.
         * @hide
         */
@@ -1452,7 +1547,8 @@ public final class UserProperties implements Parcelable {
                    mAllowStoppingUserWithDelayedLocking,
                    mDeleteAppWithParent,
                    mAlwaysVisible,
                    mCrossProfileContentSharingStrategy);
                    mCrossProfileContentSharingStrategy,
                    mProfileApiVisibility);
        }
    } // end Builder

@@ -1473,7 +1569,8 @@ public final class UserProperties implements Parcelable {
            boolean allowStoppingUserWithDelayedLocking,
            boolean deleteAppWithParent,
            boolean alwaysVisible,
            @CrossProfileContentSharingStrategy int crossProfileContentSharingStrategy) {
            @CrossProfileContentSharingStrategy int crossProfileContentSharingStrategy,
            @ProfileApiVisibility int profileApiVisibility) {
        mDefaultProperties = null;
        setShowInLauncher(showInLauncher);
        setStartWithParent(startWithParent);
@@ -1493,5 +1590,8 @@ public final class UserProperties implements Parcelable {
        setDeleteAppWithParent(deleteAppWithParent);
        setAlwaysVisible(alwaysVisible);
        setCrossProfileContentSharingStrategy(crossProfileContentSharingStrategy);
        if (android.multiuser.Flags.supportHidingProfiles()) {
            setProfileApiVisibility(profileApiVisibility);
        }
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -100,3 +100,11 @@ flag {
    description: "Enable only the API changes to support private space"
    bug: "299069460"
}

flag {
    name: "support_hiding_profiles"
    namespace: "profile_experiences"
    description: "Allow the use of a hide_profile property to hide some profiles behind a permission"
    bug: "316362775"
    is_fixed_read_only: true
}
+23 −17
Original line number Diff line number Diff line
@@ -288,6 +288,28 @@ public final class UserTypeFactory {
     * configuration.
     */
    private static UserTypeDetails.Builder getDefaultTypeProfilePrivate() {
        UserProperties.Builder userPropertiesBuilder = new UserProperties.Builder()
                .setStartWithParent(true)
                .setCredentialShareableWithParent(true)
                .setAuthAlwaysRequiredToDisableQuietMode(true)
                .setAllowStoppingUserWithDelayedLocking(true)
                .setMediaSharedWithParent(false)
                .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
                .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE)
                .setShowInQuietMode(
                        UserProperties.SHOW_IN_QUIET_MODE_HIDDEN)
                .setShowInSharingSurfaces(
                        UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE)
                .setCrossProfileIntentFilterAccessControl(
                        UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM)
                .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT)
                .setCrossProfileContentSharingStrategy(
                        UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT);
        if (android.multiuser.Flags.supportHidingProfiles()) {
            userPropertiesBuilder.setProfileApiVisibility(
                    UserProperties.PROFILE_API_VISIBILITY_HIDDEN);
        }

        return new UserTypeDetails.Builder()
                .setName(USER_TYPE_PROFILE_PRIVATE)
                .setBaseType(FLAG_PROFILE)
@@ -306,23 +328,7 @@ public final class UserTypeFactory {
                .setDarkThemeBadgeColors(
                        R.color.white)
                .setDefaultRestrictions(getDefaultProfileRestrictions())
                .setDefaultUserProperties(new UserProperties.Builder()
                        .setStartWithParent(true)
                        .setCredentialShareableWithParent(true)
                        .setAuthAlwaysRequiredToDisableQuietMode(true)
                        .setAllowStoppingUserWithDelayedLocking(true)
                        .setMediaSharedWithParent(false)
                        .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
                        .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE)
                        .setShowInQuietMode(
                                UserProperties.SHOW_IN_QUIET_MODE_HIDDEN)
                        .setShowInSharingSurfaces(
                                UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE)
                        .setCrossProfileIntentFilterAccessControl(
                                UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM)
                        .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT)
                        .setCrossProfileContentSharingStrategy(
                                UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT));
                .setDefaultUserProperties(userPropertiesBuilder);
    }

    /**
+13 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static org.testng.Assert.assertThrows;
import android.content.pm.UserProperties;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.Xml;

import androidx.test.filters.MediumTest;
@@ -31,6 +32,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

@@ -52,10 +54,13 @@ import java.util.function.Supplier;
@RunWith(AndroidJUnit4.class)
@MediumTest
public class UserManagerServiceUserPropertiesTest {
    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    /** Test that UserProperties can properly read the xml information that it writes. */
    @Test
    public void testWriteReadXml() throws Exception {
        mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
        final UserProperties defaultProps = new UserProperties.Builder()
                .setShowInLauncher(21)
                .setStartWithParent(false)
@@ -73,6 +78,7 @@ public class UserManagerServiceUserPropertiesTest {
                .setDeleteAppWithParent(false)
                .setAlwaysVisible(false)
                .setCrossProfileContentSharingStrategy(0)
                .setProfileApiVisibility(34)
                .build();
        final UserProperties actualProps = new UserProperties(defaultProps);
        actualProps.setShowInLauncher(14);
@@ -90,6 +96,7 @@ public class UserManagerServiceUserPropertiesTest {
        actualProps.setDeleteAppWithParent(true);
        actualProps.setAlwaysVisible(true);
        actualProps.setCrossProfileContentSharingStrategy(1);
        actualProps.setProfileApiVisibility(36);

        // Write the properties to xml.
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -114,6 +121,7 @@ public class UserManagerServiceUserPropertiesTest {
    /** Tests parcelling an object in which all properties are present. */
    @Test
    public void testParcelUnparcel() throws Exception {
        mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
        final UserProperties originalProps = new UserProperties.Builder()
                .setShowInLauncher(2145)
                .build();
@@ -124,6 +132,7 @@ public class UserManagerServiceUserPropertiesTest {
    /** Tests copying a UserProperties object varying permissions. */
    @Test
    public void testCopyLacksPermissions() throws Exception {
        mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
        final UserProperties defaultProps = new UserProperties.Builder()
                .setShowInLauncher(2145)
                .setStartWithParent(true)
@@ -134,6 +143,7 @@ public class UserManagerServiceUserPropertiesTest {
                .setAuthAlwaysRequiredToDisableQuietMode(false)
                .setAllowStoppingUserWithDelayedLocking(false)
                .setAlwaysVisible(true)
                .setProfileApiVisibility(110)
                .build();
        final UserProperties orig = new UserProperties(defaultProps);
        orig.setShowInLauncher(2841);
@@ -209,6 +219,8 @@ public class UserManagerServiceUserPropertiesTest {
                copy::isCredentialShareableWithParent, true);
        assertEqualGetterOrThrows(orig::getCrossProfileContentSharingStrategy,
                copy::getCrossProfileContentSharingStrategy, true);
        assertEqualGetterOrThrows(orig::getProfileApiVisibility, copy::getProfileApiVisibility,
                true);
    }

    /**
@@ -270,5 +282,6 @@ public class UserManagerServiceUserPropertiesTest {
        assertThat(expected.getAlwaysVisible()).isEqualTo(actual.getAlwaysVisible());
        assertThat(expected.getCrossProfileContentSharingStrategy())
                .isEqualTo(actual.getCrossProfileContentSharingStrategy());
        assertThat(expected.getProfileApiVisibility()).isEqualTo(actual.getProfileApiVisibility());
    }
}
Loading