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

Commit 785c3d67 authored by Sarup Dalwani's avatar Sarup Dalwani
Browse files

Creating UserProperty for deciding intent resolution strategy

Bug: 241532322
Test: atest CtsAppCloningDeviceTestCase
Test: atest com.android.server.pm.UserManagerTest
Test: atest UserManagerServiceUserTypeTest
Test: atest UserManagerServiceUserPropertiesTest
Test: atest CtsAppCloningHostTest:com.android.cts.appcloning.IntentRedirectionTest
Change-Id: Ib1a915cf35f678d580bc5696e8a2fe7fd3103579
parent fc2da3f0
Loading
Loading
Loading
Loading
+96 −3
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@ public final class UserProperties implements Parcelable {
            "updateCrossProfileIntentFiltersOnOTA";
    private static final String ATTR_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL =
            "crossProfileIntentFilterAccessControl";
    private static final String ATTR_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY =
            "crossProfileIntentResolutionStrategy";

    /** Index values of each property (to indicate whether they are present in this object). */
    @IntDef(prefix = "INDEX_", value = {
@@ -59,7 +61,8 @@ public final class UserProperties implements Parcelable {
            INDEX_INHERIT_DEVICE_POLICY,
            INDEX_USE_PARENTS_CONTACTS,
            INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA,
            INDEX_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL
            INDEX_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL,
            INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY
    })
    @Retention(RetentionPolicy.SOURCE)
    private @interface PropertyIndex {
@@ -71,6 +74,7 @@ public final class UserProperties implements Parcelable {
    private static final int INDEX_USE_PARENTS_CONTACTS = 4;
    private static final int INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA = 5;
    private static final int INDEX_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL = 6;
    private static final int INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY = 7;
    /** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
    private long mPropertiesPresent = 0;

@@ -218,6 +222,39 @@ public final class UserProperties implements Parcelable {
     */
    public static final int CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM_ADD_ONLY = 20;

    /**
     * Possible values for cross profile intent resolution strategy.
     *
     * @hide
     */
    @IntDef(prefix = {"CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_"}, value = {
            CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_DEFAULT,
            CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface CrossProfileIntentResolutionStrategy {
    }

    /**
     * Signifies to use {@link DefaultCrossProfileResolver} strategy, which
     * check if it needs to skip the initiating profile, resolves intent in target profile.
     * {@link DefaultCrossProfileResolver} also filters the {@link ResolveInfo} after intent
     * resolution based on their domain approval level
     *
     * @hide
     */
    public static final int CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_DEFAULT = 0;

    /**
     * Signifies that there is no need to filter {@link ResolveInfo} after cross profile intent
     * resolution across. This strategy is for profile acting transparent to end-user and resolves
     * all allowed intent without giving any profile priority.
     *
     * @hide
     */
    public static final int CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING = 1;


    /**
     * Creates a UserProperties (intended for the SystemServer) that stores a reference to the given
     * default properties, which it uses for any property not subsequently set.
@@ -255,6 +292,7 @@ public final class UserProperties implements Parcelable {
            setUpdateCrossProfileIntentFiltersOnOTA(orig.getUpdateCrossProfileIntentFiltersOnOTA());
            setCrossProfileIntentFilterAccessControl(
                    orig.getCrossProfileIntentFilterAccessControl());
            setCrossProfileIntentResolutionStrategy(orig.getCrossProfileIntentResolutionStrategy());
        }
        if (hasManagePermission) {
            // Add items that require MANAGE_USERS or stronger.
@@ -466,6 +504,36 @@ public final class UserProperties implements Parcelable {
    }
    private @CrossProfileIntentFilterAccessControlLevel int mCrossProfileIntentFilterAccessControl;

    /**
     * Returns the user's {@link CrossProfileIntentResolutionStrategy}. If not explicitly
     * configured, default value is {@link #CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_DEFAULT}.
     * @return user's {@link CrossProfileIntentResolutionStrategy}.
     *
     * @hide
     */
    public @CrossProfileIntentResolutionStrategy int getCrossProfileIntentResolutionStrategy() {
        if (isPresent(INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY)) {
            return mCrossProfileIntentResolutionStrategy;
        }
        if (mDefaultProperties != null) {
            return mDefaultProperties.mCrossProfileIntentResolutionStrategy;
        }
        throw new SecurityException("You don't have permission to query "
                + "crossProfileIntentResolutionStrategy");
    }
    /**
     * Sets {@link CrossProfileIntentResolutionStrategy} for the user.
     * @param val resolution strategy for user
     * @hide
     */
    public void setCrossProfileIntentResolutionStrategy(
            @CrossProfileIntentResolutionStrategy int val) {
        this.mCrossProfileIntentResolutionStrategy = val;
        setPresent(INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY);
    }
    private @CrossProfileIntentResolutionStrategy int mCrossProfileIntentResolutionStrategy;


    @Override
    public String toString() {
        // Please print in increasing order of PropertyIndex.
@@ -480,6 +548,8 @@ public final class UserProperties implements Parcelable {
                + getUpdateCrossProfileIntentFiltersOnOTA()
                + ", mCrossProfileIntentFilterAccessControl="
                + getCrossProfileIntentFilterAccessControl()
                + ", mCrossProfileIntentResolutionStrategy="
                + getCrossProfileIntentResolutionStrategy()
                + "}";
    }

@@ -500,6 +570,8 @@ public final class UserProperties implements Parcelable {
                + getUpdateCrossProfileIntentFiltersOnOTA());
        pw.println(prefix + "    mCrossProfileIntentFilterAccessControl="
                + getCrossProfileIntentFilterAccessControl());
        pw.println(prefix + "    mCrossProfileIntentResolutionStrategy="
                + getCrossProfileIntentResolutionStrategy());
    }

    /**
@@ -554,6 +626,9 @@ public final class UserProperties implements Parcelable {
                case ATTR_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL:
                    setCrossProfileIntentFilterAccessControl(parser.getAttributeInt(i));
                    break;
                case ATTR_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY:
                    setCrossProfileIntentResolutionStrategy(parser.getAttributeInt(i));
                    break;
                default:
                    Slog.w(LOG_TAG, "Skipping unknown property " + attributeName);
            }
@@ -597,6 +672,10 @@ public final class UserProperties implements Parcelable {
            serializer.attributeInt(null, ATTR_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL,
                    mCrossProfileIntentFilterAccessControl);
        }
        if (isPresent(INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY)) {
            serializer.attributeInt(null, ATTR_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY,
                    mCrossProfileIntentResolutionStrategy);
        }
    }

    // For use only with an object that has already had any permission-lacking fields stripped out.
@@ -610,6 +689,7 @@ public final class UserProperties implements Parcelable {
        dest.writeBoolean(mUseParentsContacts);
        dest.writeBoolean(mUpdateCrossProfileIntentFiltersOnOTA);
        dest.writeInt(mCrossProfileIntentFilterAccessControl);
        dest.writeInt(mCrossProfileIntentResolutionStrategy);
    }

    /**
@@ -627,6 +707,7 @@ public final class UserProperties implements Parcelable {
        mUseParentsContacts = source.readBoolean();
        mUpdateCrossProfileIntentFiltersOnOTA = source.readBoolean();
        mCrossProfileIntentFilterAccessControl = source.readInt();
        mCrossProfileIntentResolutionStrategy = source.readInt();
    }

    @Override
@@ -660,6 +741,8 @@ public final class UserProperties implements Parcelable {
        private @CrossProfileIntentFilterAccessControlLevel int
                mCrossProfileIntentFilterAccessControl =
                CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_ALL;
        private @CrossProfileIntentResolutionStrategy int mCrossProfileIntentResolutionStrategy =
                CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_DEFAULT;

        public Builder setShowInLauncher(@ShowInLauncher int showInLauncher) {
            mShowInLauncher = showInLauncher;
@@ -704,6 +787,13 @@ public final class UserProperties implements Parcelable {
            return this;
        }

        /** Sets the value for {@link #mCrossProfileIntentResolutionStrategy} */
        public Builder setCrossProfileIntentResolutionStrategy(@CrossProfileIntentResolutionStrategy
                int crossProfileIntentResolutionStrategy) {
            mCrossProfileIntentResolutionStrategy = crossProfileIntentResolutionStrategy;
            return this;
        }

        /** Builds a UserProperties object with *all* values populated. */
        public UserProperties build() {
            return new UserProperties(
@@ -713,7 +803,8 @@ public final class UserProperties implements Parcelable {
                    mInheritDevicePolicy,
                    mUseParentsContacts,
                    mUpdateCrossProfileIntentFiltersOnOTA,
                    mCrossProfileIntentFilterAccessControl);
                    mCrossProfileIntentFilterAccessControl,
                    mCrossProfileIntentResolutionStrategy);
        }
    } // end Builder

@@ -724,7 +815,8 @@ public final class UserProperties implements Parcelable {
            @ShowInSettings int showInSettings,
            @InheritDevicePolicy int inheritDevicePolicy,
            boolean useParentsContacts, boolean updateCrossProfileIntentFiltersOnOTA,
            @CrossProfileIntentFilterAccessControlLevel int crossProfileIntentFilterAccessControl) {
            @CrossProfileIntentFilterAccessControlLevel int crossProfileIntentFilterAccessControl,
            @CrossProfileIntentResolutionStrategy int crossProfileIntentResolutionStrategy) {

        mDefaultProperties = null;
        setShowInLauncher(showInLauncher);
@@ -734,5 +826,6 @@ public final class UserProperties implements Parcelable {
        setUseParentsContacts(useParentsContacts);
        setUpdateCrossProfileIntentFiltersOnOTA(updateCrossProfileIntentFiltersOnOTA);
        setCrossProfileIntentFilterAccessControl(crossProfileIntentFilterAccessControl);
        setCrossProfileIntentResolutionStrategy(crossProfileIntentResolutionStrategy);
    }
}
+40 −18
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.pm.UserProperties;
import android.os.Process;
import android.text.TextUtils;
import android.util.Pair;
@@ -147,8 +148,6 @@ public class CrossProfileIntentResolverEngine {
            return crossProfileDomainInfos;
        }

        UserInfo userInfo = mUserManagerInternal.getUserInfo(userId);

        // Grouping the CrossProfileIntentFilters based on targerId
        SparseArray<List<CrossProfileIntentFilter>> crossProfileIntentFiltersByUser =
                new SparseArray<>();
@@ -183,11 +182,9 @@ public class CrossProfileIntentResolverEngine {
                continue;
            }

            UserInfo targetUserInfo = mUserManagerInternal.getUserInfo(targetUserId);

            // Choosing strategy based on source and target user
            CrossProfileResolver crossProfileResolver =
                    chooseCrossProfileResolver(computer, userInfo, targetUserInfo);
                    chooseCrossProfileResolver(computer, userId, targetUserId);

        /*
        If {@link CrossProfileResolver} is available for source,target pair we will call it to
@@ -234,23 +231,21 @@ public class CrossProfileIntentResolverEngine {
    /**
     * Returns {@link CrossProfileResolver} strategy based on source and target user
     * @param computer {@link Computer} instance used for resolution by {@link ComponentResolverApi}
     * @param sourceUserInfo source user
     * @param targetUserInfo target user
     * @param sourceUserId source user
     * @param targetUserId target user
     * @return {@code CrossProfileResolver} which has value if source and target have
     * strategy configured otherwise null.
     */
    @SuppressWarnings("unused")
    private CrossProfileResolver chooseCrossProfileResolver(@NonNull Computer computer,
            UserInfo sourceUserInfo, UserInfo targetUserInfo) {
        //todo change isCloneProfile to user properties b/241532322
            @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
        /**
         * If source or target user is clone profile, using {@link CloneProfileResolver}
         * We would allow CloneProfileResolver only if flag
         * SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE is enabled
         * If source or target user is clone profile, using {@link NoFilteringResolver}
         * We would return NoFilteringResolver only if it is allowed(feature flag is set).
         */
        if (sourceUserInfo.isCloneProfile() || targetUserInfo.isCloneProfile()) {
            if (CloneProfileResolver.isIntentRedirectionForCloneProfileAllowed()) {
                return new CloneProfileResolver(computer.getComponentResolver(),
        if (shouldUseNoFilteringResolver(sourceUserId, targetUserId)) {
            if (NoFilteringResolver.isIntentRedirectionAllowed()) {
                return new NoFilteringResolver(computer.getComponentResolver(),
                        mUserManager);
            } else {
                return null;
@@ -624,7 +619,6 @@ public class CrossProfileIntentResolverEngine {
            categorizeResolveInfoByTargetUser, int sourceUserId, int highestApprovalLevel) {

        List<CrossProfileDomainInfo> crossProfileDomainInfos = new ArrayList<>();
        UserInfo sourceUserInfo = mUserManagerInternal.getUserInfo(sourceUserId);

        for (int index = 0; index < categorizeResolveInfoByTargetUser.size(); index++) {

@@ -634,8 +628,8 @@ public class CrossProfileIntentResolverEngine {
            } else {
                // finding cross profile strategy based on source and target user
                CrossProfileResolver crossProfileIntentResolver =
                        chooseCrossProfileResolver(computer, sourceUserInfo, mUserManagerInternal
                                .getUserInfo(categorizeResolveInfoByTargetUser.keyAt(index)));
                        chooseCrossProfileResolver(computer, sourceUserId,
                                categorizeResolveInfoByTargetUser.keyAt(index));
                // if strategy is available call it and add its filtered results
                if (crossProfileIntentResolver != null) {
                    crossProfileDomainInfos.addAll(crossProfileIntentResolver
@@ -678,4 +672,32 @@ public class CrossProfileIntentResolverEngine {
                && crossProfileDomainInfos.get(0).mResolveInfo != null
                && crossProfileDomainInfos.get(0).mResolveInfo.priority >= 0;
    }

    /**
     * Deciding if we need to user {@link NoFilteringResolver} based on source and target user
     * @param sourceUserId id of initiating user
     * @param targetUserId id of cross profile linked user
     * @return true if {@link NoFilteringResolver} is applicable in this case.
     */
    private boolean shouldUseNoFilteringResolver(@UserIdInt int sourceUserId,
            @UserIdInt int targetUserId) {
        return isNoFilteringPropertyConfiguredForUser(sourceUserId)
                || isNoFilteringPropertyConfiguredForUser(targetUserId);
    }

    /**
     * Check if configure property for cross profile intent resolution strategy for user is
     * {@link UserProperties#CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING}
     * @param userId id of user to check for property
     * @return true if user have property set to
     * {@link UserProperties#CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING}
     */
    private boolean isNoFilteringPropertyConfiguredForUser(@UserIdInt int userId) {
        if (!mUserManager.isProfile(userId)) return false;
        UserProperties userProperties = mUserManagerInternal.getUserProperties(userId);
        if (userProperties == null) return false;

        return userProperties.getCrossProfileIntentResolutionStrategy()
                == UserProperties.CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING;
    }
}
+9 −8
Original line number Diff line number Diff line
@@ -30,9 +30,10 @@ import java.util.List;
import java.util.function.Function;

/**
 * Cross Profile intent resolution strategy used for and to clone profile.
 * Intent resolution strategy used when no filtering is required. As of now, the known use-case is
 * clone profile.
 */
public class CloneProfileResolver extends CrossProfileResolver {
public class NoFilteringResolver extends CrossProfileResolver {

    /**
     * Feature flag to allow/restrict intent redirection from/to clone profile.
@@ -48,7 +49,7 @@ public class CloneProfileResolver extends CrossProfileResolver {
     * Returns true if intent redirection for clone profile feature flag is set
     * @return value of flag allow_intent_redirection_for_clone_profile
     */
    public static boolean isIntentRedirectionForCloneProfileAllowed() {
    public static boolean isIntentRedirectionAllowed() {
        final long token = Binder.clearCallingIdentity();
        try {
            return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_APP_CLONING,
@@ -58,13 +59,13 @@ public class CloneProfileResolver extends CrossProfileResolver {
        }
    }

    public CloneProfileResolver(ComponentResolverApi componentResolver,
    public NoFilteringResolver(ComponentResolverApi componentResolver,
            UserManagerService userManagerService) {
        super(componentResolver, userManagerService);
    }

    /**
     * This is resolution strategy for Clone Profile.
     * This is resolution strategy for when no filtering is required.
     * In case of clone profile, the profile is supposed to be transparent to end user. To end user
     * clone and owner profile should be part of same user space. Hence, the resolution strategy
     * would resolve intent in both profile and return combined result without any filtering of the
@@ -105,8 +106,8 @@ public class CloneProfileResolver extends CrossProfileResolver {
    }

    /**
     * As clone and owner profile are going to be part of the same userspace, we need no filtering
     * out of any clone profile's result
     * In case of Clone profile, the clone and owner profile are going to be part of the same
     * userspace, we need no filtering out of any clone profile's result.
     * @param intent request
     * @param crossProfileDomainInfos resolved in target user
     * @param flags for intent resolution
@@ -119,7 +120,7 @@ public class CloneProfileResolver extends CrossProfileResolver {
    public List<CrossProfileDomainInfo> filterResolveInfoWithDomainPreferredActivity(Intent intent,
            List<CrossProfileDomainInfo> crossProfileDomainInfos, long flags, int sourceUserId,
            int targetUserId, int highestApprovalLevel) {
        // no filtering for clone profile
        // no filtering
        return crossProfileDomainInfos;
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -133,7 +133,9 @@ public final class UserTypeFactory {
                        .setUseParentsContacts(true)
                        .setUpdateCrossProfileIntentFiltersOnOTA(true)
                        .setCrossProfileIntentFilterAccessControl(
                                UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM));
                                UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM)
                        .setCrossProfileIntentResolutionStrategy(UserProperties
                                .CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING));
    }

    /**
+1 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
            startWithParent='false'
            useParentsContacts='false'
            crossProfileIntentFilterAccessControl='20'
            crossProfileIntentResolutionStrategy='0'
        />
    </profile-type>
    <profile-type name='custom.test.1' max-allowed-per-parent='14' />
Loading