Merge changes I5e258e23,I72323430 into sc-dev

* changes:
  Update isLinkHandlingAllowed to mean all or nothing
  Update intent resolution logic with new rules
This commit is contained in:
Winson Chiu
2021-02-16 19:12:22 +00:00
committed by Android (Google) Code Review
13 changed files with 564 additions and 186 deletions

View File

@@ -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";
}

View File

@@ -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() {}

View File

@@ -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++) {
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;
final int count = candidates.size();
// First, try to use approved apps.
for (int n = 0; n < count; n++) {
ResolveInfo info = candidates.get(n);
// 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;
}
}
@@ -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,

View File

@@ -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());

View File

@@ -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 ");

View File

@@ -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;
@@ -47,6 +52,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.
*/
@@ -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.
* 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.
* 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
*/
boolean isApprovedForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent,
@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. 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.
*/
@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);
}
}
}

View File

@@ -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 =

View File

@@ -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 boolean isApprovedForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent,
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 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 APPROVAL_LEVEL_NONE;
}
DomainVerificationUserState userState = pkgState.getUserSelectionState(userId);
if (userState != null && !userState.isLinkHandlingAllowed()) {
if (DEBUG_APPROVAL) {
debugApproval(packageName, debugObject, userId, false,
"link handling not allowed");
}
return APPROVAL_LEVEL_NONE;
}
// 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;
}
return false;
}
ArrayMap<String, Integer> stateMap = pkgState.getStateMap();
DomainVerificationUserState userState = pkgState.getUserSelectionState(userId);
// 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;
}
// 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;
// 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;
}
// 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, intent, userId, true,
"host verified by wildcard");
}
return true;
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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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() {}

View File

@@ -334,6 +334,7 @@ class DomainVerificationEnforcerTest {
this[0] = PackageUserState()
}
}
whenever(getInstantApp(anyInt())) { false }
}
}

View File

@@ -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"
}

View File

@@ -244,6 +244,7 @@ class DomainVerificationSettingsMutationTest {
this[0] = PackageUserState()
}
}
whenever(getInstantApp(anyInt())) { false }
}
}