diff options
author | Patrick Baumann <patb@google.com> | 2020-01-28 10:55:25 -0800 |
---|---|---|
committer | Patrick Baumann <patb@google.com> | 2020-02-07 17:08:30 -0800 |
commit | 9918123bac48bd77b61aef98e73a8d927dfbe338 (patch) | |
tree | f05b54483ce510fa11e86743d0ed0bb28de843d2 | |
parent | b82819fc4d5851663f2d58bf18d48d5c59bcd854 (diff) |
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
8 files changed, 90 insertions, 38 deletions
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java index fbe5a48ad61e..da17ff3cdefc 100644 --- a/core/java/android/content/pm/parsing/AndroidPackage.java +++ b/core/java/android/content/pm/parsing/AndroidPackage.java @@ -286,6 +286,8 @@ public interface AndroidPackage extends Parcelable { 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 5c8c9a41a520..548d82a6ab76 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.Arrays; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.StringTokenizer; /** @hide */ public class ApkParseUtils { @@ -1817,6 +1818,25 @@ public class ApkParseUtils { ); } 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 fe8307c7c8cd..0df950006f43 100644 --- a/core/java/android/content/pm/parsing/PackageImpl.java +++ b/core/java/android/content/pm/parsing/PackageImpl.java @@ -216,6 +216,9 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android private ArrayList<String> queriesPackages; @Nullable + private ArraySet<String> queriesProviders; + + @Nullable private ArrayMap<String, ComponentParseUtils.ParsedProcess> processes; private String[] splitClassLoaderNames; @@ -957,6 +960,12 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android } @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 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android 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 9ddcc0995fd4..a2fe064b66c3 100644 --- a/core/java/android/content/pm/parsing/ParsingPackage.java +++ b/core/java/android/content/pm/parsing/ParsingPackage.java @@ -100,6 +100,8 @@ public interface ParsingPackage extends AndroidPackage { 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 b22e1867f257..c66261bb6630 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 8c13b5bf8519..d629b547992b 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.ParsedComponent; 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 @@ public class AppsFilter { 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 @@ public class AppsFilter { } /** 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 @@ public class AppsFilter { 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 @@ public class AppsFilter { 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 @@ public class AppsFilter { } // 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 @@ public class AppsFilter { } } - 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 @@ public class AppsFilter { 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 @@ public class AppsFilter { 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 3e3f40d31d0e..e28d13a1a20c 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.ParsedActivity; 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 @@ public class AppsFilterTest { 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 @@ public class AppsFilterTest { 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 @@ public class AppsFilterTest { 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 @@ public class AppsFilterTest { 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 @@ public class AppsFilterTest { 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 2af118c40138..5aa32f868104 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -391,6 +391,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, 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"]; |