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

Commit 766326b6 authored by Winson Chiu's avatar Winson Chiu Committed by Android (Google) Code Review
Browse files

Merge changes I5e258e23,I72323430 into sc-dev

* changes:
  Update isLinkHandlingAllowed to mean all or nothing
  Update intent resolution logic with new rules
parents 45e4016b ebf59827
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -238,8 +238,8 @@ public interface DomainVerificationManager {
     * permissions must be acquired and
     * {@link Context#createPackageContextAsUser(String, int, UserHandle)} should be used.
     *
     * This will be combined with the verification status and other system state to determine which
     * application is launched to handle an app link.
     * Enabling an unverified domain will allow an application to open it, but this can only occur
     * if no other app on the device is approved for the domain.
     *
     * @param domainSetId See {@link DomainVerificationInfo#getIdentifier()}.
     * @param domains     The domains to toggle the state of.
@@ -290,13 +290,15 @@ public interface DomainVerificationManager {
        public static final int REASON_ID_INVALID = 2;
        public static final int REASON_SET_NULL_OR_EMPTY = 3;
        public static final int REASON_UNKNOWN_DOMAIN = 4;
        public static final int REASON_UNABLE_TO_APPROVE = 5;

        /** @hide */
        @IntDef({
                REASON_ID_NULL,
                REASON_ID_INVALID,
                REASON_SET_NULL_OR_EMPTY,
                REASON_UNKNOWN_DOMAIN
                REASON_UNKNOWN_DOMAIN,
                REASON_UNABLE_TO_APPROVE
        })
        public @interface Reason {
        }
@@ -313,6 +315,8 @@ public interface DomainVerificationManager {
                case REASON_UNKNOWN_DOMAIN:
                    return "Domain set contains value that was not declared by the target package "
                            + packageName;
                case REASON_UNABLE_TO_APPROVE:
                    return "Domain set contains value that was owned by another package";
                default:
                    return "Unknown failure";
            }
+15 −13
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.content.pm.verify.domain;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.Parcelable;
@@ -30,18 +31,18 @@ import java.util.Set;
import java.util.UUID;

/**
 * Contains the user selection state for a package. This means all web HTTP(S) domains
 * declared by a package in its manifest, whether or not they were marked for auto
 * verification.
 * Contains the user selection state for a package. This means all web HTTP(S) domains declared by a
 * package in its manifest, whether or not they were marked for auto verification.
 * <p>
 * By default, all apps are allowed to automatically open links with domains that they've
 * successfully verified against. This is reflected by {@link #isLinkHandlingAllowed()}.
 * The user can decide to disable this, disallowing the application from opening these
 * links.
 * successfully verified against. This is reflected by {@link #isLinkHandlingAllowed()}. The user
 * can decide to disable this, disallowing the application from opening all links. Note that the
 * toggle affects <b>all</b> links and is not based on the verification state of the domains.
 * <p>
 * Separately, independent of this toggle, the user can choose specific domains to allow
 * an app to open, which is reflected as part of {@link #getHostToUserSelectionMap()},
 * which maps the domain name to the true/false state of whether it was enabled by the user.
 * Assuming the toggle is enabled, the user can also select additional unverified domains to grant
 * to the application to open, which is reflected in {@link #getHostToUserSelectionMap()}. But only
 * a single application can be approved for a domain unless the applications are both approved. If
 * another application is approved, the user will not be allowed to enable the domain.
 * <p>
 * These values can be changed through the
 * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
@@ -105,7 +106,8 @@ public final class DomainVerificationUserSelection implements Parcelable {
    // CHECKSTYLE:OFF Generated code
    //
    // To regenerate run:
    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/domain/verify/DomainVerificationUserSelection.java
    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
    // /DomainVerificationUserSelection.java
    //
    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
    //   Settings > Editor > Code Style > Formatter Control
@@ -216,7 +218,7 @@ public final class DomainVerificationUserSelection implements Parcelable {

    @Override
    @DataClass.Generated.Member
    public boolean equals(@android.annotation.Nullable Object o) {
    public boolean equals(@Nullable Object o) {
        // You can override field equality logic by defining either of the methods like:
        // boolean fieldNameEquals(DomainVerificationUserSelection other) { ... }
        // boolean fieldNameEquals(FieldType otherValue) { ... }
@@ -328,9 +330,9 @@ public final class DomainVerificationUserSelection implements Parcelable {
    };

    @DataClass.Generated(
            time = 1611799495498L,
            time = 1612829797220L,
            codegenVersion = "1.0.22",
            sourceFile = "frameworks/base/core/java/android/content/pm/domain/verify/DomainVerificationUserSelection.java",
            sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java",
            inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull android.os.UserHandle mUser\nprivate final @android.annotation.NonNull boolean mLinkHandlingAllowed\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Boolean> mHostToUserSelectionMap\nclass DomainVerificationUserSelection extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true)")
    @Deprecated
    private void __metadata() {}
+52 −44
Original line number Diff line number Diff line
@@ -193,7 +193,6 @@ import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
import android.content.pm.ModuleInfo;
import android.content.pm.overlay.OverlayPaths;
import android.content.pm.PackageChangeEvent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
@@ -462,6 +461,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
/**
@@ -2586,49 +2586,42 @@ public class PackageManagerService extends IPackageManager.Stub
                Intent intent, int matchFlags, List<ResolveInfo> candidates,
                CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
            final ArrayList<ResolveInfo> result = new ArrayList<>();
            final ArrayList<ResolveInfo> alwaysList = new ArrayList<>();
            final ArrayList<ResolveInfo> undefinedList = new ArrayList<>();
            final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
            final int count = candidates.size();
            // First, try to use linked apps. Partition the candidates into four lists:
            // one for the final results, one for the "do not use ever", one for "undefined status"
            // and finally one for "browser app type".
            // First, try to use approved apps.
            for (int n = 0; n < count; n++) {
                ResolveInfo info = candidates.get(n);
                String packageName = info.activityInfo.packageName;
                PackageSetting ps = mSettings.getPackageLPr(packageName);
                if (ps != null) {
                // Add to the special match all list (Browser use case)
                if (info.handleAllWebDataURI) {
                    matchAllList.add(info);
                        continue;
                    }
                    boolean isAlways = mDomainVerificationManager
                            .isApprovedForDomain(ps, intent, userId);
                    if (isAlways) {
                        alwaysList.add(info);
                    } else {
                        undefinedList.add(info);
                    }
                    continue;
                }
            }
            Pair<List<ResolveInfo>, Integer> infosAndLevel = mDomainVerificationManager
                    .filterToApprovedApp(intent, candidates, userId, mSettings::getPackageLPr);
            List<ResolveInfo> approvedInfos = infosAndLevel.first;
            Integer highestApproval = infosAndLevel.second;
            // We'll want to include browser possibilities in a few cases
            boolean includeBrowser = false;
            // First try to add the "always" resolution(s) for the current user, if any
            if (alwaysList.size() > 0) {
                result.addAll(alwaysList);
            // If no apps are approved for the domain, resolve only to browsers
            if (approvedInfos.isEmpty()) {
                // If the other profile has a result, include that and delegate to ResolveActivity
                if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel
                        > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
                    result.add(xpDomainInfo.resolveInfo);
                } else {
                    includeBrowser = true;
                }
            } else {
                // Add all undefined apps as we want them to appear in the disambiguation dialog.
                result.addAll(undefinedList);
                // Maybe add one for the other profile.
                if (xpDomainInfo != null && xpDomainInfo.wereAnyDomainsVerificationApproved) {
                result.addAll(approvedInfos);
                // If the other profile has an app that's of equal or higher approval, add it
                if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel >= highestApproval) {
                    result.add(xpDomainInfo.resolveInfo);
                }
                includeBrowser = true;
            }
            if (includeBrowser) {
@@ -2676,9 +2669,7 @@ public class PackageManagerService extends IPackageManager.Stub
                    }
                }
                // If there is nothing selected, add all candidates and remove the ones that the
                //user
                // has explicitly put into the INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER state
                // If there is nothing selected, add all candidates
                if (result.size() == 0) {
                    result.addAll(candidates);
                }
@@ -2780,10 +2771,12 @@ public class PackageManagerService extends IPackageManager.Stub
                            sourceUserId, parentUserId);
                }
                result.wereAnyDomainsVerificationApproved |= mDomainVerificationManager
                        .isApprovedForDomain(ps, intent, riTargetUser.targetUserId);
                result.highestApprovalLevel = Math.max(mDomainVerificationManager
                        .approvalLevelForDomain(ps, intent, riTargetUser.targetUserId),
                        result.highestApprovalLevel);
            }
            if (result != null && !result.wereAnyDomainsVerificationApproved) {
            if (result != null && result.highestApprovalLevel
                    <= DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
                return null;
            }
            return result;
@@ -3026,9 +3019,10 @@ public class PackageManagerService extends IPackageManager.Stub
                    final String packageName = info.activityInfo.packageName;
                    final PackageSetting ps = mSettings.getPackageLPr(packageName);
                    if (ps.getInstantApp(userId)) {
                        if (mDomainVerificationManager.isApprovedForDomain(ps, intent, userId)) {
                        if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent,
                                userId)) {
                            if (DEBUG_INSTANT) {
                                Slog.v(TAG, "Instant app approvd for intent; pkg: "
                                Slog.v(TAG, "Instant app approved for intent; pkg: "
                                        + packageName);
                            }
                            localInstantApp = info;
@@ -3953,7 +3947,8 @@ public class PackageManagerService extends IPackageManager.Stub
                if (ps != null) {
                    // only check domain verification status if the app is not a browser
                    if (!info.handleAllWebDataURI) {
                        if (mDomainVerificationManager.isApprovedForDomain(ps, intent, userId)) {
                        if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent,
                                userId)) {
                            if (DEBUG_INSTANT) {
                                Slog.v(TAG, "DENY instant app;" + " pkg: " + packageName
                                        + ", approved");
@@ -9369,8 +9364,8 @@ public class PackageManagerService extends IPackageManager.Stub
                    if (ri.activityInfo.applicationInfo.isInstantApp()) {
                        final String packageName = ri.activityInfo.packageName;
                        final PackageSetting ps = mSettings.getPackageLPr(packageName);
                        if (ps != null && mDomainVerificationManager
                                .isApprovedForDomain(ps, intent, userId)) {
                        if (ps != null && hasAnyDomainApproval(mDomainVerificationManager, ps,
                                intent, userId)) {
                            return ri;
                        }
                    }
@@ -9419,6 +9414,19 @@ public class PackageManagerService extends IPackageManager.Stub
        return null;
    }
    /**
     * Do NOT use for intent resolution filtering. That should be done with
     * {@link DomainVerificationManagerInternal#filterToApprovedApp(Intent, List, int, Function)}.
     *
     * @return if the package is approved at any non-zero level for the domain in the intent
     */
    private static boolean hasAnyDomainApproval(
            @NonNull DomainVerificationManagerInternal manager, @NonNull PackageSetting pkgSetting,
            @NonNull Intent intent, @UserIdInt int userId) {
        return manager.approvalLevelForDomain(pkgSetting, intent, userId)
                > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
    }
    /**
     * Return true if the given list is not empty and all of its contents have
     * an activityInfo with the given package name.
@@ -9862,7 +9870,7 @@ public class PackageManagerService extends IPackageManager.Stub
    private static class CrossProfileDomainInfo {
        /* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */
        ResolveInfo resolveInfo;
        boolean wereAnyDomainsVerificationApproved;
        int highestApprovalLevel = DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
    }
    private CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
+4 −0
Original line number Diff line number Diff line
@@ -783,6 +783,10 @@ public abstract class PackageSettingBase extends SettingBase {
        incrementalStates.onStorageHealthStatusChanged(status);
    }

    public long getFirstInstallTime() {
        return firstInstallTime;
    }

    protected PackageSettingBase updateFrom(PackageSettingBase other) {
        super.copyFrom(other);
        setPath(other.getPath());
+1 −4
Original line number Diff line number Diff line
@@ -38,8 +38,6 @@ import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
import com.android.server.pm.verify.domain.models.DomainVerificationUserState;

import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;

@SuppressWarnings("PointlessBooleanExpression")
@@ -202,8 +200,7 @@ public class DomainVerificationDebug {
                printedHeader = true;
            }

            boolean isLinkHandlingAllowed = userState == null
                    || !userState.isDisallowLinkHandling();
            boolean isLinkHandlingAllowed = userState == null || userState.isLinkHandlingAllowed();

            writer.increaseIndent();
            writer.print("User ");
Loading