diff options
| author | 2021-02-16 19:12:22 +0000 | |
|---|---|---|
| committer | 2021-02-16 19:12:22 +0000 | |
| commit | 766326b69ae9ba43e1df927a7bfbf4d3f1501e01 (patch) | |
| tree | 129606bf8656aa0648a2c8ae85f9f421fd4e9e54 | |
| parent | 45e4016bb1f804c18a3ee542305c31fae1249dee (diff) | |
| parent | ebf59827eedbc7c6f8add8c32abb8c9bed791054 (diff) | |
Merge changes I5e258e23,I72323430 into sc-dev
* changes:
Update isLinkHandlingAllowed to mean all or nothing
Update intent resolution logic with new rules
13 files changed, 561 insertions, 183 deletions
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java index af12536fff99..cbb3baaa6700 100644 --- a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java +++ b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java @@ -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"; } diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java b/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java index 8d16f75bf1b4..73346ef0273b 100644 --- a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java +++ b/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java @@ -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() {} diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 7b9cf734fd30..fc18ddb0c7a3 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -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". - for (int n=0; n<count; n++) { + // 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; + // Add to the special match all list (Browser use case) + if (info.handleAllWebDataURI) { + matchAllList.add(info); } } + 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; } } @@ -9420,6 +9415,19 @@ public class PackageManagerService extends IPackageManager.Stub } /** + * 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, diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 5364cbfede86..a83a3f81bc00 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -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()); diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java index 1925590112f8..b3108c58a11e 100644 --- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java +++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java @@ -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 "); diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java index 50fd6e3ddea1..5d4370ae5dd4 100644 --- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java +++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java @@ -16,18 +16,22 @@ package com.android.server.pm.verify.domain; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.content.Intent; import android.content.pm.IntentFilterVerificationInfo; +import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; import android.content.pm.verify.domain.DomainVerificationInfo; import android.content.pm.verify.domain.DomainVerificationManager; import android.os.Binder; import android.os.UserHandle; import android.util.IndentingPrintWriter; +import android.util.Pair; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; @@ -39,6 +43,7 @@ import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.util.List; import java.util.Set; import java.util.UUID; import java.util.function.Function; @@ -48,6 +53,78 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan UUID DISABLED_ID = new UUID(0, 0); /** + * The app has not been approved for this domain and should never be able to open it through + * an implicit web intent. + */ + int APPROVAL_LEVEL_NONE = 0; + + /** + * The app has been approved through the legacy + * {@link PackageManager#updateIntentVerificationStatusAsUser(String, int, int)} API, which has + * been preserved for migration purposes, but is otherwise ignored. Corresponds to + * {@link PackageManager#INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK} and + * {@link PackageManager#INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK}. + * + * This should be used as the cutoff for showing a picker if no better approved app exists + * during the legacy transition period. + * + * TODO(b/177923646): The legacy values can be removed once the Settings API changes are + * shipped. These values are not stable, so just deleting the constant and shifting others is + * fine. + */ + int APPROVAL_LEVEL_LEGACY_ASK = 1; + + /** + * The app has been approved through the legacy + * {@link PackageManager#updateIntentVerificationStatusAsUser(String, int, int)} API, which has + * been preserved for migration purposes, but is otherwise ignored. Corresponds to + * {@link PackageManager#INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS}. + */ + int APPROVAL_LEVEL_LEGACY_ALWAYS = 1; + + /** + * The app has been chosen by the user through + * {@link #setDomainVerificationUserSelection(UUID, Set, boolean)}, indictag an explicit + * choice to use this app to open an unverified domain. + */ + int APPROVAL_LEVEL_SELECTION = 2; + + /** + * The app is approved through the digital asset link statement being hosted at the domain + * it is capturing. This is set through {@link #setDomainVerificationStatus(UUID, Set, int)} by + * the domain verification agent on device. + */ + int APPROVAL_LEVEL_VERIFIED = 3; + + /** + * The app has been installed as an instant app, which grants it total authority on the domains + * that it declares. It is expected that the package installer validate the domains the app + * declares against the digital asset link statements before allowing it to be installed. + * + * The user is still able to disable instant app link handling through + * {@link #setDomainVerificationLinkHandlingAllowed(String, boolean)}. + */ + int APPROVAL_LEVEL_INSTANT_APP = 4; + + /** + * Defines the possible values for {@link #approvalLevelForDomain(PackageSetting, Intent, int)} + * which sorts packages by approval priority. A higher numerical value means the package should + * override all lower values. This means that comparison using less/greater than IS valid. + * + * Negative values are possible, although not implemented, reserved if explicit disable of a + * package for a domain needs to be tracked. + */ + @IntDef({ + APPROVAL_LEVEL_NONE, + APPROVAL_LEVEL_LEGACY_ASK, + APPROVAL_LEVEL_LEGACY_ALWAYS, + APPROVAL_LEVEL_SELECTION, + APPROVAL_LEVEL_VERIFIED, + APPROVAL_LEVEL_INSTANT_APP + }) + @interface ApprovalLevel{} + + /** * Generate a new domain set ID to be used for attaching new packages. */ @NonNull @@ -211,11 +288,28 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan DomainVerificationCollector getCollector(); /** - * Check if a resolving URI is approved to takeover the domain as the sole resolved target. + * Filters the provided list down to the {@link ResolveInfo} objects that should be allowed + * to open the domain inside the {@link Intent}. It is possible for no packages represented in + * the list to be approved, in which case an empty list will be returned. + * + * @return the filtered list and the corresponding approval level + */ + @NonNull + Pair<List<ResolveInfo>, Integer> filterToApprovedApp(@NonNull Intent intent, + @NonNull List<ResolveInfo> infos, @UserIdInt int userId, + @NonNull Function<String, PackageSetting> pkgSettingFunction); + + /** + * Check at what precedence a package resolving a URI is approved to takeover the domain. * This can be because the domain was auto-verified for the package, or if the user manually - * chose to enable the domain for the package. + * chose to enable the domain for the package. If an app is auto-verified, it will be + * preferred over apps that were manually selected. + * + * NOTE: This should not be used for filtering intent resolution. See + * {@link #filterToApprovedApp(Intent, List, int, Function)} for that. */ - boolean isApprovedForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent, + @ApprovalLevel + int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent, @UserIdInt int userId); /** @@ -231,8 +325,7 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan throws IllegalArgumentException, NameNotFoundException; - interface Connection extends DomainVerificationEnforcer.Callback, - Function<String, PackageSetting> { + interface Connection extends DomainVerificationEnforcer.Callback { /** * Notify that a settings change has been made and that eventually @@ -265,10 +358,5 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan @Nullable AndroidPackage getPackageLocked(@NonNull String pkgName); - - @Override - default PackageSetting apply(@NonNull String pkgName) { - return getPackageSettingLocked(pkgName); - } } } diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java index 679f948bb3de..c864b2937f6b 100644 --- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java +++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java @@ -53,7 +53,7 @@ public class DomainVerificationPersistence { public static final String TAG_USER_STATE = "user-state"; public static final String ATTR_USER_ID = "userId"; - public static final String ATTR_DISALLOW_LINK_HANDLING = "disallowLinkHandling"; + public static final String ATTR_ALLOW_LINK_HANDLING = "allowLinkHandling"; public static final String TAG_ENABLED_HOSTS = "enabled-hosts"; public static final String TAG_HOST = "host"; @@ -252,7 +252,7 @@ public class DomainVerificationPersistence { return null; } - boolean disallowLinkHandling = section.getBoolean(ATTR_DISALLOW_LINK_HANDLING); + boolean allowLinkHandling = section.getBoolean(ATTR_ALLOW_LINK_HANDLING, true); ArraySet<String> enabledHosts = new ArraySet<>(); SettingsXml.ChildSection child = section.children(); @@ -260,7 +260,7 @@ public class DomainVerificationPersistence { readEnabledHosts(child, enabledHosts); } - return new DomainVerificationUserState(userId, enabledHosts, disallowLinkHandling); + return new DomainVerificationUserState(userId, enabledHosts, allowLinkHandling); } private static void readEnabledHosts(@NonNull SettingsXml.ReadSection section, @@ -279,8 +279,8 @@ public class DomainVerificationPersistence { try (SettingsXml.WriteSection section = parentSection.startSection(TAG_USER_STATE) .attribute(ATTR_USER_ID, userState.getUserId()) - .attribute(ATTR_DISALLOW_LINK_HANDLING, - userState.isDisallowLinkHandling())) { + .attribute(ATTR_ALLOW_LINK_HANDLING, + userState.isLinkHandlingAllowed())) { ArraySet<String> enabledHosts = userState.getEnabledHosts(); if (!enabledHosts.isEmpty()) { try (SettingsXml.WriteSection enabledHostsSection = diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java index fa0327414914..86a92d792026 100644 --- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java +++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java @@ -16,6 +16,8 @@ package com.android.server.pm.verify.domain; +import static java.util.Collections.emptyList; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -26,6 +28,8 @@ import android.content.Intent; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; +import android.content.pm.parsing.component.ParsedActivity; import android.content.pm.verify.domain.DomainVerificationInfo; import android.content.pm.verify.domain.DomainVerificationManager; import android.content.pm.verify.domain.DomainVerificationState; @@ -35,6 +39,7 @@ import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IndentingPrintWriter; +import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; @@ -62,6 +67,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.function.Function; @@ -401,7 +407,7 @@ public class DomainVerificationService extends SystemService } pkgState.getOrCreateUserSelectionState(userId) - .setDisallowLinkHandling(!allowed); + .setLinkHandlingAllowed(allowed); } mConnection.scheduleWriteSettings(); @@ -423,11 +429,11 @@ public class DomainVerificationService extends SystemService for (int userStateIndex = 0; userStateIndex < userStatesSize; userStateIndex++) { userStates.valueAt(userStateIndex) - .setDisallowLinkHandling(!allowed); + .setLinkHandlingAllowed(allowed); } } else { pkgState.getOrCreateUserSelectionState(userId) - .setDisallowLinkHandling(!allowed); + .setLinkHandlingAllowed(allowed); } } @@ -440,7 +446,7 @@ public class DomainVerificationService extends SystemService } pkgState.getOrCreateUserSelectionState(userId) - .setDisallowLinkHandling(!allowed); + .setLinkHandlingAllowed(allowed); } } @@ -468,6 +474,17 @@ public class DomainVerificationService extends SystemService throw new InvalidDomainSetException(domainSetId, null, InvalidDomainSetException.REASON_ID_INVALID); } + + if (enabled) { + for (String domain : domains) { + if (!getApprovedPackages(domain, userId, APPROVAL_LEVEL_LEGACY_ALWAYS + 1, + mConnection::getPackageSettingLocked).first.isEmpty()) { + throw new InvalidDomainSetException(domainSetId, null, + InvalidDomainSetException.REASON_UNABLE_TO_APPROVE); + } + } + } + DomainVerificationPkgState pkgState = getAndValidateAttachedLocked(domainSetId, domains, false /* forAutoVerify */, callingUid, userId); DomainVerificationUserState userState = pkgState.getOrCreateUserSelectionState(userId); @@ -589,10 +606,10 @@ public class DomainVerificationService extends SystemService hostToUserSelectionMap.put(domains.valueAt(index), false); } - boolean openVerifiedLinks = false; DomainVerificationUserState userState = pkgState.getUserSelectionState(userId); + boolean linkHandlingAllowed = true; if (userState != null) { - openVerifiedLinks = !userState.isDisallowLinkHandling(); + linkHandlingAllowed = userState.isLinkHandlingAllowed(); ArraySet<String> enabledHosts = userState.getEnabledHosts(); int hostsSize = enabledHosts.size(); for (int index = 0; index < hostsSize; index++) { @@ -601,7 +618,7 @@ public class DomainVerificationService extends SystemService } return new DomainVerificationUserSelection(pkgState.getId(), packageName, - UserHandle.of(userId), openVerifiedLinks, hostToUserSelectionMap); + UserHandle.of(userId), linkHandlingAllowed, hostToUserSelectionMap); } } @@ -683,7 +700,7 @@ public class DomainVerificationService extends SystemService ArraySet<String> newEnabledHosts = new ArraySet<>(oldEnabledHosts); newEnabledHosts.retainAll(newWebDomains); DomainVerificationUserState newUserState = new DomainVerificationUserState( - userId, newEnabledHosts, oldUserState.isDisallowLinkHandling()); + userId, newEnabledHosts, oldUserState.isLinkHandlingAllowed()); newUserStates.put(userId, newUserState); } } @@ -910,7 +927,7 @@ public class DomainVerificationService extends SystemService // This method is only used by DomainVerificationShell, which doesn't lock PMS, so it's // safe to pass mConnection directly here and lock PMS. This method is not exposed // to the general system server/PMS. - printState(writer, packageName, userId, mConnection); + printState(writer, packageName, userId, mConnection::getPackageSettingLocked); } @Override @@ -919,7 +936,7 @@ public class DomainVerificationService extends SystemService @Nullable Function<String, PackageSetting> pkgSettingFunction) throws NameNotFoundException { if (pkgSettingFunction == null) { - pkgSettingFunction = mConnection; + pkgSettingFunction = mConnection::getPackageSettingLocked; } synchronized (mLock) { @@ -1156,46 +1173,211 @@ public class DomainVerificationService extends SystemService mConnection.scheduleWriteSettings(); } + /** + * {@inheritDoc} + * + * Resolving an Intent to an approved app happens in stages: + * <ol> + * <li>Find all non-zero approved packages for the {@link Intent}'s domain</li> + * <li>Filter to packages with the highest approval level, see {@link ApprovalLevel}</li> + * <li>Filter out {@link ResolveInfo}s that don't match that approved packages</li> + * <li>Take the approved packages with the latest install time</li> + * <li>Take the ResolveInfo representing the Activity declared last in the manifest</li> + * <li>Return remaining results if any exist</li> + * </ol> + */ + @NonNull + @Override + public Pair<List<ResolveInfo>, Integer> filterToApprovedApp(@NonNull Intent intent, + @NonNull List<ResolveInfo> infos, @UserIdInt int userId, + @NonNull Function<String, PackageSetting> pkgSettingFunction) { + String domain = intent.getData().getHost(); + + // Collect package names + ArrayMap<String, Integer> packageApprovals = new ArrayMap<>(); + int infosSize = infos.size(); + for (int index = 0; index < infosSize; index++) { + packageApprovals.put(infos.get(index).getComponentInfo().packageName, + APPROVAL_LEVEL_NONE); + } + + // Find all approval levels + int highestApproval = fillMapWithApprovalLevels(packageApprovals, domain, userId, + pkgSettingFunction); + if (highestApproval == APPROVAL_LEVEL_NONE) { + return Pair.create(emptyList(), highestApproval); + } + + // Filter to highest, non-zero packages + ArraySet<String> approvedPackages = new ArraySet<>(); + for (int index = 0; index < infosSize; index++) { + if (packageApprovals.valueAt(index) == highestApproval) { + approvedPackages.add(packageApprovals.keyAt(index)); + } + } + + ArraySet<String> filteredPackages = new ArraySet<>(); + if (highestApproval == APPROVAL_LEVEL_LEGACY_ASK) { + // To maintain legacy behavior while the Settings API is not implemented, + // show the chooser if all approved apps are marked ask, skipping the + // last app, last declaration filtering. + filteredPackages.addAll(approvedPackages); + } else { + // Filter to last installed package + long latestInstall = Long.MIN_VALUE; + int approvedSize = approvedPackages.size(); + for (int index = 0; index < approvedSize; index++) { + String packageName = approvedPackages.valueAt(index); + PackageSetting pkgSetting = pkgSettingFunction.apply(packageName); + if (pkgSetting == null) { + continue; + } + long installTime = pkgSetting.getFirstInstallTime(); + if (installTime > latestInstall) { + latestInstall = installTime; + filteredPackages.clear(); + filteredPackages.add(packageName); + } else if (installTime == latestInstall) { + filteredPackages.add(packageName); + } + } + } + + // Filter to approved ResolveInfos + ArrayMap<String, List<ResolveInfo>> approvedInfos = new ArrayMap<>(); + for (int index = 0; index < infosSize; index++) { + ResolveInfo info = infos.get(index); + String packageName = info.getComponentInfo().packageName; + if (filteredPackages.contains(packageName)) { + List<ResolveInfo> infosPerPackage = approvedInfos.get(packageName); + if (infosPerPackage == null) { + infosPerPackage = new ArrayList<>(); + approvedInfos.put(packageName, infosPerPackage); + } + infosPerPackage.add(info); + } + } + + List<ResolveInfo> finalList; + if (highestApproval == APPROVAL_LEVEL_LEGACY_ASK) { + // If legacy ask, skip the last declaration filtering + finalList = new ArrayList<>(); + int size = approvedInfos.size(); + for (int index = 0; index < size; index++) { + finalList.addAll(approvedInfos.valueAt(index)); + } + } else { + // Find the last declared ResolveInfo per package + finalList = filterToLastDeclared(approvedInfos, pkgSettingFunction); + } + + return Pair.create(finalList, highestApproval); + } + + /** + * @return highest approval level found + */ + private int fillMapWithApprovalLevels(@NonNull ArrayMap<String, Integer> inputMap, + @NonNull String domain, @UserIdInt int userId, + @NonNull Function<String, PackageSetting> pkgSettingFunction) { + int highestApproval = APPROVAL_LEVEL_NONE; + int size = inputMap.size(); + for (int index = 0; index < size; index++) { + String packageName = inputMap.keyAt(index); + PackageSetting pkgSetting = pkgSettingFunction.apply(packageName); + if (pkgSetting == null) { + inputMap.setValueAt(index, APPROVAL_LEVEL_NONE); + continue; + } + int approval = approvalLevelForDomain(pkgSetting, domain, userId, domain); + highestApproval = Math.max(highestApproval, approval); + inputMap.setValueAt(index, approval); + } + + return highestApproval; + } + + @NonNull + private List<ResolveInfo> filterToLastDeclared( + @NonNull ArrayMap<String, List<ResolveInfo>> inputMap, + @NonNull Function<String, PackageSetting> pkgSettingFunction) { + List<ResolveInfo> finalList = new ArrayList<>(inputMap.size()); + + int inputSize = inputMap.size(); + for (int inputIndex = 0; inputIndex < inputSize; inputIndex++) { + String packageName = inputMap.keyAt(inputIndex); + List<ResolveInfo> infos = inputMap.valueAt(inputIndex); + PackageSetting pkgSetting = pkgSettingFunction.apply(packageName); + AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg(); + if (pkg == null) { + continue; + } + + ResolveInfo result = null; + int highestIndex = -1; + int infosSize = infos.size(); + for (int infoIndex = 0; infoIndex < infosSize; infoIndex++) { + ResolveInfo info = infos.get(infoIndex); + List<ParsedActivity> activities = pkg.getActivities(); + int activitiesSize = activities.size(); + for (int activityIndex = 0; activityIndex < activitiesSize; activityIndex++) { + if (Objects.equals(activities.get(activityIndex).getComponentName(), + info.getComponentInfo().getComponentName())) { + if (activityIndex > highestIndex) { + highestIndex = activityIndex; + result = info; + } + break; + } + } + } + + // Shouldn't be null, but might as well be safe + if (result != null) { + finalList.add(result); + } + } + + return finalList; + } + @Override - public boolean isApprovedForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent, + public int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent, @UserIdInt int userId) { String packageName = pkgSetting.name; if (!DomainVerificationUtils.isDomainVerificationIntent(intent)) { if (DEBUG_APPROVAL) { debugApproval(packageName, intent, userId, false, "not valid intent"); } - return false; + return APPROVAL_LEVEL_NONE; } - String host = intent.getData().getHost(); + return approvalLevelForDomain(pkgSetting, intent.getData().getHost(), userId, intent); + } + + /** + * @param debugObject Should be an {@link Intent} if checking for resolution or a {@link String} + * otherwise. + */ + private int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull String host, + @UserIdInt int userId, @NonNull Object debugObject) { + String packageName = pkgSetting.name; final AndroidPackage pkg = pkgSetting.getPkg(); // Should never be null, but if it is, skip this and assume that v2 is enabled - if (pkg != null) { - // To allow an instant app to immediately open domains after being installed by the - // user, auto approve them for any declared autoVerify domains. - if (pkgSetting.getInstantApp(userId) - && mCollector.collectAutoVerifyDomains(pkg).contains(host)) { - return true; - } - - if (!DomainVerificationUtils.isChangeEnabled(mPlatformCompat, pkg, SETTINGS_API_V2)) { - int legacyState = mLegacySettings.getUserState(packageName, userId); - switch (legacyState) { - case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED: - // If nothing specifically set, assume v2 rules - break; - case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK: - case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: - case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK: - // With v2 split into 2 lists, always and undefined, the concept of whether - // or not to ask is irrelevant. Assume the user wants this application to - // open the domain. - return true; - case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: - // Never has the same semantics are before - return false; - } + if (pkg != null && !DomainVerificationUtils.isChangeEnabled(mPlatformCompat, pkg, + SETTINGS_API_V2)) { + switch (mLegacySettings.getUserState(packageName, userId)) { + case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED: + // If nothing specifically set, assume v2 rules + break; + case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: + return APPROVAL_LEVEL_NONE; + case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK: + case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK: + return APPROVAL_LEVEL_LEGACY_ASK; + case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: + return APPROVAL_LEVEL_LEGACY_ALWAYS; } } @@ -1203,59 +1385,76 @@ public class DomainVerificationService extends SystemService DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName); if (pkgState == null) { if (DEBUG_APPROVAL) { - debugApproval(packageName, intent, userId, false, "pkgState unavailable"); + debugApproval(packageName, debugObject, userId, false, "pkgState unavailable"); } - return false; + return APPROVAL_LEVEL_NONE; } - ArrayMap<String, Integer> stateMap = pkgState.getStateMap(); DomainVerificationUserState userState = pkgState.getUserSelectionState(userId); - // Only allow autoVerify approval if the user hasn't disabled it - if (userState == null || !userState.isDisallowLinkHandling()) { - // Check if the exact host matches - Integer state = stateMap.get(host); - if (state != null && DomainVerificationManager.isStateVerified(state)) { - if (DEBUG_APPROVAL) { - debugApproval(packageName, intent, userId, true, "host verified exactly"); - } - return true; + if (userState != null && !userState.isLinkHandlingAllowed()) { + if (DEBUG_APPROVAL) { + debugApproval(packageName, debugObject, userId, false, + "link handling not allowed"); } + return APPROVAL_LEVEL_NONE; + } - // Otherwise see if the host matches a verified domain by wildcard - int stateMapSize = stateMap.size(); - for (int index = 0; index < stateMapSize; index++) { - if (!DomainVerificationManager.isStateVerified(stateMap.valueAt(index))) { - continue; - } + // The instant app branch must be run after the link handling check, + // since that should also disable instant apps if toggled + if (pkg != null) { + // To allow an instant app to immediately open domains after being installed by the + // user, auto approve them for any declared autoVerify domains. + if (pkgSetting.getInstantApp(userId) + && mCollector.collectAutoVerifyDomains(pkg).contains(host)) { + return APPROVAL_LEVEL_INSTANT_APP; + } + } - String domain = stateMap.keyAt(index); - if (domain.startsWith("*.") && host.endsWith(domain.substring(2))) { - if (DEBUG_APPROVAL) { - debugApproval(packageName, intent, userId, true, - "host verified by wildcard"); - } - return true; + ArrayMap<String, Integer> stateMap = pkgState.getStateMap(); + // Check if the exact host matches + Integer state = stateMap.get(host); + if (state != null && DomainVerificationManager.isStateVerified(state)) { + if (DEBUG_APPROVAL) { + debugApproval(packageName, debugObject, userId, true, + "host verified exactly"); + } + return APPROVAL_LEVEL_VERIFIED; + } + + // Otherwise see if the host matches a verified domain by wildcard + int stateMapSize = stateMap.size(); + for (int index = 0; index < stateMapSize; index++) { + if (!DomainVerificationManager.isStateVerified(stateMap.valueAt(index))) { + continue; + } + + String domain = stateMap.keyAt(index); + if (domain.startsWith("*.") && host.endsWith(domain.substring(2))) { + if (DEBUG_APPROVAL) { + debugApproval(packageName, debugObject, userId, true, + "host verified by wildcard"); } + return APPROVAL_LEVEL_VERIFIED; } } // Check user state if available if (userState == null) { if (DEBUG_APPROVAL) { - debugApproval(packageName, intent, userId, false, "userState unavailable"); + debugApproval(packageName, debugObject, userId, false, "userState unavailable"); } - return false; + return APPROVAL_LEVEL_NONE; } // See if the user has approved the exact host ArraySet<String> enabledHosts = userState.getEnabledHosts(); if (enabledHosts.contains(host)) { if (DEBUG_APPROVAL) { - debugApproval(packageName, intent, userId, true, + debugApproval(packageName, debugObject, userId, true, "host enabled by user exactly"); } - return true; + return APPROVAL_LEVEL_SELECTION; } // See if the host matches a user selection by wildcard @@ -1264,24 +1463,85 @@ public class DomainVerificationService extends SystemService String domain = enabledHosts.valueAt(index); if (domain.startsWith("*.") && host.endsWith(domain.substring(2))) { if (DEBUG_APPROVAL) { - debugApproval(packageName, intent, userId, true, + debugApproval(packageName, debugObject, userId, true, "host enabled by user through wildcard"); } - return true; + return APPROVAL_LEVEL_SELECTION; } } if (DEBUG_APPROVAL) { - debugApproval(packageName, intent, userId, false, "not approved"); + debugApproval(packageName, debugObject, userId, false, "not approved"); } - return false; + return APPROVAL_LEVEL_NONE; } } - private void debugApproval(@NonNull String packageName, @NonNull Intent intent, + /** + * @return the filtered list paired with the corresponding approval level + */ + @NonNull + private Pair<List<String>, Integer> getApprovedPackages(@NonNull String domain, + @UserIdInt int userId, int minimumApproval, + @NonNull Function<String, PackageSetting> pkgSettingFunction) { + int highestApproval = minimumApproval; + List<String> approvedPackages = emptyList(); + + synchronized (mLock) { + final int size = mAttachedPkgStates.size(); + for (int index = 0; index < size; index++) { + DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index); + String packageName = pkgState.getPackageName(); + PackageSetting pkgSetting = pkgSettingFunction.apply(packageName); + if (pkgSetting == null) { + continue; + } + + int level = approvalLevelForDomain(pkgSetting, domain, userId, domain); + if (level < minimumApproval) { + continue; + } + + if (level > highestApproval) { + approvedPackages.clear(); + approvedPackages = CollectionUtils.add(approvedPackages, packageName); + highestApproval = level; + } else if (level == highestApproval) { + approvedPackages = CollectionUtils.add(approvedPackages, packageName); + } + } + } + + if (approvedPackages.isEmpty()) { + return Pair.create(approvedPackages, APPROVAL_LEVEL_NONE); + } + + List<String> filteredPackages = new ArrayList<>(); + long latestInstall = Long.MIN_VALUE; + final int approvedSize = approvedPackages.size(); + for (int index = 0; index < approvedSize; index++) { + String packageName = approvedPackages.get(index); + PackageSetting pkgSetting = pkgSettingFunction.apply(packageName); + if (pkgSetting == null) { + continue; + } + long installTime = pkgSetting.getFirstInstallTime(); + if (installTime > latestInstall) { + latestInstall = installTime; + filteredPackages.clear(); + filteredPackages.add(packageName); + } else if (installTime == latestInstall) { + filteredPackages.add(packageName); + } + } + + return Pair.create(filteredPackages, highestApproval); + } + + private void debugApproval(@NonNull String packageName, @NonNull Object debugObject, @UserIdInt int userId, boolean approved, @NonNull String reason) { String approvalString = approved ? "approved" : "denied"; - Slog.d(TAG + "Approval", packageName + " was " + approvalString + " for " + intent - + " for user " + userId + ": " + reason); + Slog.d(TAG + "Approval", packageName + " was " + approvalString + " for " + + debugObject + " for user " + userId + ": " + reason); } } diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java index 073967e00134..a8e937cf2b90 100644 --- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java +++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java @@ -23,7 +23,6 @@ import android.content.pm.verify.domain.DomainVerificationState; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.Pair; import android.util.SparseArray; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; @@ -229,14 +228,14 @@ class DomainVerificationSettings { DomainVerificationUserState oldUserState = oldSelectionStates.get(UserHandle.USER_SYSTEM); - boolean disallowLinkHandling = newUserState.isDisallowLinkHandling(); + boolean linkHandlingAllowed = newUserState.isLinkHandlingAllowed(); if (oldUserState == null) { oldUserState = new DomainVerificationUserState(UserHandle.USER_SYSTEM, - newEnabledHosts, disallowLinkHandling); + newEnabledHosts, linkHandlingAllowed); oldSelectionStates.put(UserHandle.USER_SYSTEM, oldUserState); } else { oldUserState.addHosts(newEnabledHosts) - .setDisallowLinkHandling(disallowLinkHandling); + .setLinkHandlingAllowed(linkHandlingAllowed); } } } diff --git a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java index 8e8260899a48..22468640800e 100644 --- a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java +++ b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java @@ -25,10 +25,10 @@ import com.android.internal.util.DataClass; import java.util.Set; /** - * Tracks which domains have been explicitly enabled by the user, allowing it to automatically open - * that domain when a web URL Intent is sent ft. + * Tracks which domains have been explicitly enabled by the user, allowing it to open that domain + * when a web URL Intent is sent and the application is the highest priority for that domain. */ -@DataClass(genSetters = true, genEqualsHashCode = true, genToString = true) +@DataClass(genSetters = true, genEqualsHashCode = true, genToString = true, genBuilder = false) public class DomainVerificationUserState { @UserIdInt @@ -38,8 +38,10 @@ public class DomainVerificationUserState { @NonNull private final ArraySet<String> mEnabledHosts; - /** Whether to disallow this package from automatically opening links by auto verification. */ - private boolean mDisallowLinkHandling; + /** + * Whether to allow this package to automatically open links by auto verification. + */ + private boolean mLinkHandlingAllowed = true; public DomainVerificationUserState(@UserIdInt int userId) { mUserId = userId; @@ -67,13 +69,15 @@ public class DomainVerificationUserState { } + // Code below generated by codegen v1.0.22. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code // // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/domain/verify/models/DomainVerificationUserState.java + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm + // /verify/domain/models/DomainVerificationUserState.java // // To exclude the generated code from IntelliJ auto-formatting enable (one-time): // Settings > Editor > Code Style > Formatter Control @@ -85,19 +89,21 @@ public class DomainVerificationUserState { * * @param enabledHosts * List of domains which have been enabled by the user. * + * @param linkHandlingAllowed + * Whether to allow this package to automatically open links by auto verification. */ @DataClass.Generated.Member public DomainVerificationUserState( @UserIdInt int userId, @NonNull ArraySet<String> enabledHosts, - boolean disallowLinkHandling) { + boolean linkHandlingAllowed) { this.mUserId = userId; com.android.internal.util.AnnotationValidations.validate( UserIdInt.class, null, mUserId); this.mEnabledHosts = enabledHosts; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mEnabledHosts); - this.mDisallowLinkHandling = disallowLinkHandling; + this.mLinkHandlingAllowed = linkHandlingAllowed; // onConstructed(); // You can define this method to get a callback } @@ -115,14 +121,20 @@ public class DomainVerificationUserState { return mEnabledHosts; } + /** + * Whether to allow this package to automatically open links by auto verification. + */ @DataClass.Generated.Member - public boolean isDisallowLinkHandling() { - return mDisallowLinkHandling; + public boolean isLinkHandlingAllowed() { + return mLinkHandlingAllowed; } + /** + * Whether to allow this package to automatically open links by auto verification. + */ @DataClass.Generated.Member - public @NonNull DomainVerificationUserState setDisallowLinkHandling( boolean value) { - mDisallowLinkHandling = value; + public @NonNull DomainVerificationUserState setLinkHandlingAllowed( boolean value) { + mLinkHandlingAllowed = value; return this; } @@ -135,7 +147,7 @@ public class DomainVerificationUserState { return "DomainVerificationUserState { " + "userId = " + mUserId + ", " + "enabledHosts = " + mEnabledHosts + ", " + - "disallowLinkHandling = " + mDisallowLinkHandling + + "linkHandlingAllowed = " + mLinkHandlingAllowed + " }"; } @@ -154,7 +166,7 @@ public class DomainVerificationUserState { return true && mUserId == that.mUserId && java.util.Objects.equals(mEnabledHosts, that.mEnabledHosts) - && mDisallowLinkHandling == that.mDisallowLinkHandling; + && mLinkHandlingAllowed == that.mLinkHandlingAllowed; } @Override @@ -166,15 +178,15 @@ public class DomainVerificationUserState { int _hash = 1; _hash = 31 * _hash + mUserId; _hash = 31 * _hash + java.util.Objects.hashCode(mEnabledHosts); - _hash = 31 * _hash + Boolean.hashCode(mDisallowLinkHandling); + _hash = 31 * _hash + Boolean.hashCode(mLinkHandlingAllowed); return _hash; } @DataClass.Generated( - time = 1608234273324L, + time = 1612894390039L, codegenVersion = "1.0.22", - sourceFile = "frameworks/base/services/core/java/com/android/server/pm/domain/verify/models/DomainVerificationUserState.java", - inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull android.util.ArraySet<java.lang.String> mEnabledHosts\nprivate boolean mDisallowLinkHandling\npublic com.android.server.pm.verify.domain.models.DomainVerificationUserState addHosts(android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationUserState addHosts(java.util.Set<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationUserState removeHosts(android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationUserState removeHosts(java.util.Set<java.lang.String>)\nclass DomainVerificationUserState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genEqualsHashCode=true, genToString=true)") + sourceFile = "frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java", + inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull android.util.ArraySet<java.lang.String> mEnabledHosts\nprivate boolean mLinkHandlingAllowed\npublic com.android.server.pm.verify.domain.models.DomainVerificationUserState addHosts(android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationUserState addHosts(java.util.Set<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationUserState removeHosts(android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationUserState removeHosts(java.util.Set<java.lang.String>)\nclass DomainVerificationUserState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genEqualsHashCode=true, genToString=true, genBuilder=false)") @Deprecated private void __metadata() {} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt index c2e0b776fc60..2d23fb4990bf 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt @@ -334,6 +334,7 @@ class DomainVerificationEnforcerTest { this[0] = PackageUserState() } } + whenever(getInstantApp(anyInt())) { false } } } diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt index a76152c9df7d..a92ab9e35ddc 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt @@ -104,14 +104,14 @@ class DomainVerificationPersistenceTest { userSelectionStates[1] = DomainVerificationUserState(1).apply { addHosts(setOf("example-user1.com", "example-user1.org")) - isDisallowLinkHandling = false + isLinkHandlingAllowed = true } } val stateOne = mockEmptyPkgState(1).apply { // It's valid to have a user selection without any autoVerify domains userSelectionStates[1] = DomainVerificationUserState(1).apply { addHosts(setOf("example-user1.com", "example-user1.org")) - isDisallowLinkHandling = true + isLinkHandlingAllowed = false } } @@ -137,13 +137,15 @@ class DomainVerificationPersistenceTest { hasAutoVerifyDomains="true" > <state> - <domain name="example.com" state="${DomainVerificationManager.STATE_SUCCESS}"/> - <domain name="example.org" state="${DomainVerificationManager.STATE_FIRST_VERIFIER_DEFINED}"/> + <domain name="example.com" state="${ + DomainVerificationManager.STATE_SUCCESS}"/> + <domain name="example.org" state="${ + DomainVerificationManager.STATE_FIRST_VERIFIER_DEFINED}"/> <not-domain name="not-domain.com" state="1"/> <domain name="missing-state.com"/> </state> <user-states> - <user-state userId="1" disallowLinkHandling="false"> + <user-state userId="1" allowLinkHandling="true"> <enabled-hosts> <host name="example-user1.com"/> <not-host name="not-host.com"/> @@ -171,7 +173,7 @@ class DomainVerificationPersistenceTest { > <state/> <user-states> - <user-state userId="1" disallowLinkHandling="true"> + <user-state userId="1" allowLinkHandling="false"> <enabled-hosts> <host name="example-user1.com"/> <host name="example-user1.org"/> @@ -214,9 +216,9 @@ class DomainVerificationPersistenceTest { stateMap["$packageName.com"] = id userSelectionStates[id] = DomainVerificationUserState(id).apply { addHosts(setOf("$packageName-user.com")) - isDisallowLinkHandling = true + isLinkHandlingAllowed = true } } - private fun pkgName(id: Int) = "${PKG_PREFIX}.pkg$id" + private fun pkgName(id: Int) = "$PKG_PREFIX.pkg$id" } diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt index 5629d1c1107d..48518f4693dd 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt @@ -244,6 +244,7 @@ class DomainVerificationSettingsMutationTest { this[0] = PackageUserState() } } + whenever(getInstantApp(anyInt())) { false } } } |