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

Commit e37b6cff authored by Sarup Dalwani's avatar Sarup Dalwani
Browse files

Changes in queryIntentAcitivities api for intent redirection

Changing behavior of queryIntentAcitivities where for api would return
results across owner and clone profile if and only if caller sets flag
MATCH_CLONE_PROFILE and have permission QUERY_CLONED_APPS. For other
callers the api would only return results from current profile.

Bug: 251373122
Test: Tested manually, CTS test cases to follow in next CL.

Change-Id: I17fed609efda3cb1a6a142891ff7c44c8254c9f5
parent 18511f25
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -3793,6 +3793,7 @@ package android.content.pm {
    field @Deprecated public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; // 0x1
    field @Deprecated public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
    field public static final int MATCH_ANY_USER = 4194304; // 0x400000
    field public static final int MATCH_CLONE_PROFILE = 536870912; // 0x20000000
    field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
    field public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 536870912; // 0x20000000
    field public static final int MATCH_INSTANT = 8388608; // 0x800000
+14 −0
Original line number Diff line number Diff line
@@ -783,6 +783,7 @@ public abstract class PackageManager {
            GET_DISABLED_COMPONENTS,
            GET_DISABLED_UNTIL_USED_COMPONENTS,
            GET_UNINSTALLED_PACKAGES,
            MATCH_CLONE_PROFILE
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ResolveInfoFlagsBits {}
@@ -1112,6 +1113,19 @@ public abstract class PackageManager {
     */
    public static final int MATCH_DIRECT_BOOT_AUTO = 0x10000000;

    /**
     * {@link ResolveInfo} flag: allow matching components across clone profile
     * <p>
     * This flag is used only for query and not resolution, the default behaviour would be to
     * restrict querying across clone profile. This flag would be honored only if caller have
     * permission {@link Manifest.permission.QUERY_CLONED_APPS}.
     *
     *  @hide
     * <p>
     */
    @SystemApi
    public static final int MATCH_CLONE_PROFILE = 0x20000000;

    /**
     * {@link PackageInfo} flag: return all attributions declared in the package manifest
     */
+2 −2
Original line number Diff line number Diff line
@@ -766,7 +766,7 @@ public class ComputerEngine implements Computer {
             */
            crossProfileResults = mCrossProfileIntentResolverEngine.resolveIntent(this, intent,
                    resolvedType, userId, flags, pkgName, hasNonNegativePriorityResult,
                    mSettings::getPackage);
                    resolveForStart, mSettings::getPackage);
            if (intent.hasWebURI() || !crossProfileResults.isEmpty()) sortResult = true;
        } else {
            final PackageStateInternal setting =
@@ -791,7 +791,7 @@ public class ComputerEngine implements Computer {
             */
            crossProfileResults = mCrossProfileIntentResolverEngine.resolveIntent(this, intent,
                    resolvedType, userId, flags, pkgName, false,
                    mSettings::getPackage);
                    resolveForStart, mSettings::getPackage);
        }

        /*
+28 −19
Original line number Diff line number Diff line
@@ -84,15 +84,16 @@ public class CrossProfileIntentResolverEngine {
     * @param pkgName the application package name this Intent is limited to.
     * @param hasNonNegativePriorityResult signifies if current profile have any non-negative(active
     *                                     and valid) ResolveInfo in current profile.
     * @param resolveForStart true if resolution occurs to start an activity.
     * @param pkgSettingFunction function to find PackageStateInternal for given package
     * @return list of {@link CrossProfileDomainInfo} from linked profiles.
     */
    public List<CrossProfileDomainInfo> resolveIntent(@NonNull Computer computer, Intent intent,
            String resolvedType, int userId, long flags, String pkgName,
            boolean hasNonNegativePriorityResult,
            boolean hasNonNegativePriorityResult, boolean resolveForStart,
            Function<String, PackageStateInternal> pkgSettingFunction) {
        return resolveIntentInternal(computer, intent, resolvedType, userId, userId, flags, pkgName,
                hasNonNegativePriorityResult, pkgSettingFunction, null);
                hasNonNegativePriorityResult, resolveForStart, pkgSettingFunction, null);
    }

    /**
@@ -113,13 +114,14 @@ public class CrossProfileIntentResolverEngine {
     * @param pkgName the application package name this Intent is limited to.
     * @param hasNonNegativePriorityResult signifies if current profile have any non-negative(active
     *                                     and valid) ResolveInfo in current profile.
     * @param resolveForStart true if resolution occurs to start an activity.
     * @param pkgSettingFunction function to find PackageStateInternal for given package
     * @param visitedUserIds users for which we have already performed resolution
     * @return list of {@link CrossProfileDomainInfo} from linked profiles.
     */
    private List<CrossProfileDomainInfo> resolveIntentInternal(@NonNull Computer computer,
            Intent intent, String resolvedType, int sourceUserId, int userId, long flags,
            String pkgName, boolean hasNonNegativePriorityResult,
            String pkgName, boolean hasNonNegativePriorityResult, boolean resolveForStart,
            Function<String, PackageStateInternal> pkgSettingFunction,
            Set<Integer> visitedUserIds) {

@@ -184,7 +186,8 @@ public class CrossProfileIntentResolverEngine {

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

        /*
        If {@link CrossProfileResolver} is available for source,target pair we will call it to
@@ -217,8 +220,8 @@ public class CrossProfileIntentResolverEngine {
                if (allowChainedResolution) {
                    crossProfileDomainInfos.addAll(resolveIntentInternal(computer, intent,
                            resolvedType, sourceUserId, targetUserId, flags, pkgName,
                            hasNonNegativePriority(crossProfileInfos), pkgSettingFunction,
                            visitedUserIds));
                            hasNonNegativePriority(crossProfileInfos), resolveForStart,
                            pkgSettingFunction, visitedUserIds));
                }

            }
@@ -233,18 +236,21 @@ public class CrossProfileIntentResolverEngine {
     * @param computer {@link Computer} instance used for resolution by {@link ComponentResolverApi}
     * @param sourceUserId source user
     * @param targetUserId target user
     * @param resolveForStart true if resolution occurs to start an activity.
     * @param flags used for intent resolver selection
     * @return {@code CrossProfileResolver} which has value if source and target have
     * strategy configured otherwise null.
     */
    @SuppressWarnings("unused")
    private CrossProfileResolver chooseCrossProfileResolver(@NonNull Computer computer,
            @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
            @UserIdInt int sourceUserId, @UserIdInt int targetUserId, boolean resolveForStart,
            long flags) {
        /**
         * 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 (shouldUseNoFilteringResolver(sourceUserId, targetUserId)) {
            if (NoFilteringResolver.isIntentRedirectionAllowed()) {
            if (NoFilteringResolver.isIntentRedirectionAllowed(mContext, resolveForStart, flags)) {
                return new NoFilteringResolver(computer.getComponentResolver(),
                        mUserManager);
            } else {
@@ -384,7 +390,6 @@ public class CrossProfileIntentResolverEngine {
             ephemeral activities.
             */
            candidates = resolveInfoFromCrossProfileDomainInfo(crossProfileCandidates);

            return new QueryIntentActivitiesResult(computer.applyPostResolutionFilter(candidates,
                    instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
                    userId, intent));
@@ -404,11 +409,10 @@ public class CrossProfileIntentResolverEngine {
             */
            candidates = filterCandidatesWithDomainPreferredActivitiesLPr(computer, intent,
                    matchFlags, candidates, crossProfileCandidates, userId,
                    areWebInstantAppsDisabled, pkgSettingFunction);
                    areWebInstantAppsDisabled, resolveForStart, pkgSettingFunction);
        } else {
            candidates.addAll(resolveInfoFromCrossProfileDomainInfo(crossProfileCandidates));
        }

        return new QueryIntentActivitiesResult(sortResult, addInstant, candidates);
    }

@@ -421,13 +425,14 @@ public class CrossProfileIntentResolverEngine {
     * @param crossProfileCandidates crossProfileDomainInfos from cross profile, it have ResolveInfo
     * @param userId user id of source user
     * @param areWebInstantAppsDisabled true if web instant apps are disabled
     * @param resolveForStart true if intent is for resolution
     * @param pkgSettingFunction function to find PackageStateInternal for given package
     * @return list of ResolveInfo
     */
    private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Computer computer,
            Intent intent, long matchFlags, List<ResolveInfo> candidates,
            List<CrossProfileDomainInfo> crossProfileCandidates, int userId,
            boolean areWebInstantAppsDisabled,
            boolean areWebInstantAppsDisabled, boolean resolveForStart,
            Function<String, PackageStateInternal> pkgSettingFunction) {
        final boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0;

@@ -439,7 +444,7 @@ public class CrossProfileIntentResolverEngine {
        final List<ResolveInfo> result =
                filterCandidatesWithDomainPreferredActivitiesLPrBody(computer, intent, matchFlags,
                        candidates, crossProfileCandidates, userId, areWebInstantAppsDisabled,
                        debug, pkgSettingFunction);
                        debug, resolveForStart, pkgSettingFunction);

        if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
            Slog.v(TAG, "Filtered results with preferred activities. New candidates count: "
@@ -461,13 +466,14 @@ public class CrossProfileIntentResolverEngine {
     * @param userId user id of source user
     * @param areWebInstantAppsDisabled true if web instant apps are disabled
     * @param debug true if resolution logs needed to be printed
     * @param resolveForStart true if intent is for resolution
     * @param pkgSettingFunction function to find PackageStateInternal for given package
     * @return list of resolve infos
     */
    private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
            Computer computer, Intent intent, long matchFlags, List<ResolveInfo> candidates,
            List<CrossProfileDomainInfo> crossProfileCandidates, int userId,
            boolean areWebInstantAppsDisabled, boolean debug,
            boolean areWebInstantAppsDisabled, boolean debug, boolean resolveForStart,
            Function<String, PackageStateInternal> pkgSettingFunction) {
        final ArrayList<ResolveInfo> result = new ArrayList<>();
        final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
@@ -525,7 +531,7 @@ public class CrossProfileIntentResolverEngine {
            // calling cross profile strategy to filter corresponding results
            result.addAll(filterCrossProfileCandidatesWithDomainPreferredActivities(computer,
                    intent, matchFlags, categorizeResolveInfoByTargetUser, userId,
                    DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE));
                    DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE, resolveForStart));
            includeBrowser = true;
        } else {
            Pair<List<ResolveInfo>, Integer> infosAndLevel = mDomainVerificationManager
@@ -539,7 +545,7 @@ public class CrossProfileIntentResolverEngine {
                // calling cross profile strategy to filter corresponding results
                result.addAll(filterCrossProfileCandidatesWithDomainPreferredActivities(computer,
                        intent, matchFlags, categorizeResolveInfoByTargetUser, userId,
                        DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE));
                        DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE, resolveForStart));
            } else {
                result.addAll(approvedInfos);

@@ -547,7 +553,7 @@ public class CrossProfileIntentResolverEngine {
                // calling cross profile strategy to filter corresponding results
                result.addAll(filterCrossProfileCandidatesWithDomainPreferredActivities(computer,
                        intent, matchFlags, categorizeResolveInfoByTargetUser, userId,
                        highestApproval));
                        highestApproval, resolveForStart));
            }
        }

