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

Commit 260d9c9e authored by William Loh's avatar William Loh Committed by Android (Google) Code Review
Browse files

Merge "Support wildcard domains for UriRelativeFilterGroups" into main

parents 48429de1 72f54dea
Loading
Loading
Loading
Loading
+20 −3
Original line number Diff line number Diff line
@@ -163,14 +163,31 @@ public final class DomainVerificationManager {
    }

    /**
     * Update the URI relative filter groups for a package. All previously existing groups
     * will be cleared before the new groups will be applied.
     * Update the URI relative filter groups for a package. The groups set using this API acts
     * as an additional filtering layer during intent resolution. It does not replace any
     * existing groups that have been added to the package's intent filters either using the
     * {@link android.content.IntentFilter#addUriRelativeFilterGroup(UriRelativeFilterGroup)}
     * API or defined in the manifest.
     * <p>
     * Groups can be indexed to any domain or can be indexed for all subdomains by prefixing the
     * hostname with a wildcard (i.e. "*.example.com"). Priority will be first given to groups
     * that are indexed to the specific subdomain of the intent's data URI followed by any groups
     * indexed to wildcard subdomains. If the subdomain consists of more than one label, priority
     * will decrease corresponding to the decreasing number of subdomain labels after the wildcard.
     * For example "a.b.c.d" will match "*.b.c.d" before "*.c.d".
     * <p>
     * All previously existing groups set for a domain index using this API will be cleared when
     * new groups are set.
     *
     * @param packageName The name of the package.
     * @param domainToGroupsMap A map of domains to a list of {@link UriRelativeFilterGroup}s that
     *                         should apply to them. Groups for each domain will replace any groups
     *                         provided for that domain in a prior call to this method. Groups will
     *                         provided for that domain in a prior call to this method. To clear
     *                         existing groups, set the list to null or a empty list. Groups will
     *                         be evaluated in the order they are provided.
     *
     * @see UriRelativeFilterGroup
     * @see android.content.IntentFilter
     * @hide
     */
    @SystemApi
+37 −8
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package com.android.server.pm.verify.domain;

import static android.content.IntentFilter.WILDCARD;

import static com.android.server.pm.verify.domain.DomainVerificationUtils.isValidDomain;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;

@@ -253,9 +257,18 @@ public class DomainVerificationService extends SystemService
            Map<String, List<UriRelativeFilterGroup>> domainToGroupsMap =
                    pkgState.getUriRelativeFilterGroupMap();
            for (String domain : bundle.keySet()) {
                if (!isValidDomain(domain)) {
                    continue;
                }
                ArrayList<UriRelativeFilterGroupParcel> parcels =
                        bundle.getParcelableArrayList(domain, UriRelativeFilterGroupParcel.class);
                domainToGroupsMap.put(domain, UriRelativeFilterGroup.parcelsToGroups(parcels));
                List<UriRelativeFilterGroup> groups =
                        UriRelativeFilterGroup.parcelsToGroups(parcels);
                if (groups == null || groups.isEmpty()) {
                    domainToGroupsMap.remove(domain);
                } else {
                    domainToGroupsMap.put(domain, groups);
                }
            }
        }
    }
@@ -273,28 +286,44 @@ public class DomainVerificationService extends SystemService
                Map<String, List<UriRelativeFilterGroup>> map =
                        pkgState.getUriRelativeFilterGroupMap();
                for (int i = 0; i < domains.size(); i++) {
                    if (map.containsKey(domains.get(i))) {
                        List<UriRelativeFilterGroup> groups = map.get(domains.get(i));
                        bundle.putParcelableList(domains.get(i),
                                UriRelativeFilterGroup.groupsToParcels(groups));
                    }
                }
            }
        }
        return bundle;
    }

    @NonNull
    private List<UriRelativeFilterGroup> getUriRelativeFilterGroups(@NonNull String packageName,
            @NonNull String domain) {
        List<UriRelativeFilterGroup> groups = Collections.emptyList();
        List<UriRelativeFilterGroup> groups;
        synchronized (mLock) {
            DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName);
            if (pkgState != null) {
                groups = pkgState.getUriRelativeFilterGroupMap().getOrDefault(domain,
                        Collections.emptyList());
            }
                Map<String, List<UriRelativeFilterGroup>> groupMap =
                        pkgState.getUriRelativeFilterGroupMap();
                groups = groupMap.get(domain);
                if (groups != null) {
                    return groups;
                }
                int first = domain.indexOf(".");
                int second = domain.indexOf('.', first + 1);
                while (first > 0 && second > 0) {
                    groups = groupMap.get(WILDCARD + domain.substring(first));
                    if (groups != null) {
                        return groups;
                    }
                    first = second;
                    second = domain.indexOf('.', second + 1);
                }
            }
        }
        return Collections.emptyList();
    }

    @NonNull
    public List<String> queryValidVerificationPackageNames() {
+40 −0
Original line number Diff line number Diff line
@@ -35,6 +35,9 @@ import java.util.regex.Matcher;

public final class DomainVerificationUtils {

    public static final int MAX_DOMAIN_LENGTH = 254;
    public static final int MAX_DOMAIN_LABEL_LENGTH = 63;

    private static final ThreadLocal<Matcher> sCachedMatcher = ThreadLocal.withInitial(
            () -> Patterns.DOMAIN_NAME.matcher(""));

@@ -108,4 +111,41 @@ public final class DomainVerificationUtils {
        appInfo.targetSdkVersion = pkg.getTargetSdkVersion();
        return appInfo;
    }

    static boolean isValidDomain(String domain) {
        if (domain.length() > MAX_DOMAIN_LENGTH || domain.equals("*")) {
            return false;
        }
        if (domain.charAt(0) == '*') {
            if (domain.charAt(1) != '.') {
                return false;
            }
            domain = domain.substring(2);
        }
        int labels = 1;
        int labelStart = -1;
        for (int i = 0; i < domain.length(); i++) {
            char c = domain.charAt(i);
            if (c == '.') {
                int labelLength = i - labelStart - 1;
                if (labelLength == 0 || labelLength > MAX_DOMAIN_LABEL_LENGTH) {
                    return false;
                }
                labelStart = i;
                labels += 1;
            } else if (!isValidDomainChar(c)) {
                return false;
            }
        }
        int lastLabelLength = domain.length() - labelStart - 1;
        if (lastLabelLength == 0 || lastLabelLength > 63) {
            return false;
        }
        return labels > 1;
    }

    private static boolean isValidDomainChar(char c) {
        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
                || (c >= '0' && c <= '9') || c == '-';
    }
}
+1 −5
Original line number Diff line number Diff line
@@ -83,11 +83,7 @@ class DomainVerificationManagerApiTest {
        }

        val bundle = service.getUriRelativeFilterGroups(PKG_ONE, listOf(DOMAIN_1, DOMAIN_2))
        assertThat(bundle.keySet()).containsExactlyElementsIn(listOf(DOMAIN_1, DOMAIN_2))
        assertThat(bundle.getParcelableArrayList(DOMAIN_1, UriRelativeFilterGroup::class.java))
            .isEmpty()
        assertThat(bundle.getParcelableArrayList(DOMAIN_2, UriRelativeFilterGroup::class.java))
            .isEmpty()
        assertThat(bundle.keySet()).isEmpty()

        val pathGroup = UriRelativeFilterGroup(UriRelativeFilterGroup.ACTION_ALLOW)
        pathGroup.addUriRelativeFilter(