Merge changes from topic "ir_3P"

* changes:
  Changes in queryIntentAcitivities api for intent redirection
  Adding a new permission to interact across clone profile apps.
This commit is contained in:
Himanshu Gupta
2023-01-17 21:44:17 +00:00
committed by Android (Google) Code Review
6 changed files with 78 additions and 24 deletions

View File

@@ -248,6 +248,7 @@ package android {
field public static final String PROVIDE_TRUST_AGENT = "android.permission.PROVIDE_TRUST_AGENT";
field public static final String PROVISION_DEMO_DEVICE = "android.permission.PROVISION_DEMO_DEVICE";
field public static final String QUERY_ADMIN_POLICY = "android.permission.QUERY_ADMIN_POLICY";
field public static final String QUERY_CLONED_APPS = "android.permission.QUERY_CLONED_APPS";
field @Deprecated public static final String QUERY_TIME_ZONE_RULES = "android.permission.QUERY_TIME_ZONE_RULES";
field public static final String QUERY_USERS = "android.permission.QUERY_USERS";
field public static final String RADIO_SCAN_WITHOUT_LOCATION = "android.permission.RADIO_SCAN_WITHOUT_LOCATION";
@@ -3793,6 +3794,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

@@ -7040,6 +7040,15 @@
android:protectionLevel="signature|knownSigner"
android:knownCerts="@array/config_healthConnectMigrationKnownSigners" />
<!-- @SystemApi Allows an app to query apps in clone profile. The permission is
bidirectional in nature, i.e. cloned apps would be able to query apps in root user.
The permission is not meant for 3P apps as of now.
<p>Protection level: signature|privileged
@hide
-->
<permission android:name="android.permission.QUERY_CLONED_APPS"
android:protectionLevel="signature|privileged" />
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->

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