@@ -612,11 +618,13 @@ public class CrossProfileIntentResolverEngine {
     *                                          CrossProfileDomainInfos
     * @param sourceUserId user id for intent
     * @param highestApprovalLevel domain approval level
     * @param resolveForStart true if intent is for resolution
     * @return list of ResolveInfos
     */
    private List<ResolveInfo> filterCrossProfileCandidatesWithDomainPreferredActivities(
            Computer computer, Intent intent, long flags, SparseArray<List<CrossProfileDomainInfo>>
            categorizeResolveInfoByTargetUser, int sourceUserId, int highestApprovalLevel) {
            categorizeResolveInfoByTargetUser, int sourceUserId, int highestApprovalLevel,
            boolean resolveForStart) {

        List<CrossProfileDomainInfo> crossProfileDomainInfos = new ArrayList<>();

@@ -629,7 +637,8 @@ public class CrossProfileIntentResolverEngine {
                // finding cross profile strategy based on source and target user
                CrossProfileResolver crossProfileIntentResolver =
                        chooseCrossProfileResolver(computer, sourceUserId,
                                categorizeResolveInfoByTargetUser.keyAt(index));
                                categorizeResolveInfoByTargetUser.keyAt(index), resolveForStart,
                                flags);
                // if strategy is available call it and add its filtered results
                if (crossProfileIntentResolver != null) {
                    crossProfileDomainInfos.addAll(crossProfileIntentResolver
+23 −3
Original line number Diff line number Diff line
@@ -16,7 +16,10 @@

package com.android.server.pm;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Binder;
import android.provider.DeviceConfig;
@@ -47,13 +50,19 @@ public class NoFilteringResolver extends CrossProfileResolver {

    /**
     * Returns true if intent redirection for clone profile feature flag is set
     * @return value of flag allow_intent_redirection_for_clone_profile
     * and if its query, then check if calling user have necessary permission
     * (android.permission.QUERY_CLONED_APPS) as well as required flag
     * (PackageManager.MATCH_CLONE_PROFILE) bit set.
     * @return true if resolver would be used for cross profile resolution.
     */
    public static boolean isIntentRedirectionAllowed() {
    public static boolean isIntentRedirectionAllowed(Context context,
            boolean resolveForStart, long flags) {
        final long token = Binder.clearCallingIdentity();
        try {
            return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_APP_CLONING,
                    FLAG_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE, false /* defaultValue */);
                    FLAG_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE, false /* defaultValue */)
                    && (resolveForStart || (((flags & PackageManager.MATCH_CLONE_PROFILE) != 0)
                    && hasPermission(context, Manifest.permission.QUERY_CLONED_APPS)));
        } finally {
            Binder.restoreCallingIdentity(token);
        }
@@ -123,4 +132,15 @@ public class NoFilteringResolver extends CrossProfileResolver {
        // no filtering
        return crossProfileDomainInfos;
    }

    /**
     * Checks if calling uid have the mentioned permission
     * @param context calling context
     * @param permission permission name
     * @return true if uid have the permission
     */
    private static boolean hasPermission(Context context, String permission) {
        return context.checkCallingOrSelfPermission(permission)
                == PackageManager.PERMISSION_GRANTED;
    }
}