Adds queries->provider tag
This change adds support for the <provider> tag inside of the <queries>
tag to support more succinct declaration that an app would like to see
the provider of a given authority.
Test: atest AppEnumerationTests AppsFilterTest
Bug: 136675067
Change-Id: Ie0f73213fae7a3a0619238e44063d4e5be157201
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java
index fbe5a48..da17ff3 100644
--- a/core/java/android/content/pm/parsing/AndroidPackage.java
+++ b/core/java/android/content/pm/parsing/AndroidPackage.java
@@ -286,6 +286,8 @@
List<String> getQueriesPackages();
+ Set<String> getQueriesProviders();
+
String getRealPackage();
// TODO(b/135203078): Rename to getRequiredFeatures? Somewhat ambiguous whether "Req" is
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
index 5c8c9a4..548d82a 100644
--- a/core/java/android/content/pm/parsing/ApkParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkParseUtils.java
@@ -96,6 +96,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.StringTokenizer;
/** @hide */
public class ApkParseUtils {
@@ -1817,6 +1818,25 @@
);
}
parsingPackage.addQueriesPackage(packageName.intern());
+ } else if (parser.getName().equals("provider")) {
+ final TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestQueriesProvider);
+ try {
+ final String authorities =
+ sa.getString(R.styleable.AndroidManifestQueriesProvider_authorities);
+ if (TextUtils.isEmpty(authorities)) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Authority missing from provider tag."
+ );
+ }
+ StringTokenizer authoritiesTokenizer = new StringTokenizer(authorities, ";");
+ while (authoritiesTokenizer.hasMoreElements()) {
+ parsingPackage.addQueriesProvider(authoritiesTokenizer.nextToken());
+ }
+ } finally {
+ sa.recycle();
+ }
}
}
return parseInput.success(parsingPackage);
diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java
index fe8307c..0df9500 100644
--- a/core/java/android/content/pm/parsing/PackageImpl.java
+++ b/core/java/android/content/pm/parsing/PackageImpl.java
@@ -216,6 +216,9 @@
private ArrayList<String> queriesPackages;
@Nullable
+ private ArraySet<String> queriesProviders;
+
+ @Nullable
private ArrayMap<String, ComponentParseUtils.ParsedProcess> processes;
private String[] splitClassLoaderNames;
@@ -957,6 +960,12 @@
}
@Override
+ public ParsingPackage addQueriesProvider(String authority) {
+ this.queriesProviders = ArrayUtils.add(this.queriesProviders, authority);
+ return this;
+ }
+
+ @Override
public PackageImpl setProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> processes) {
this.processes = processes;
return this;
@@ -2975,6 +2984,11 @@
return queriesPackages;
}
+ @Override
+ public Set<String> getQueriesProviders() {
+ return queriesProviders;
+ }
+
private static void internStringArrayList(List<String> list) {
if (list != null) {
final int N = list.size();
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 9ddcc09..a2fe064 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -100,6 +100,8 @@
ParsingPackage addQueriesPackage(String packageName);
+ ParsingPackage addQueriesProvider(String authority);
+
ParsingPackage setProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> processes);
ParsingPackage asSplit(
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b22e186..c66261b 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2056,6 +2056,9 @@
<attr name="name" />
</declare-styleable>
<declare-styleable name="AndroidManifestQueriesIntent" parent="AndroidManifestQueries" />
+ <declare-styleable name="AndroidManifestQueriesProvider" parent="AndroidManifestQueries" >
+ <attr name="authorities" />
+ </declare-styleable>
<!-- The <code>static-library</code> tag declares that this apk is providing itself
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 8c13b5b..d629b54 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -33,7 +33,6 @@
import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
import android.content.pm.parsing.ComponentParseUtils.ParsedService;
-import android.net.Uri;
import android.os.Binder;
import android.os.Process;
import android.os.Trace;
@@ -87,10 +86,10 @@
private final SparseSetArray<Integer> mQueriesViaPackage = new SparseSetArray<>();
/**
- * A mapping from the set of App IDs that query others via intent to the list
- * of packages that the intents resolve to.
+ * A mapping from the set of App IDs that query others via component match to the list
+ * of packages that the they resolve to.
*/
- private final SparseSetArray<Integer> mQueriesViaIntent = new SparseSetArray<>();
+ private final SparseSetArray<Integer> mQueriesViaComponent = new SparseSetArray<>();
/**
* A set of App IDs that are always queryable by any package, regardless of their manifest
@@ -206,16 +205,19 @@
}
/** Returns true if the querying package may query for the potential target package */
- private static boolean canQueryViaIntent(AndroidPackage querying,
+ private static boolean canQueryViaComponents(AndroidPackage querying,
AndroidPackage potentialTarget) {
- if (querying.getQueriesIntents() == null) {
- return false;
- }
- for (Intent intent : querying.getQueriesIntents()) {
- if (matches(intent, potentialTarget)) {
- return true;
+ if (querying.getQueriesIntents() != null) {
+ for (Intent intent : querying.getQueriesIntents()) {
+ if (matchesIntentFilters(intent, potentialTarget)) {
+ return true;
+ }
}
}
+ if (querying.getQueriesProviders() != null
+ && matchesProviders(querying.getQueriesProviders(), potentialTarget)) {
+ return true;
+ }
return false;
}
@@ -238,24 +240,25 @@
return false;
}
- private static boolean matches(Intent intent, AndroidPackage potentialTarget) {
+ private static boolean matchesProviders(
+ Set<String> queriesAuthorities, AndroidPackage potentialTarget) {
for (int p = ArrayUtils.size(potentialTarget.getProviders()) - 1; p >= 0; p--) {
ParsedProvider provider = potentialTarget.getProviders().get(p);
if (!provider.isExported()) {
continue;
}
- final Uri data = intent.getData();
- if (!"content".equalsIgnoreCase(intent.getScheme()) || data == null
- || provider.getAuthority() == null) {
- continue;
- }
- StringTokenizer authorities = new StringTokenizer(provider.getAuthority(), ";", false);
+ StringTokenizer authorities = new StringTokenizer(provider.getAuthority(), ";",
+ false);
while (authorities.hasMoreElements()) {
- if (Objects.equals(authorities.nextElement(), data.getAuthority())) {
+ if (queriesAuthorities.contains(authorities.nextToken())) {
return true;
}
}
}
+ return false;
+ }
+
+ private static boolean matchesIntentFilters(Intent intent, AndroidPackage potentialTarget) {
for (int s = ArrayUtils.size(potentialTarget.getServices()) - 1; s >= 0; s--) {
ParsedService service = potentialTarget.getServices().get(s);
if (!service.exported) {
@@ -368,8 +371,8 @@
final AndroidPackage existingPkg = existingSetting.pkg;
// let's evaluate the ability of already added packages to see this new package
if (!newIsForceQueryable) {
- if (canQueryViaIntent(existingPkg, newPkg)) {
- mQueriesViaIntent.add(existingSetting.appId, newPkgSetting.appId);
+ if (canQueryViaComponents(existingPkg, newPkg)) {
+ mQueriesViaComponent.add(existingSetting.appId, newPkgSetting.appId);
}
if (canQueryViaPackage(existingPkg, newPkg)
|| canQueryAsInstaller(existingSetting, newPkg)) {
@@ -378,8 +381,8 @@
}
// now we'll evaluate our new package's ability to see existing packages
if (!mForceQueryable.contains(existingSetting.appId)) {
- if (canQueryViaIntent(newPkg, existingPkg)) {
- mQueriesViaIntent.add(newPkgSetting.appId, existingSetting.appId);
+ if (canQueryViaComponents(newPkg, existingPkg)) {
+ mQueriesViaComponent.add(newPkgSetting.appId, existingSetting.appId);
}
if (canQueryViaPackage(newPkg, existingPkg)
|| canQueryAsInstaller(newPkgSetting, existingPkg)) {
@@ -427,9 +430,9 @@
}
}
- mQueriesViaIntent.remove(setting.appId);
- for (int i = mQueriesViaIntent.size() - 1; i >= 0; i--) {
- mQueriesViaIntent.remove(mQueriesViaIntent.keyAt(i), setting.appId);
+ mQueriesViaComponent.remove(setting.appId);
+ for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) {
+ mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i), setting.appId);
}
mQueriesViaPackage.remove(setting.appId);
for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) {
@@ -594,10 +597,10 @@
Trace.endSection();
}
try {
- Trace.beginSection("mQueriesViaIntent");
- if (mQueriesViaIntent.contains(callingAppId, targetAppId)) {
+ Trace.beginSection("mQueriesViaComponent");
+ if (mQueriesViaComponent.contains(callingAppId, targetAppId)) {
if (DEBUG_LOGGING) {
- log(callingSetting, targetPkgSetting, "queries intent");
+ log(callingSetting, targetPkgSetting, "queries component");
}
return false;
}
@@ -732,7 +735,7 @@
pw.println(" queries via package name:");
dumpQueriesMap(pw, filteringAppId, mQueriesViaPackage, " ", expandPackages);
pw.println(" queries via intent:");
- dumpQueriesMap(pw, filteringAppId, mQueriesViaIntent, " ", expandPackages);
+ dumpQueriesMap(pw, filteringAppId, mQueriesViaComponent, " ", expandPackages);
pw.println(" queryable via interaction:");
for (int user : users) {
pw.append(" User ").append(Integer.toString(user)).println(":");
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 3e3f40d..e28d13a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -35,7 +35,6 @@
import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
import android.content.pm.parsing.PackageImpl;
import android.content.pm.parsing.ParsingPackage;
-import android.net.Uri;
import android.os.Build;
import android.os.Process;
import android.util.ArrayMap;
@@ -87,6 +86,17 @@
return pkg;
}
+ private static ParsingPackage pkgQueriesProvider(String packageName,
+ String... queriesAuthorities) {
+ ParsingPackage pkg = pkg(packageName);
+ if (queriesAuthorities != null) {
+ for (String authority : queriesAuthorities) {
+ pkg.addQueriesProvider(authority);
+ }
+ }
+ return pkg;
+ }
+
private static ParsingPackage pkg(String packageName, String... queriesPackages) {
ParsingPackage pkg = pkg(packageName);
if (queriesPackages != null) {
@@ -172,8 +182,7 @@
PackageSetting target = simulateAddPackage(appsFilter,
pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_UID);
PackageSetting calling = simulateAddPackage(appsFilter,
- pkg("com.some.other.package",
- new Intent().setData(Uri.parse("content://com.some.authority"))),
+ pkgQueriesProvider("com.some.other.package", "com.some.authority"),
DUMMY_CALLING_UID);
assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
@@ -188,8 +197,7 @@
PackageSetting target = simulateAddPackage(appsFilter,
pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_UID);
PackageSetting calling = simulateAddPackage(appsFilter,
- pkg("com.some.other.package",
- new Intent().setData(Uri.parse("content://com.some.other.authority"))),
+ pkgQueriesProvider("com.some.other.package", "com.some.other.authority"),
DUMMY_CALLING_UID);
assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
@@ -205,8 +213,7 @@
pkgWithProvider("com.some.package", "com.some.authority;com.some.other.authority"),
DUMMY_TARGET_UID);
PackageSetting calling = simulateAddPackage(appsFilter,
- pkg("com.some.other.package",
- new Intent().setData(Uri.parse("content://com.some.authority"))),
+ pkgQueriesProvider("com.some.other.package", "com.some.authority"),
DUMMY_CALLING_UID);
assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
@@ -266,7 +273,7 @@
appsFilter.onSystemReady();
PackageSetting target = simulateAddPackage(appsFilter,
- pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_UID);
+ pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_UID);
PackageSetting calling = simulateAddPackage(appsFilter,
pkg("com.some.other.package"), DUMMY_CALLING_UID);
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 2af118c..5aa32f8 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -391,6 +391,7 @@
manifest_action["uses-split"].Action(RequiredNameIsJavaPackage);
manifest_action["queries"]["package"].Action(RequiredNameIsJavaPackage);
manifest_action["queries"]["intent"] = intent_filter_action;
+ manifest_action["queries"]["provider"].Action(RequiredAndroidAttribute("authorities"));
// TODO: more complicated component name tag
manifest_action["key-sets"]["key-set"]["public-key"];