From c2e96d45d27ab1465aaef89c1a3161708c714bcd Mon Sep 17 00:00:00 2001 From: Todd Kennedy Date: Thu, 8 Sep 2016 15:34:03 -0700 Subject: [PATCH] Add filter ordering Filter ordering allows automatic disambiguation between multiple filters that matching a pattern. Ordering currently only works for EphemeralResolveInfo objects. Bug: 30837021 Change-Id: Ia217218c7c7d159dbd75d7733c45556e690d06d2 --- core/java/android/content/IntentFilter.java | 12 ++++ .../com/android/server/IntentResolver.java | 8 +++ .../server/pm/PackageManagerService.java | 60 ++++++++++++++++++- 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 22ab43bbb4292..d07b545735479 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -265,6 +265,7 @@ public class IntentFilter implements Parcelable { public static final String SCHEME_HTTPS = "https"; private int mPriority; + private int mOrder; private final ArrayList mActions; private ArrayList mCategories = null; private ArrayList mDataSchemes = null; @@ -425,6 +426,7 @@ public class IntentFilter implements Parcelable { */ public IntentFilter(IntentFilter o) { mPriority = o.mPriority; + mOrder = o.mOrder; mActions = new ArrayList(o.mActions); if (o.mCategories != null) { mCategories = new ArrayList(o.mCategories); @@ -477,6 +479,16 @@ public class IntentFilter implements Parcelable { return mPriority; } + /** @hide */ + public final void setOrder(int order) { + mOrder = order; + } + + /** @hide */ + public final int getOrder() { + return mOrder; + } + /** * Set whether this filter will needs to be automatically verified against its data URIs or not. * The default is false. diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java index 3fdccebd02288..83d374c41a51e 100644 --- a/services/core/java/com/android/server/IntentResolver.java +++ b/services/core/java/com/android/server/IntentResolver.java @@ -364,6 +364,7 @@ public abstract class IntentResolver { buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, listCut.get(i), resultList, userId); } + filterResults(resultList); sortResults(resultList); return resultList; } @@ -457,6 +458,7 @@ public abstract class IntentResolver { buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, schemeCut, finalList, userId); } + filterResults(finalList); sortResults(finalList); if (debug) { @@ -521,6 +523,12 @@ public abstract class IntentResolver { Collections.sort(results, mResolvePrioritySorter); } + /** + * Apply filtering to the results. This happens before the results are sorted. + */ + protected void filterResults(List results) { + } + protected void dumpFilter(PrintWriter out, String prefix, F filter) { out.print(prefix); out.println(filter); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f84356bdb2b7d..5e98b15f4d7d7 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -212,6 +212,7 @@ import android.util.ExceptionUtils; import android.util.Log; import android.util.LogPrinter; import android.util.MathUtils; +import android.util.Pair; import android.util.PrintStreamPrinter; import android.util.Slog; import android.util.SparseArray; @@ -11229,6 +11230,19 @@ public class PackageManagerService extends IPackageManager.Stub { private static final class EphemeralIntentResolver extends IntentResolver { + /** + * The result that has the highest defined order. Ordering applies on a + * per-package basis. Mapping is from package name to Pair of order and + * EphemeralResolveInfo. + *

+ * NOTE: This is implemented as a field variable for convenience and efficiency. + * By having a field variable, we're able to track filter ordering as soon as + * a non-zero order is defined. Otherwise, multiple loops across the result set + * would be needed to apply ordering. If the intent resolver becomes re-entrant, + * this needs to be contained entirely within {@link #filterResults()}. + */ + final ArrayMap> mOrderResult = new ArrayMap<>(); + @Override protected EphemeralResolveIntentInfo[] newArray(int size) { return new EphemeralResolveIntentInfo[size]; @@ -11245,7 +11259,51 @@ public class PackageManagerService extends IPackageManager.Stub { if (!sUserManager.exists(userId)) { return null; } - return info.getEphemeralResolveInfo(); + final String packageName = info.getEphemeralResolveInfo().getPackageName(); + final Integer order = info.getOrder(); + final Pair lastOrderResult = + mOrderResult.get(packageName); + // ordering is enabled and this item's order isn't high enough + if (lastOrderResult != null && lastOrderResult.first >= order) { + return null; + } + final EphemeralResolveInfo res = info.getEphemeralResolveInfo(); + if (order > 0) { + // non-zero order, enable ordering + mOrderResult.put(packageName, new Pair<>(order, res)); + } + return res; + } + + @Override + protected void filterResults(List results) { + // only do work if ordering is enabled [most of the time it won't be] + if (mOrderResult.size() == 0) { + return; + } + int resultSize = results.size(); + for (int i = 0; i < resultSize; i++) { + final EphemeralResolveInfo info = results.get(i); + final String packageName = info.getPackageName(); + final Pair savedInfo = mOrderResult.get(packageName); + if (savedInfo == null) { + // package doesn't having ordering + continue; + } + if (savedInfo.second == info) { + // circled back to the highest ordered item; remove from order list + mOrderResult.remove(savedInfo); + if (mOrderResult.size() == 0) { + // no more ordered items + break; + } + continue; + } + // item has a worse order, remove it from the result list + results.remove(i); + resultSize--; + i--; + } } }