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
This commit is contained in:
Todd Kennedy
2016-04-04 12:29:59 -07:00
parent d385a6d95f
commit d6174e7402
2 changed files with 266 additions and 7 deletions

View File

@@ -700,6 +700,15 @@ public class IntentFilter implements Parcelable {
return true; 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. * Determine whether this AuthorityEntry matches the given data Uri.
* <em>Note that this comparison is case-sensitive, unlike formal * <em>Note that this comparison is case-sensitive, unlike formal
@@ -734,7 +743,7 @@ public class IntentFilter implements Parcelable {
} }
return MATCH_CATEGORY_HOST; return MATCH_CATEGORY_HOST;
} }
}; }
/** /**
* Add a new Intent data "scheme specific part" to match against. The filter must * Add a new Intent data "scheme specific part" to match against. The filter must

View File

@@ -244,6 +244,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private static final boolean DEBUG_PACKAGE_SCANNING = false; private static final boolean DEBUG_PACKAGE_SCANNING = false;
private static final boolean DEBUG_VERIFY = false; private static final boolean DEBUG_VERIFY = false;
private static final boolean DEBUG_DEXOPT = false; private static final boolean DEBUG_DEXOPT = false;
private static final boolean DEBUG_FILTERS = false;
private static final boolean DEBUG_ABI_SELECTION = false; private static final boolean DEBUG_ABI_SELECTION = false;
private static final int RADIO_UID = Process.PHONE_UID; private static final int RADIO_UID = Process.PHONE_UID;
@@ -7268,6 +7269,255 @@ public class PackageManagerService extends IPackageManager.Stub {
return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); 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 = isSystemApp(applicationInfo);
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) { public final void addActivity(PackageParser.Activity a, String type) {
final boolean systemApp = isSystemApp(a.info.applicationInfo); final boolean systemApp = isSystemApp(a.info.applicationInfo);
mActivities.put(a.getComponentName(), a); mActivities.put(a.getComponentName(), a);
@@ -7280,10 +7530,12 @@ public class PackageManagerService extends IPackageManager.Stub {
final int NI = a.intents.size(); final int NI = a.intents.size();
for (int j=0; j<NI; j++) { for (int j=0; j<NI; j++) {
PackageParser.ActivityIntentInfo intent = a.intents.get(j); PackageParser.ActivityIntentInfo intent = a.intents.get(j);
if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) { if ("activity".equals(type)) {
intent.setPriority(0); final PackageSetting ps =
Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity " mSettings.getDisabledSystemPkgLPr(intent.activity.info.packageName);
+ a.className + " with priority > 0, forcing to 0"); final List<PackageParser.Activity> systemActivities =
ps != null && ps.pkg != null ? ps.pkg.activities : null;
adjustPriority(systemActivities, intent);
} }
if (DEBUG_SHOW_INFO) { if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:"); Log.v(TAG, " IntentFilter:");
@@ -9290,8 +9542,6 @@ public class PackageManagerService extends IPackageManager.Stub {
* Called after the source arguments are copied. This is used mostly for * 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 * MoveParams when it needs to read the source file to put it in the
* destination. * destination.
*
* @return
*/ */
int doPostCopy(int uid) { int doPostCopy(int uid) {
return PackageManager.INSTALL_SUCCEEDED; return PackageManager.INSTALL_SUCCEEDED;