Merge changes from topic "ir_3P"
* changes:
Changes in queryIntentAcitivities api for intent redirection
Adding a new permission to interact across clone profile apps.
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 299bfa2..4e882d8 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -248,6 +248,7 @@
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 @@
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 da36da5..1a6f6b8 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -783,6 +783,7 @@
GET_DISABLED_COMPONENTS,
GET_DISABLED_UNTIL_USED_COMPONENTS,
GET_UNINSTALLED_PACKAGES,
+ MATCH_CLONE_PROFILE
})
@Retention(RetentionPolicy.SOURCE)
public @interface ResolveInfoFlagsBits {}
@@ -1113,6 +1114,19 @@
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
*/
public static final int GET_ATTRIBUTIONS = 0x80000000;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3f18e5a..f74ebc4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -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. -->
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 2752104..c2f0f52 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 @@
*/
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 @@
*/
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 397fdd8..e149b04 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 @@
* @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 @@
* @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 @@
// 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 @@
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 @@
* @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 @@
ephemeral activities.
*/
candidates = resolveInfoFromCrossProfileDomainInfo(crossProfileCandidates);
-
return new QueryIntentActivitiesResult(computer.applyPostResolutionFilter(candidates,
instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
userId, intent));
@@ -404,11 +409,10 @@
*/
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 @@
* @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 @@
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 @@
* @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 @@
// 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 @@
// 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 @@
// calling cross profile strategy to filter corresponding results
result.addAll(filterCrossProfileCandidatesWithDomainPreferredActivities(computer,
intent, matchFlags, categorizeResolveInfoByTargetUser, userId,
- highestApproval));
+ highestApproval, resolveForStart));
}
}
@@ -612,11 +618,13 @@
* 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 @@
// 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 492f915..999706a 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 @@
/**
* 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 @@
// 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;
+ }
}