diff options
author | Todd Kennedy <toddke@google.com> | 2016-04-04 12:29:59 -0700 |
---|---|---|
committer | The Android Automerger <android-build@android.com> | 2016-06-24 16:52:38 -0700 |
commit | a75537b496e9df71c74c1d045ba5569631a16298 (patch) | |
tree | f21b4b6a2189183fe8ccdd280bdc79efc049def2 | |
parent | e7cf91a198de995c7440b3b64352effd2e309906 (diff) | |
download | frameworks_base-a75537b496e9df71c74c1d045ba5569631a16298.zip frameworks_base-a75537b496e9df71c74c1d045ba5569631a16298.tar.gz frameworks_base-a75537b496e9df71c74c1d045ba5569631a16298.tar.bz2 |
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
-rw-r--r-- | core/java/android/content/IntentFilter.java | 11 | ||||
-rw-r--r-- | services/core/java/com/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 3a17e23..ed5dfa5 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. * <em>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 c1d091b..7654cc9 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; @@ -8744,6 +8745,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<PackageParser.Activity> 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<E> { + public Iterator<E> generate(ActivityIntentInfo info) { + return null; + } + } + + public class ActionIterGenerator extends IterGenerator<String> { + @Override + public Iterator<String> generate(ActivityIntentInfo info) { + return info.actionsIterator(); + } + } + + public class CategoriesIterGenerator extends IterGenerator<String> { + @Override + public Iterator<String> generate(ActivityIntentInfo info) { + return info.categoriesIterator(); + } + } + + public class SchemesIterGenerator extends IterGenerator<String> { + @Override + public Iterator<String> generate(ActivityIntentInfo info) { + return info.schemesIterator(); + } + } + + public class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> { + @Override + public Iterator<IntentFilter.AuthorityEntry> generate(ActivityIntentInfo info) { + return info.authoritiesIterator(); + } + } + + /** + * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE + * MODIFIED. Do not pass in a list that should not be changed. + */ + private <T> void getIntentListSubset(List<ActivityIntentInfo> intentList, + IterGenerator<T> generator, Iterator<T> 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<ActivityIntentInfo> 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<T> 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. + * <p> + * <ul> + * <li>The priority for unbundled updates to system applications is capped to the + * priority defined on the system partition</li> + * </ul> + */ + private void adjustPriority( + List<PackageParser.Activity> 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<ActivityIntentInfo> intentListCopy = + new ArrayList<>(foundActivity.intents); + final List<ActivityIntentInfo> foundFilters = findFilters(intent); + + // find matching action subsets + final Iterator<String> 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<String> 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<String> 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<IntentFilter.AuthorityEntry> + 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); @@ -8756,10 +9006,12 @@ public class PackageManagerService extends IPackageManager.Stub { final int NI = a.intents.size(); for (int j=0; j<NI; j++) { PackageParser.ActivityIntentInfo intent = a.intents.get(j); - if (!systemApp && intent.getPriority() > 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<PackageParser.Activity> systemActivities = + ps != null && ps.pkg != null ? ps.pkg.activities : null; + adjustPriority(systemActivities, intent); } if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); @@ -8913,18 +9165,6 @@ public class PackageManagerService extends IPackageManager.Stub { out.println(); } -// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) { -// final Iterator<ResolveInfo> i = resolveInfoList.iterator(); -// final List<ResolveInfo> 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<ComponentName, PackageParser.Activity> mActivities = new ArrayMap<ComponentName, PackageParser.Activity>(); @@ -10974,8 +11214,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; |