From eeb970ada10d37495ad7a8a4b14ad0506b640eea Mon Sep 17 00:00:00 2001 From: Todd Kennedy Date: Mon, 4 Apr 2016 12:29:59 -0700 Subject: DO NOT MERGE Fix intent filter priorities Since this is a backport, there is only one rule that guards intent filter priorities: 1) Updates will NOT be granted a priority greater than the priority defined on the system image. Bug: 27450489 Change-Id: Ifcec4d7a59e684331399abc41eea1bd6876155a4 --- core/java/android/content/IntentFilter.java | 11 +- .../android/server/pm/PackageManagerService.java | 274 +++++++++++++++++++-- 2 files changed, 266 insertions(+), 19 deletions(-) diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 3a17e23b0547..ed5dfa5393ec 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -883,6 +883,15 @@ public class IntentFilter implements Parcelable { return true; } + @Override + public boolean equals(Object obj) { + if (obj instanceof AuthorityEntry) { + final AuthorityEntry other = (AuthorityEntry)obj; + return match(other); + } + return false; + } + /** * Determine whether this AuthorityEntry matches the given data Uri. * Note that this comparison is case-sensitive, unlike formal @@ -917,7 +926,7 @@ public class IntentFilter implements Parcelable { } return MATCH_CATEGORY_HOST; } - }; + } /** * Add a new Intent data "scheme specific part" to match against. The filter must diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 25c4d4210370..d19da1c1c5c8 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -297,6 +297,7 @@ public class PackageManagerService extends IPackageManager.Stub { private static final boolean DEBUG_PACKAGE_SCANNING = false; private static final boolean DEBUG_VERIFY = false; private static final boolean DEBUG_DEXOPT = false; + private static final boolean DEBUG_FILTERS = false; private static final boolean DEBUG_ABI_SELECTION = false; static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false; @@ -8730,6 +8731,255 @@ public class PackageManagerService extends IPackageManager.Stub { return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); } + /** + * Finds a privileged activity that matches the specified activity names. + */ + private PackageParser.Activity findMatchingActivity( + List activityList, ActivityInfo activityInfo) { + for (PackageParser.Activity sysActivity : activityList) { + if (sysActivity.info.name.equals(activityInfo.name)) { + return sysActivity; + } + if (sysActivity.info.name.equals(activityInfo.targetActivity)) { + return sysActivity; + } + if (sysActivity.info.targetActivity != null) { + if (sysActivity.info.targetActivity.equals(activityInfo.name)) { + return sysActivity; + } + if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) { + return sysActivity; + } + } + } + return null; + } + + public class IterGenerator { + public Iterator generate(ActivityIntentInfo info) { + return null; + } + } + + public class ActionIterGenerator extends IterGenerator { + @Override + public Iterator generate(ActivityIntentInfo info) { + return info.actionsIterator(); + } + } + + public class CategoriesIterGenerator extends IterGenerator { + @Override + public Iterator generate(ActivityIntentInfo info) { + return info.categoriesIterator(); + } + } + + public class SchemesIterGenerator extends IterGenerator { + @Override + public Iterator generate(ActivityIntentInfo info) { + return info.schemesIterator(); + } + } + + public class AuthoritiesIterGenerator extends IterGenerator { + @Override + public Iterator generate(ActivityIntentInfo info) { + return info.authoritiesIterator(); + } + } + + /** + * WARNING for performance reasons, the passed in intentList WILL BE + * MODIFIED. Do not pass in a list that should not be changed. + */ + private void getIntentListSubset(List intentList, + IterGenerator generator, Iterator searchIterator) { + // loop through the set of actions; every one must be found in the intent filter + while (searchIterator.hasNext()) { + // we must have at least one filter in the list to consider a match + if (intentList.size() == 0) { + break; + } + + final T searchAction = searchIterator.next(); + + // loop through the set of intent filters + final Iterator intentIter = intentList.iterator(); + while (intentIter.hasNext()) { + final ActivityIntentInfo intentInfo = intentIter.next(); + boolean selectionFound = false; + + // loop through the intent filter's selection criteria; at least one + // of them must match the searched criteria + final Iterator intentSelectionIter = generator.generate(intentInfo); + while (intentSelectionIter != null && intentSelectionIter.hasNext()) { + final T intentSelection = intentSelectionIter.next(); + if (intentSelection != null && intentSelection.equals(searchAction)) { + selectionFound = true; + break; + } + } + + // the selection criteria wasn't found in this filter's set; this filter + // is not a potential match + if (!selectionFound) { + intentIter.remove(); + } + } + } + } + + /** + * Adjusts the priority of the given intent filter according to policy. + *

+ *

    + *
  • The priority for unbundled updates to system applications is capped to the + * priority defined on the system partition
  • + *
+ */ + private void adjustPriority( + List systemActivities, ActivityIntentInfo intent) { + // nothing to do; priority is fine as-is + if (intent.getPriority() <= 0) { + return; + } + + final ActivityInfo activityInfo = intent.activity.info; + final ApplicationInfo applicationInfo = activityInfo.applicationInfo; + + final boolean systemApp = applicationInfo.isSystemApp(); + if (!systemApp) { + // non-system applications can never define a priority >0 + Slog.w(TAG, "Non-system app; cap priority to 0;" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + intent.setPriority(0); + return; + } + + if (systemActivities == null) { + // the system package is not disabled; we're parsing the system partition + // apps on the system image get whatever priority they request + return; + } + + // system app unbundled update ... try to find the same activity + final PackageParser.Activity foundActivity = + findMatchingActivity(systemActivities, activityInfo); + if (foundActivity == null) { + // this is a new activity; it cannot obtain >0 priority + if (DEBUG_FILTERS) { + Slog.i(TAG, "New activity; cap priority to 0;" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(0); + return; + } + + // found activity, now check for filter equivalence + + // a shallow copy is enough; we modify the list, not its contents + final List intentListCopy = + new ArrayList<>(foundActivity.intents); + final List foundFilters = findFilters(intent); + + // find matching action subsets + final Iterator actionsIterator = intent.actionsIterator(); + if (actionsIterator != null) { + getIntentListSubset( + intentListCopy, new ActionIterGenerator(), actionsIterator); + if (intentListCopy.size() == 0) { + // no more intents to match; we're not equivalent + if (DEBUG_FILTERS) { + Slog.i(TAG, "Mismatched action; cap priority to 0;" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(0); + return; + } + } + + // find matching category subsets + final Iterator categoriesIterator = intent.categoriesIterator(); + if (categoriesIterator != null) { + getIntentListSubset(intentListCopy, new CategoriesIterGenerator(), + categoriesIterator); + if (intentListCopy.size() == 0) { + // no more intents to match; we're not equivalent + if (DEBUG_FILTERS) { + Slog.i(TAG, "Mismatched category; cap priority to 0;" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(0); + return; + } + } + + // find matching schemes subsets + final Iterator schemesIterator = intent.schemesIterator(); + if (schemesIterator != null) { + getIntentListSubset(intentListCopy, new SchemesIterGenerator(), + schemesIterator); + if (intentListCopy.size() == 0) { + // no more intents to match; we're not equivalent + if (DEBUG_FILTERS) { + Slog.i(TAG, "Mismatched scheme; cap priority to 0;" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(0); + return; + } + } + + // find matching authorities subsets + final Iterator + authoritiesIterator = intent.authoritiesIterator(); + if (authoritiesIterator != null) { + getIntentListSubset(intentListCopy, + new AuthoritiesIterGenerator(), + authoritiesIterator); + if (intentListCopy.size() == 0) { + // no more intents to match; we're not equivalent + if (DEBUG_FILTERS) { + Slog.i(TAG, "Mismatched authority; cap priority to 0;" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(0); + return; + } + } + + // we found matching filter(s); app gets the max priority of all intents + int cappedPriority = 0; + for (int i = intentListCopy.size() - 1; i >= 0; --i) { + cappedPriority = Math.max(cappedPriority, intentListCopy.get(i).getPriority()); + } + if (intent.getPriority() > cappedPriority) { + if (DEBUG_FILTERS) { + Slog.i(TAG, "Found matching filter(s);" + + " cap priority to " + cappedPriority + ";" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(cappedPriority); + return; + } + // all this for nothing; the requested priority was <= what was on the system + } + public final void addActivity(PackageParser.Activity a, String type) { final boolean systemApp = a.info.applicationInfo.isSystemApp(); mActivities.put(a.getComponentName(), a); @@ -8742,10 +8992,12 @@ public class PackageManagerService extends IPackageManager.Stub { final int NI = a.intents.size(); for (int j=0; j 0 && "activity".equals(type)) { - intent.setPriority(0); - Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity " - + a.className + " with priority > 0, forcing to 0"); + if ("activity".equals(type)) { + final PackageSetting ps = + mSettings.getDisabledSystemPkgLPr(intent.activity.info.packageName); + final List systemActivities = + ps != null && ps.pkg != null ? ps.pkg.activities : null; + adjustPriority(systemActivities, intent); } if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); @@ -8899,18 +9151,6 @@ public class PackageManagerService extends IPackageManager.Stub { out.println(); } -// List filterEnabled(List resolveInfoList) { -// final Iterator i = resolveInfoList.iterator(); -// final List retList = Lists.newArrayList(); -// while (i.hasNext()) { -// final ResolveInfo resolveInfo = i.next(); -// if (isEnabledLP(resolveInfo.activityInfo)) { -// retList.add(resolveInfo); -// } -// } -// return retList; -// } - // Keys are String (activity class name), values are Activity. private final ArrayMap mActivities = new ArrayMap(); @@ -10960,8 +11200,6 @@ public class PackageManagerService extends IPackageManager.Stub { * Called after the source arguments are copied. This is used mostly for * MoveParams when it needs to read the source file to put it in the * destination. - * - * @return */ int doPostCopy(int uid) { return PackageManager.INSTALL_SUCCEEDED; -- cgit v1.2.3-59-g8ed1b