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

Commit f2ac2761 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fix issue #17082301: replacePreferredActivity is ignoring userId

It was being given the argument and just...  ignoring it.

But the bulk of this change is to make replacePreferredActivity
better about replacing -- it now detects if the request will not
make a change and, in that case, just do nothing.

The reason for this?

It turns out that each time you install an app, the telephony
system is calling this function over 20 times to set the default
SMS app.  This is almost always doing nothing, but before this
change it means we would re-write packages.xml over 20 times...!

There are definitely more improvements that can be made here (delaying
write of packages.xml to allow them to batch together, reducing
the amount of calls being made), but until then this is a big
improvement.

Change-Id: I02c4235b8ecd5c13ef53e65d13c7dc2223719cec
parent 82d6d337
Loading
Loading
Loading
Loading
+63 −0
Original line number Original line Diff line number Diff line
@@ -564,6 +564,11 @@ public class IntentFilter implements Parcelable {
        return mDataTypes != null && findMimeType(type);
        return mDataTypes != null && findMimeType(type);
    }
    }


    /** @hide */
    public final boolean hasExactDataType(String type) {
        return mDataTypes != null && mDataTypes.contains(type);
    }

    /**
    /**
     * Return the number of data types in the filter.
     * Return the number of data types in the filter.
     */
     */
@@ -681,6 +686,20 @@ public class IntentFilter implements Parcelable {
            return mPort;
            return mPort;
        }
        }


        /** @hide */
        public boolean match(AuthorityEntry other) {
            if (mWild != other.mWild) {
                return false;
            }
            if (!mHost.equals(other.mHost)) {
                return false;
            }
            if (mPort != other.mPort) {
                return false;
            }
            return true;
        }

        /**
        /**
         * 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
@@ -792,6 +811,21 @@ public class IntentFilter implements Parcelable {
        return false;
        return false;
    }
    }


    /** @hide */
    public final boolean hasDataSchemeSpecificPart(PatternMatcher ssp) {
        if (mDataSchemeSpecificParts == null) {
            return false;
        }
        final int numDataSchemeSpecificParts = mDataSchemeSpecificParts.size();
        for (int i = 0; i < numDataSchemeSpecificParts; i++) {
            final PatternMatcher pe = mDataSchemeSpecificParts.get(i);
            if (pe.getType() == ssp.getType() && pe.getPath().equals(ssp.getPath())) {
                return true;
            }
        }
        return false;
    }

    /**
    /**
     * Return an iterator over the filter's data scheme specific parts.
     * Return an iterator over the filter's data scheme specific parts.
     */
     */
@@ -860,6 +894,20 @@ public class IntentFilter implements Parcelable {
        return matchDataAuthority(data) >= 0;
        return matchDataAuthority(data) >= 0;
    }
    }


    /** @hide */
    public final boolean hasDataAuthority(AuthorityEntry auth) {
        if (mDataAuthorities == null) {
            return false;
        }
        final int numDataAuthorities = mDataAuthorities.size();
        for (int i = 0; i < numDataAuthorities; i++) {
            if (mDataAuthorities.get(i).match(auth)) {
                return true;
            }
        }
        return false;
    }

    /**
    /**
     * Return an iterator over the filter's data authorities.
     * Return an iterator over the filter's data authorities.
     */
     */
@@ -942,6 +990,21 @@ public class IntentFilter implements Parcelable {
        return false;
        return false;
    }
    }


    /** @hide */
    public final boolean hasDataPath(PatternMatcher path) {
        if (mDataPaths == null) {
            return false;
        }
        final int numDataPaths = mDataPaths.size();
        for (int i = 0; i < numDataPaths; i++) {
            final PatternMatcher pe = mDataPaths.get(i);
            if (pe.getType() == path.getType() && pe.getPath().equals(path.getPath())) {
                return true;
            }
        }
        return false;
    }

    /**
    /**
     * Return an iterator over the filter's data paths.
     * Return an iterator over the filter's data paths.
     */
     */
