Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a75537b4 authored by Todd Kennedy's avatar Todd Kennedy Committed by The Android Automerger
Browse files

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
parent e7cf91a1
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -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
+256 −18
Original line number Diff line number Diff line
@@ -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;