diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 314e27050423b..81d8e24ae8dae 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -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
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 900454d59e507..895ffefe09e06 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -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
+ *
+ * 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
+ *
+ */
+ @SystemApi
+ public static final int MATCH_CLONE_PROFILE = 0x20000000;
+
/**
* {@link PackageInfo} flag: return all attributions declared in the package manifest
*/
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 2752104371435..c2f0f52623051 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -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);
}
/*
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java
index 397fdd8e34a10..e149b04a3e4b9 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java
@@ -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 resolveIntent(@NonNull Computer computer, Intent intent,
String resolvedType, int userId, long flags, String pkgName,
- boolean hasNonNegativePriorityResult,
+ boolean hasNonNegativePriorityResult, boolean resolveForStart,
Function 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 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 pkgSettingFunction,
Set 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 filterCandidatesWithDomainPreferredActivitiesLPr(Computer computer,
Intent intent, long matchFlags, List candidates,
List crossProfileCandidates, int userId,
- boolean areWebInstantAppsDisabled,
+ boolean areWebInstantAppsDisabled, boolean resolveForStart,
Function pkgSettingFunction) {
final boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0;
@@ -439,7 +444,7 @@ public class CrossProfileIntentResolverEngine {
final List 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 filterCandidatesWithDomainPreferredActivitiesLPrBody(
Computer computer, Intent intent, long matchFlags, List candidates,
List crossProfileCandidates, int userId,
- boolean areWebInstantAppsDisabled, boolean debug,
+ boolean areWebInstantAppsDisabled, boolean debug, boolean resolveForStart,
Function pkgSettingFunction) {
final ArrayList result = new ArrayList<>();
final ArrayList 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, 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 filterCrossProfileCandidatesWithDomainPreferredActivities(
Computer computer, Intent intent, long flags, SparseArray>
- categorizeResolveInfoByTargetUser, int sourceUserId, int highestApprovalLevel) {
+ categorizeResolveInfoByTargetUser, int sourceUserId, int highestApprovalLevel,
+ boolean resolveForStart) {
List 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
diff --git a/services/core/java/com/android/server/pm/NoFilteringResolver.java b/services/core/java/com/android/server/pm/NoFilteringResolver.java
index 492f9158be85e..999706a431144 100644
--- a/services/core/java/com/android/server/pm/NoFilteringResolver.java
+++ b/services/core/java/com/android/server/pm/NoFilteringResolver.java
@@ -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;
+ }
}