+118 −0
Original line number Original line Diff line number Diff line
@@ -69,6 +69,124 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
        }
        }
    }
    }


    private boolean filterEquals(IntentFilter f1, IntentFilter f2) {
        int s1 = f1.countActions();
        int s2 = f2.countActions();
        if (s1 != s2) {
            return false;
        }
        for (int i=0; i<s1; i++) {
            if (!f2.hasAction(f1.getAction(i))) {
                return false;
            }
        }
        s1 = f1.countCategories();
        s2 = f2.countCategories();
        if (s1 != s2) {
            return false;
        }
        for (int i=0; i<s1; i++) {
            if (!f2.hasCategory(f1.getCategory(i))) {
                return false;
            }
        }
        s1 = f1.countDataTypes();
        s2 = f2.countDataTypes();
        if (s1 != s2) {
            return false;
        }
        for (int i=0; i<s1; i++) {
            if (!f2.hasExactDataType(f1.getDataType(i))) {
                return false;
            }
        }
        s1 = f1.countDataSchemes();
        s2 = f2.countDataSchemes();
        if (s1 != s2) {
            return false;
        }
        for (int i=0; i<s1; i++) {
            if (!f2.hasDataScheme(f1.getDataScheme(i))) {
                return false;
            }
        }
        s1 = f1.countDataAuthorities();
        s2 = f2.countDataAuthorities();
        if (s1 != s2) {
            return false;
        }
        for (int i=0; i<s1; i++) {
            if (!f2.hasDataAuthority(f1.getDataAuthority(i))) {
                return false;
            }
        }
        s1 = f1.countDataPaths();
        s2 = f2.countDataPaths();
        if (s1 != s2) {
            return false;
        }
        for (int i=0; i<s1; i++) {
            if (!f2.hasDataPath(f1.getDataPath(i))) {
                return false;
            }
        }
        s1 = f1.countDataSchemeSpecificParts();
        s2 = f2.countDataSchemeSpecificParts();
        if (s1 != s2) {
            return false;
        }
        for (int i=0; i<s1; i++) {
            if (!f2.hasDataSchemeSpecificPart(f1.getDataSchemeSpecificPart(i))) {
                return false;
            }
        }
        return true;
    }

    private ArrayList<F> collectFilters(F[] array, IntentFilter matching) {
        ArrayList<F> res = null;
        if (array != null) {
            for (int i=0; i<array.length; i++) {
                F cur = array[i];
                if (cur == null) {
                    break;
                }
                if (filterEquals(cur, matching)) {
                    if (res == null) {
                        res = new ArrayList<>();
                    }
                    res.add(cur);
                }
            }
        }
        return res;
    }

    public ArrayList<F> findFilters(IntentFilter matching) {
        if (matching.countDataSchemes() == 1) {
            // Fast case.
            return collectFilters(mSchemeToFilter.get(matching.getDataScheme(0)), matching);
        } else if (matching.countDataTypes() != 0 && matching.countActions() == 1) {
            // Another fast case.
            return collectFilters(mTypedActionToFilter.get(matching.getAction(0)), matching);
        } else if (matching.countDataTypes() == 0 && matching.countDataSchemes() == 0
                && matching.countActions() == 1) {
            // Last fast case.
            return collectFilters(mActionToFilter.get(matching.getAction(0)), matching);
        } else {
            ArrayList<F> res = null;
            for (F cur : mFilters) {
                if (filterEquals(cur, matching)) {
                    if (res == null) {
                        res = new ArrayList<>();
                    }
                    res.add(cur);
                }
            }
            return res;
        }
    }

    public void removeFilter(F f) {
    public void removeFilter(F f) {
        removeFilterInternal(f);
        removeFilterInternal(f);
        mFilters.remove(f);
        mFilters.remove(f);
+56 −22
Original line number Original line Diff line number Diff line
@@ -2920,7 +2920,8 @@ public class PackageManagerService extends IPackageManager.Stub {
        findPreferredActivity(intent, resolvedType,
        findPreferredActivity(intent, resolvedType,
                flags, query, 0, false, true, false, userId);
                flags, query, 0, false, true, false, userId);
        // Add the new activity as the last chosen for this filter
        // Add the new activity as the last chosen for this filter
        addPreferredActivityInternal(filter, match, null, activity, false, userId);
        addPreferredActivityInternal(filter, match, null, activity, false, userId,
                "Setting last chosen");
    }
    }
    @Override
    @Override
@@ -11462,11 +11463,13 @@ public class PackageManagerService extends IPackageManager.Stub {
    @Override
    @Override
    public void addPreferredActivity(IntentFilter filter, int match,
    public void addPreferredActivity(IntentFilter filter, int match,
            ComponentName[] set, ComponentName activity, int userId) {
            ComponentName[] set, ComponentName activity, int userId) {
        addPreferredActivityInternal(filter, match, set, activity, true, userId);
        addPreferredActivityInternal(filter, match, set, activity, true, userId,
                "Adding preferred");
    }
    }
    private void addPreferredActivityInternal(IntentFilter filter, int match,
    private void addPreferredActivityInternal(IntentFilter filter, int match,
            ComponentName[] set, ComponentName activity, boolean always, int userId) {
            ComponentName[] set, ComponentName activity, boolean always, int userId,
            String opname) {
        // writer
        // writer
        int callingUid = Binder.getCallingUid();
        int callingUid = Binder.getCallingUid();
        enforceCrossUserPermission(callingUid, userId, true, "add preferred activity");
        enforceCrossUserPermission(callingUid, userId, true, "add preferred activity");
@@ -11488,10 +11491,11 @@ public class PackageManagerService extends IPackageManager.Stub {
                        android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
                        android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
            }
            }
            Slog.i(TAG, "Adding preferred activity " + activity + " for user " + userId + " :");
            PreferredIntentResolver pir = mSettings.editPreferredActivitiesLPw(userId);
            Slog.i(TAG, opname + " activity " + activity.flattenToShortString() + " for user "
                    + userId + ":");
            filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
            filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
            mSettings.editPreferredActivitiesLPw(userId).addFilter(
            pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
                    new PreferredActivity(filter, match, set, activity, always));
            mSettings.writePackageRestrictionsLPr(userId);
            mSettings.writePackageRestrictionsLPr(userId);
        }
        }
    }
    }
