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
This commit is contained in:
Sarup Dalwani
2022-10-06 08:32:13 +00:00
parent 18511f25ec
commit e37b6cffbd
5 changed files with 68 additions and 24 deletions

View File

@@ -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

View File

@@ -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
*/

View File

@@ -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);
}
/*

View File

@@ -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

View File

@@ -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;
}
}