@@ -11514,7 +11518,6 @@ public class PackageManagerService extends IPackageManager.Stub {
        final int callingUid = Binder.getCallingUid();
        final int callingUid = Binder.getCallingUid();
        enforceCrossUserPermission(callingUid, userId, true, "replace preferred activity");
        enforceCrossUserPermission(callingUid, userId, true, "replace preferred activity");
        final int callingUserId = UserHandle.getUserId(callingUid);
        synchronized (mPackages) {
        synchronized (mPackages) {
            if (mContext.checkCallingOrSelfPermission(
            if (mContext.checkCallingOrSelfPermission(
                    android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
                    android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
@@ -11529,30 +11532,61 @@ public class PackageManagerService extends IPackageManager.Stub {
                        android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
                        android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
            }
            }
            PreferredIntentResolver pir = mSettings.mPreferredActivities.get(callingUserId);
            PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
            if (pir != null) {
            if (pir != null) {
                Intent intent = new Intent(filter.getAction(0)).addCategory(filter.getCategory(0));
                // Get all of the existing entries that exactly match this filter.
                if (filter.countDataSchemes() == 1) {
                ArrayList<PreferredActivity> existing = pir.findFilters(filter);
                    Uri.Builder builder = new Uri.Builder();
                if (existing != null && existing.size() == 1) {
                    builder.scheme(filter.getDataScheme(0));
                    PreferredActivity cur = existing.get(0);
                    intent.setData(builder.build());
                    if (DEBUG_PREFERRED) {
                }
                        Slog.i(TAG, "Checking replace of preferred:");
                List<PreferredActivity> matches = pir.queryIntent(
                        filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
                        intent, null, true, callingUserId);
                        if (!cur.mPref.mAlways) {
                            Slog.i(TAG, "  -- CUR; not mAlways!");
                        } else {
                            Slog.i(TAG, "  -- CUR: mMatch=" + cur.mPref.mMatch);
                            Slog.i(TAG, "  -- CUR: mSet="
                                    + Arrays.toString(cur.mPref.mSetComponents));
                            Slog.i(TAG, "  -- CUR: mComponent=" + cur.mPref.mShortComponent);
                            Slog.i(TAG, "  -- NEW: mMatch="
                                    + (match&IntentFilter.MATCH_CATEGORY_MASK));
                            Slog.i(TAG, "  -- CUR: mSet=" + Arrays.toString(set));
                            Slog.i(TAG, "  -- CUR: mComponent=" + activity.flattenToShortString());
                        }
                    }
                    if (cur.mPref.mAlways && cur.mPref.mComponent.equals(activity)
                            && cur.mPref.mMatch == (match&IntentFilter.MATCH_CATEGORY_MASK)
                            && cur.mPref.sameSet(set)) {
                        if (DEBUG_PREFERRED) {
                        if (DEBUG_PREFERRED) {
                    Slog.i(TAG, matches.size() + " preferred matches for " + intent);
                            Slog.i(TAG, "Replacing with same preferred activity "
                                    + cur.mPref.mShortComponent + " for user "
                                    + userId + ":");
                            filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
                        } else {
                            Slog.i(TAG, "Replacing with same preferred activity "
                                    + cur.mPref.mShortComponent + " for user "
                                    + userId);
                        }
                        return;
                    }
                    }
                for (int i = 0; i < matches.size(); i++) {
                }
                    PreferredActivity pa = matches.get(i);
                if (DEBUG_PREFERRED) {
                if (DEBUG_PREFERRED) {
                        Slog.i(TAG, "Removing preferred activity "
                    Slog.i(TAG, existing.size() + " existing preferred matches for:");
                                + pa.mPref.mComponent + ":");
                    filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
                    filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
                }
                }
                for (int i = 0; i < existing.size(); i++) {
                    PreferredActivity pa = existing.get(i);
                    if (DEBUG_PREFERRED) {
                        Slog.i(TAG, "Removing existing preferred activity "
                                + pa.mPref.mComponent + ":");
                        pa.dump(new LogPrinter(Log.INFO, TAG), "  ");
                    }
                    pir.removeFilter(pa);
                    pir.removeFilter(pa);
                }
                }
            }
            }
            addPreferredActivityInternal(filter, match, set, activity, true, callingUserId);
            addPreferredActivityInternal(filter, match, set, activity, true, userId,
                    "Replacing preferred");
        }
        }
    }
    }
+31 −5
Original line number Original line Diff line number Diff line
@@ -44,10 +44,10 @@ public class PreferredComponent {
    // Whether this is to be the one that's always chosen. If false, it's the most recently chosen.
    // Whether this is to be the one that's always chosen. If false, it's the most recently chosen.
    public boolean mAlways;
    public boolean mAlways;


    private final String[] mSetPackages;
    final String[] mSetPackages;
    private final String[] mSetClasses;
    final String[] mSetClasses;
    private final String[] mSetComponents;
    final String[] mSetComponents;
    private final String mShortComponent;
    final String mShortComponent;
    private String mParseError;
    private String mParseError;


    private final Callbacks mCallbacks;
    private final Callbacks mCallbacks;
@@ -193,7 +193,12 @@ public class PreferredComponent {
    }
    }


    public boolean sameSet(List<ResolveInfo> query, int priority) {
    public boolean sameSet(List<ResolveInfo> query, int priority) {
        if (mSetPackages == null) return false;
        if (mSetPackages == null) {
            return query == null;
        }
        if (query == null) {
            return false;
        }
        final int NQ = query.size();
        final int NQ = query.size();
        final int NS = mSetPackages.length;
        final int NS = mSetPackages.length;
        int numMatch = 0;
        int numMatch = 0;
@@ -215,6 +220,27 @@ public class PreferredComponent {
        return numMatch == NS;
        return numMatch == NS;
    }
    }


    public boolean sameSet(ComponentName[] comps) {
        if (mSetPackages == null) return false;
        final int NQ = comps.length;
        final int NS = mSetPackages.length;
        int numMatch = 0;
        for (int i=0; i<NQ; i++) {
            ComponentName cn = comps[i];
            boolean good = false;
            for (int j=0; j<NS; j++) {
                if (mSetPackages[j].equals(cn.getPackageName())
                        && mSetClasses[j].equals(cn.getClassName())) {
                    numMatch++;
                    good = true;
                    break;
                }
            }
            if (!good) return false;
        }
        return numMatch == NS;
    }

    public void dump(PrintWriter out, String prefix, Object ident) {
    public void dump(PrintWriter out, String prefix, Object ident) {
        out.print(prefix); out.print(
        out.print(prefix); out.print(
                Integer.toHexString(System.identityHashCode(ident)));
                Integer.toHexString(System.identityHashCode(ident)));