Merge changes I28bc7390,I2b248726,Ia7b7acff,Ia81866d2,I5b0deac6, ... into sc-dev

* changes:
  Rename to DomainVerificationUserState
  Rename to DomainVerificationInternalUserState
  Expose getDomainVerificationUserSelection as public API
  Fix setDomainVerificationLinkHandlingAllowed docs
  Rename get -> queryValidVerificationPackageNames
  Make DomainVerificationManager a final class
This commit is contained in:
Winson Chiu
2021-03-04 16:57:00 +00:00
committed by Android (Google) Code Review
27 changed files with 677 additions and 647 deletions

View File

@@ -12948,6 +12948,27 @@ package android.content.pm {
}
package android.content.pm.verify.domain {
public final class DomainVerificationManager {
method @Nullable public android.content.pm.verify.domain.DomainVerificationUserState getDomainVerificationUserState(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
}
public final class DomainVerificationUserState implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getHostToStateMap();
method @NonNull public String getPackageName();
method @NonNull public android.os.UserHandle getUser();
method @NonNull public boolean isLinkHandlingAllowed();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationUserState> CREATOR;
field public static final int DOMAIN_STATE_NONE = 0; // 0x0
field public static final int DOMAIN_STATE_SELECTED = 1; // 0x1
field public static final int DOMAIN_STATE_VERIFIED = 2; // 0x2
}
}
package android.content.res {
public class AssetFileDescriptor implements java.io.Closeable android.os.Parcelable {

View File

@@ -2789,13 +2789,12 @@ package android.content.pm.verify.domain {
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationInfo> CREATOR;
}
public interface DomainVerificationManager {
public final class DomainVerificationManager {
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION}) public android.content.pm.verify.domain.DomainVerificationInfo getDomainVerificationInfo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method @Nullable @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public android.content.pm.verify.domain.DomainVerificationUserSelection getDomainVerificationUserSelection(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public java.util.List<android.content.pm.verify.domain.DomainOwner> getOwnersForDomain(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public java.util.List<java.lang.String> getValidVerificationPackageNames();
method public static boolean isStateModifiable(int);
method public static boolean isStateVerified(int);
method @NonNull @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public java.util.List<java.lang.String> queryValidVerificationPackageNames();
method @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public void setDomainVerificationLinkHandlingAllowed(@NonNull String, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
method @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public void setDomainVerificationStatus(@NonNull java.util.UUID, @NonNull java.util.Set<java.lang.String>, int) throws android.content.pm.PackageManager.NameNotFoundException;
method @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public void setDomainVerificationUserSelection(@NonNull java.util.UUID, @NonNull java.util.Set<java.lang.String>, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -2812,18 +2811,8 @@ package android.content.pm.verify.domain {
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationRequest> CREATOR;
}
public final class DomainVerificationUserSelection implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getHostToStateMap();
public final class DomainVerificationUserState implements android.os.Parcelable {
method @NonNull public java.util.UUID getIdentifier();
method @NonNull public String getPackageName();
method @NonNull public android.os.UserHandle getUser();
method @NonNull public boolean isLinkHandlingAllowed();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationUserSelection> CREATOR;
field public static final int DOMAIN_STATE_NONE = 0; // 0x0
field public static final int DOMAIN_STATE_SELECTED = 1; // 0x1
field public static final int DOMAIN_STATE_VERIFIED = 2; // 0x2
}
}

View File

@@ -71,7 +71,6 @@ import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutManager;
import android.content.pm.verify.domain.DomainVerificationManager;
import android.content.pm.verify.domain.DomainVerificationManagerImpl;
import android.content.pm.verify.domain.IDomainVerificationManager;
import android.content.res.Resources;
import android.content.rollback.RollbackManagerFrameworkInitializer;
@@ -1422,7 +1421,6 @@ public final class SystemServiceRegistry {
}
});
// TODO(b/159952358): Only register this service for the domain verification agent?
registerService(Context.DOMAIN_VERIFICATION_SERVICE, DomainVerificationManager.class,
new CachedServiceFetcher<DomainVerificationManager>() {
@Override
@@ -1432,7 +1430,7 @@ public final class SystemServiceRegistry {
Context.DOMAIN_VERIFICATION_SERVICE);
IDomainVerificationManager service =
IDomainVerificationManager.Stub.asInterface(binder);
return new DomainVerificationManagerImpl(context, service);
return new DomainVerificationManager(context, service);
}
});

View File

@@ -7017,7 +7017,7 @@ public abstract class PackageManager {
* domain to an application, use
* {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)},
* passing in all of the domains returned inside
* {@link DomainVerificationManager#getDomainVerificationUserSelection(String)}.
* {@link DomainVerificationManager#getDomainVerificationUserState(String)}.
*
* @hide
*/

View File

@@ -66,16 +66,7 @@ public final class DomainOwner implements Parcelable {
* @param packageName
* Package name of that owns the domain.
* @param overrideable
* Whether or not this owner can be automatically overridden. If all owners for a domain are
* overrideable, then calling
* {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
* Set, boolean)} to enable the domain will disable all other owners. On the other hand, if any
* of the owners are non-overrideable, then
* {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
* boolean)} must be called with false to disable all of the other owners before this domain can
* be taken by a new owner through
* {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
* Set, boolean)}.
* Whether or not this owner can be automatically overridden.
*/
@DataClass.Generated.Member
public DomainOwner(
@@ -98,16 +89,9 @@ public final class DomainOwner implements Parcelable {
}
/**
* Whether or not this owner can be automatically overridden. If all owners for a domain are
* overrideable, then calling
* {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
* Set, boolean)} to enable the domain will disable all other owners. On the other hand, if any
* of the owners are non-overrideable, then
* {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
* boolean)} must be called with false to disable all of the other owners before this domain can
* be taken by a new owner through
* {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
* Set, boolean)}.
* Whether or not this owner can be automatically overridden.
*
* @see DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)
*/
@DataClass.Generated.Member
public boolean isOverrideable() {
@@ -205,7 +189,7 @@ public final class DomainOwner implements Parcelable {
};
@DataClass.Generated(
time = 1614119379978L,
time = 1614721802044L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainOwner.java",
inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final boolean mOverrideable\nclass DomainOwner extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genEqualsHashCode=true, genAidl=true, genToString=true)")

View File

@@ -94,7 +94,7 @@ public final class DomainVerificationInfo implements Parcelable {
private Map<String, Integer> unparcelHostToStateMap(Parcel in) {
return DomainVerificationUtils.readHostMap(in, new ArrayMap<>(),
DomainVerificationUserSelection.class.getClassLoader());
DomainVerificationUserState.class.getClassLoader());
}
@@ -105,8 +105,7 @@ public final class DomainVerificationInfo implements Parcelable {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
// /DomainVerificationInfo.java
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -321,7 +320,7 @@ public final class DomainVerificationInfo implements Parcelable {
};
@DataClass.Generated(
time = 1613002530369L,
time = 1614721812023L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationInfo.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 java.util.Map<java.lang.String,java.lang.Integer> mHostToStateMap\nprivate void parcelHostToStateMap(android.os.Parcel,int)\nprivate java.util.Map<java.lang.String,java.lang.Integer> unparcelHostToStateMap(android.os.Parcel)\nclass DomainVerificationInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true)")

View File

@@ -25,6 +25,8 @@ import android.annotation.SystemService;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.UserHandle;
import java.util.List;
@@ -32,55 +34,63 @@ import java.util.Set;
import java.util.UUID;
/**
* System service to access the domain verification APIs.
* System service to access domain verification APIs.
*
* Allows the approved domain verification
* agent on the device (the sole holder of
* {@link android.Manifest.permission#DOMAIN_VERIFICATION_AGENT}) to update the approval status
* of domains declared by applications in their AndroidManifest.xml, to allow them to open those
* links inside the app when selected by the user. This is done through querying
* {@link #getDomainVerificationInfo(String)} and calling
* {@link #setDomainVerificationStatus(UUID, Set, int)}.
*
* Also allows the domain preference settings (holder of
* {@link android.Manifest.permission#UPDATE_DOMAIN_VERIFICATION_USER_SELECTION}) to update the
* preferences of the user, when they have chosen to explicitly allow an application to open links.
* This is done through querying {@link #getDomainVerificationUserSelection(String)} and calling
* {@link #setDomainVerificationUserSelection(UUID, Set, boolean)} and
* {@link #setDomainVerificationLinkHandlingAllowed(String, boolean)}.
*
* @hide
* Applications should use {@link #getDomainVerificationUserState(String)} if necessary to
* check if/how they are verified for a domain, which is required starting from platform
* {@link android.os.Build.VERSION_CODES#S} in order to open {@link Intent}s which declare
* {@link Intent#CATEGORY_BROWSABLE} or no category and also match against
* {@link Intent#CATEGORY_DEFAULT} {@link android.content.IntentFilter}s, either through an
* explicit declaration of {@link Intent#CATEGORY_DEFAULT} or through the use of
* {@link android.content.pm.PackageManager#MATCH_DEFAULT_ONLY}, which is usually added for the
* caller when using {@link Context#startActivity(Intent)} and similar.
*/
@SystemApi
@SystemService(Context.DOMAIN_VERIFICATION_SERVICE)
public interface DomainVerificationManager {
public final class DomainVerificationManager {
/**
* Extra field name for a {@link DomainVerificationRequest} for the requested packages.
* Passed to an the domain verification agent that handles
* Extra field name for a {@link DomainVerificationRequest} for the requested packages. Passed
* to an the domain verification agent that handles
* {@link Intent#ACTION_DOMAINS_NEED_VERIFICATION}.
*
* @hide
*/
String EXTRA_VERIFICATION_REQUEST =
@SystemApi
public static final String EXTRA_VERIFICATION_REQUEST =
"android.content.pm.verify.domain.extra.VERIFICATION_REQUEST";
/**
* No response has been recorded by either the system or any verification agent.
*
* @hide
*/
int STATE_NO_RESPONSE = DomainVerificationState.STATE_NO_RESPONSE;
/** The verification agent has explicitly verified the domain at some point. */
int STATE_SUCCESS = DomainVerificationState.STATE_SUCCESS;
@SystemApi
public static final int STATE_NO_RESPONSE = DomainVerificationState.STATE_NO_RESPONSE;
/**
* The first available custom response code. This and any greater integer, along with
* {@link #STATE_SUCCESS} are the only values settable by the verification agent. All values
* will be treated as if the domain is unverified.
* The verification agent has explicitly verified the domain at some point.
*
* @hide
*/
int STATE_FIRST_VERIFIER_DEFINED = DomainVerificationState.STATE_FIRST_VERIFIER_DEFINED;
@SystemApi
public static final int STATE_SUCCESS = DomainVerificationState.STATE_SUCCESS;
/** @hide */
/**
* The first available custom response code. This and any greater integer, along with {@link
* #STATE_SUCCESS} are the only values settable by the verification agent. All values will be
* treated as if the domain is unverified.
*
* @hide
*/
@SystemApi
public static final int STATE_FIRST_VERIFIER_DEFINED =
DomainVerificationState.STATE_FIRST_VERIFIER_DEFINED;
/**
* @hide
*/
@NonNull
static String stateToDebugString(@DomainVerificationState.State int state) {
public static String stateToDebugString(@DomainVerificationState.State int state) {
switch (state) {
case DomainVerificationState.STATE_NO_RESPONSE:
return "none";
@@ -104,10 +114,13 @@ public interface DomainVerificationManager {
}
/**
* Checks if a state considers the corresponding domain to be successfully verified. The
* domain verification agent may use this to determine whether or not to re-verify a domain.
* Checks if a state considers the corresponding domain to be successfully verified. The domain
* verification agent may use this to determine whether or not to re-verify a domain.
*
* @hide
*/
static boolean isStateVerified(@DomainVerificationState.State int state) {
@SystemApi
public static boolean isStateVerified(@DomainVerificationState.State int state) {
switch (state) {
case DomainVerificationState.STATE_SUCCESS:
case DomainVerificationState.STATE_APPROVED:
@@ -126,10 +139,13 @@ public interface DomainVerificationManager {
/**
* Checks if a state is modifiable by the domain verification agent. This is useful as the
* platform may add new state codes in newer versions, and older verification agents can use
* this method to determine if a state can be changed without having to be aware of what the
* new state means.
* this method to determine if a state can be changed without having to be aware of what the new
* state means.
*
* @hide
*/
static boolean isStateModifiable(@DomainVerificationState.State int state) {
@SystemApi
public static boolean isStateModifiable(@DomainVerificationState.State int state) {
switch (state) {
case DomainVerificationState.STATE_NO_RESPONSE:
case DomainVerificationState.STATE_SUCCESS:
@@ -147,11 +163,12 @@ public interface DomainVerificationManager {
}
/**
* For determine re-verify policy. This is hidden from the domain verification agent so that
* no behavior is made based on the result.
* For determine re-verify policy. This is hidden from the domain verification agent so that no
* behavior is made based on the result.
*
* @hide
*/
static boolean isStateDefault(@DomainVerificationState.State int state) {
public static boolean isStateDefault(@DomainVerificationState.State int state) {
switch (state) {
case DomainVerificationState.STATE_NO_RESPONSE:
case DomainVerificationState.STATE_MIGRATED:
@@ -167,15 +184,73 @@ public interface DomainVerificationManager {
}
}
/**
* @hide
*/
public static final int ERROR_INVALID_DOMAIN_SET = 1;
/**
* @hide
*/
public static final int ERROR_NAME_NOT_FOUND = 2;
/**
* @hide
*/
@IntDef(prefix = {"ERROR_"}, value = {
ERROR_INVALID_DOMAIN_SET,
ERROR_NAME_NOT_FOUND,
})
private @interface Error {
}
private final Context mContext;
private final IDomainVerificationManager mDomainVerificationManager;
/**
* System service to access the domain verification APIs.
* <p>
* Allows the approved domain verification agent on the device (the sole holder of {@link
* android.Manifest.permission#DOMAIN_VERIFICATION_AGENT}) to update the approval status of
* domains declared by applications in their AndroidManifest.xml, to allow them to open those
* links inside the app when selected by the user. This is done through querying {@link
* #getDomainVerificationInfo(String)} and calling {@link #setDomainVerificationStatus(UUID,
* Set, int)}.
* <p>
* Also allows the domain preference settings (holder of
* {@link android.Manifest.permission#UPDATE_DOMAIN_VERIFICATION_USER_SELECTION})
* to update the preferences of the user, when they have chosen to explicitly allow an
* application to open links. This is done through querying
* {@link #getDomainVerificationUserState(String)} and calling
* {@link #setDomainVerificationUserSelection(UUID, Set, boolean)} and
* {@link #setDomainVerificationLinkHandlingAllowed(String, boolean)}.
*
* @hide
*/
public DomainVerificationManager(Context context,
IDomainVerificationManager domainVerificationManager) {
mContext = context;
mDomainVerificationManager = domainVerificationManager;
}
/**
* Used to iterate all {@link DomainVerificationInfo} values to do cleanup or retries. This is
* usually a heavy workload and should be done infrequently.
*
* @return the current snapshot of package names with valid autoVerify URLs.
* @hide
*/
@SystemApi
@NonNull
@RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT)
List<String> getValidVerificationPackageNames();
public List<String> queryValidVerificationPackageNames() {
try {
return mDomainVerificationManager.queryValidVerificationPackageNames();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Retrieves the domain verification state for a given package.
@@ -183,61 +258,106 @@ public interface DomainVerificationManager {
* @return the data for the package, or null if it does not declare any autoVerify domains
* @throws NameNotFoundException If the package is unavailable. This is an unrecoverable error
* and should not be re-tried except on a time scheduled basis.
* @hide
*/
@SystemApi
@Nullable
@RequiresPermission(anyOf = {
android.Manifest.permission.DOMAIN_VERIFICATION_AGENT,
android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
})
DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
throws NameNotFoundException;
public DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
throws NameNotFoundException {
try {
return mDomainVerificationManager.getDomainVerificationInfo(packageName);
} catch (Exception e) {
Exception converted = rethrow(e, packageName);
if (converted instanceof NameNotFoundException) {
throw (NameNotFoundException) converted;
} else if (converted instanceof RuntimeException) {
throw (RuntimeException) converted;
} else {
throw new RuntimeException(converted);
}
}
}
/**
* Change the verification status of the {@param domains} of the package associated with
* {@param domainSetId}.
* Change the verification status of the {@param domains} of the package associated with {@param
* domainSetId}.
*
* @param domainSetId See {@link DomainVerificationInfo#getIdentifier()}.
* @param domains List of host names to change the state of.
* @param state See {@link DomainVerificationInfo#getHostToStateMap()}.
* @throws IllegalArgumentException If the ID is invalidated or the {@param domains} are
* invalid. This usually means the work being processed by the
* verification agent is outdated and a new request should
* be scheduled, if one has not already been done as part of
* the {@link Intent#ACTION_DOMAINS_NEED_VERIFICATION}
* broadcast.
* verification agent is outdated and a new request should be
* scheduled, if one has not already been done as part of the
* {@link Intent#ACTION_DOMAINS_NEED_VERIFICATION} broadcast.
* @throws NameNotFoundException If the ID is known to be good, but the package is
* unavailable. This may be because the package is
* installed on a volume that is no longer mounted. This
* error is unrecoverable until the package is available
* again, and should not be re-tried except on a time
* scheduled basis.
* unavailable. This may be because the package is installed on
* a volume that is no longer mounted. This error is
* unrecoverable until the package is available again, and
* should not be re-tried except on a time scheduled basis.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT)
void setDomainVerificationStatus(@NonNull UUID domainSetId, @NonNull Set<String> domains,
@DomainVerificationState.State int state) throws NameNotFoundException;
public void setDomainVerificationStatus(@NonNull UUID domainSetId, @NonNull Set<String> domains,
@DomainVerificationState.State int state) throws NameNotFoundException {
try {
mDomainVerificationManager.setDomainVerificationStatus(domainSetId.toString(),
new DomainSet(domains), state);
} catch (Exception e) {
Exception converted = rethrow(e, domainSetId);
if (converted instanceof NameNotFoundException) {
throw (NameNotFoundException) converted;
} else if (converted instanceof RuntimeException) {
throw (RuntimeException) converted;
} else {
throw new RuntimeException(converted);
}
}
}
/**
* TODO(b/178525735): This documentation is incorrect in the context of UX changes.
* Change whether the given {@param packageName} is allowed to automatically open verified
* HTTP/HTTPS domains. The final state is determined along with the verification status for the
* specific domain being opened and other system state. An app with this enabled is not
* guaranteed to be the sole link handler for its domains.
* Change whether the given packageName is allowed to handle BROWSABLE and DEFAULT category web
* (HTTP/HTTPS) {@link Intent} Activity open requests. The final state is determined along with
* the verification status for the specific domain being opened and other system state. An app
* with this enabled is not guaranteed to be the sole link handler for its domains.
* <p>
* By default, all apps are allowed to open links. Users must disable them explicitly.
*
* By default, all apps are allowed to open verified links. Users must disable them explicitly.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName, boolean allowed)
throws NameNotFoundException;
public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
boolean allowed) throws NameNotFoundException {
try {
mDomainVerificationManager.setDomainVerificationLinkHandlingAllowed(packageName,
allowed, mContext.getUserId());
} catch (Exception e) {
Exception converted = rethrow(e, packageName);
if (converted instanceof NameNotFoundException) {
throw (NameNotFoundException) converted;
} else if (converted instanceof RuntimeException) {
throw (RuntimeException) converted;
} else {
throw new RuntimeException(converted);
}
}
}
/**
* Update the recorded user selection for the given {@param domains} for the given {@param
* domainSetId}. This state is recorded for the lifetime of a domain for a package on device,
* and will never be reset by the system short of an app data clear.
*
* <p>
* This state is stored per device user. If another user needs to be changed, the appropriate
* permissions must be acquired and
* {@link Context#createPackageContextAsUser(String, int, UserHandle)} should be used.
*
* permissions must be acquired and {@link Context#createContextAsUser(UserHandle, int)} should
* be used.
* <p>
* 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 a higher approval level. This can queried
* using {@link #getOwnersForDomain(String)}.
@@ -255,33 +375,55 @@ public interface DomainVerificationManager {
* @throws IllegalArgumentException If the ID is invalidated or the {@param domains} are
* invalid.
* @throws NameNotFoundException If the ID is known to be good, but the package is
* unavailable. This may be because the package is
* installed on a volume that is no longer mounted. This
* error is unrecoverable until the package is available
* again, and should not be re-tried except on a time
* scheduled basis.
* unavailable. This may be because the package is installed on
* a volume that is no longer mounted. This error is
* unrecoverable until the package is available again, and
* should not be re-tried except on a time scheduled basis.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
@NonNull Set<String> domains, boolean enabled) throws NameNotFoundException;
public void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
@NonNull Set<String> domains, boolean enabled) throws NameNotFoundException {
try {
mDomainVerificationManager.setDomainVerificationUserSelection(domainSetId.toString(),
new DomainSet(domains), enabled, mContext.getUserId());
} catch (Exception e) {
Exception converted = rethrow(e, domainSetId);
if (converted instanceof NameNotFoundException) {
throw (NameNotFoundException) converted;
} else if (converted instanceof RuntimeException) {
throw (RuntimeException) converted;
} else {
throw new RuntimeException(converted);
}
}
}
/**
* Retrieve the user selection data for the given {@param packageName} and the current user.
* It is the responsibility of the caller to ensure that the
* {@link DomainVerificationUserSelection#getIdentifier()} matches any prior API calls.
*
* This state is stored per device user. If another user needs to be accessed, the appropriate
* permissions must be acquired and
* {@link Context#createPackageContextAsUser(String, int, UserHandle)} should be used.
*
* @param packageName The app to query state for.
* @return the user selection verification data for the given package for the current user,
* or null if the package does not declare any HTTP/HTTPS domains.
* @return the user selection verification data for the given package for the current user, or
* null if the package does not declare any HTTP/HTTPS domains.
*/
@Nullable
@RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
DomainVerificationUserSelection getDomainVerificationUserSelection(@NonNull String packageName)
throws NameNotFoundException;
public DomainVerificationUserState getDomainVerificationUserState(
@NonNull String packageName) throws NameNotFoundException {
try {
return mDomainVerificationManager.getDomainVerificationUserState(packageName,
mContext.getUserId());
} catch (Exception e) {
Exception converted = rethrow(e, packageName);
if (converted instanceof NameNotFoundException) {
throw (NameNotFoundException) converted;
} else if (converted instanceof RuntimeException) {
throw (RuntimeException) converted;
} else {
throw new RuntimeException(converted);
}
}
}
/**
* For the given domain, return all apps which are approved to open it in a
@@ -291,21 +433,65 @@ public interface DomainVerificationManager {
*
* By default the list will be returned ordered from lowest to highest
* priority.
*
* @hide
*/
@SystemApi
@NonNull
@RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
List<DomainOwner> getOwnersForDomain(@NonNull String domain);
public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
try {
return mDomainVerificationManager.getOwnersForDomain(domain, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
private Exception rethrow(Exception exception, @Nullable UUID domainSetId) {
return rethrow(exception, domainSetId, null);
}
private Exception rethrow(Exception exception, @Nullable String packageName) {
return rethrow(exception, null, packageName);
}
private Exception rethrow(Exception exception, @Nullable UUID domainSetId,
@Nullable String packageName) {
if (exception instanceof ServiceSpecificException) {
int packedErrorCode = ((ServiceSpecificException) exception).errorCode;
if (packageName == null) {
packageName = exception.getMessage();
}
@Error int managerErrorCode = packedErrorCode & 0xFFFF;
switch (managerErrorCode) {
case ERROR_INVALID_DOMAIN_SET:
int errorSpecificCode = packedErrorCode >> 16;
return new IllegalArgumentException(InvalidDomainSetException.buildMessage(
domainSetId, packageName, errorSpecificCode));
case ERROR_NAME_NOT_FOUND:
return new NameNotFoundException(packageName);
default:
return exception;
}
} else if (exception instanceof RemoteException) {
return ((RemoteException) exception).rethrowFromSystemServer();
} else {
return exception;
}
}
/**
* Thrown if a {@link DomainVerificationInfo#getIdentifier()}} or an associated set of domains
* provided by the caller is no longer valid. This may be recoverable, and the caller should
* re-query the package name associated with the ID using
* {@link #getDomainVerificationInfo(String)} in order to check. If that also fails, then the
* package is no longer known to the device and thus all pending work for it should be dropped.
* {@link #getDomainVerificationInfo(String)}
* in order to check. If that also fails, then the package is no longer known to the device and
* thus all pending work for it should be dropped.
*
* @hide
*/
class InvalidDomainSetException extends IllegalArgumentException {
public static class InvalidDomainSetException extends IllegalArgumentException {
public static final int REASON_ID_NULL = 1;
public static final int REASON_ID_INVALID = 2;
@@ -313,7 +499,9 @@ public interface DomainVerificationManager {
public static final int REASON_UNKNOWN_DOMAIN = 4;
public static final int REASON_UNABLE_TO_APPROVE = 5;
/** @hide */
/**
* @hide
*/
@IntDef({
REASON_ID_NULL,
REASON_ID_INVALID,
@@ -352,7 +540,9 @@ public interface DomainVerificationManager {
@Nullable
private final String mPackageName;
/** @hide */
/**
* @hide
*/
public InvalidDomainSetException(@Nullable UUID domainSetId, @Nullable String packageName,
@Reason int reason) {
super(buildMessage(domainSetId, packageName, reason));

View File

@@ -1,202 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content.pm.verify.domain;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import java.util.List;
import java.util.Set;
import java.util.UUID;
/**
* @hide
*/
@SuppressWarnings("RedundantThrows")
public class DomainVerificationManagerImpl implements DomainVerificationManager {
public static final int ERROR_INVALID_DOMAIN_SET = 1;
public static final int ERROR_NAME_NOT_FOUND = 2;
@IntDef(prefix = { "ERROR_" }, value = {
ERROR_INVALID_DOMAIN_SET,
ERROR_NAME_NOT_FOUND,
})
private @interface Error {
}
private final Context mContext;
private final IDomainVerificationManager mDomainVerificationManager;
public DomainVerificationManagerImpl(Context context,
IDomainVerificationManager domainVerificationManager) {
mContext = context;
mDomainVerificationManager = domainVerificationManager;
}
@NonNull
@Override
public List<String> getValidVerificationPackageNames() {
try {
return mDomainVerificationManager.getValidVerificationPackageNames();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Nullable
@Override
public DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
throws NameNotFoundException {
try {
return mDomainVerificationManager.getDomainVerificationInfo(packageName);
} catch (Exception e) {
Exception converted = rethrow(e, packageName);
if (converted instanceof NameNotFoundException) {
throw (NameNotFoundException) converted;
} else if (converted instanceof RuntimeException) {
throw (RuntimeException) converted;
} else {
throw new RuntimeException(converted);
}
}
}
@Override
public void setDomainVerificationStatus(@NonNull UUID domainSetId, @NonNull Set<String> domains,
int state) throws IllegalArgumentException, NameNotFoundException {
try {
mDomainVerificationManager.setDomainVerificationStatus(domainSetId.toString(),
new DomainSet(domains), state);
} catch (Exception e) {
Exception converted = rethrow(e, domainSetId);
if (converted instanceof NameNotFoundException) {
throw (NameNotFoundException) converted;
} else if (converted instanceof RuntimeException) {
throw (RuntimeException) converted;
} else {
throw new RuntimeException(converted);
}
}
}
@Override
public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
boolean allowed) throws NameNotFoundException {
try {
mDomainVerificationManager.setDomainVerificationLinkHandlingAllowed(packageName,
allowed, mContext.getUserId());
} catch (Exception e) {
Exception converted = rethrow(e, packageName);
if (converted instanceof NameNotFoundException) {
throw (NameNotFoundException) converted;
} else if (converted instanceof RuntimeException) {
throw (RuntimeException) converted;
} else {
throw new RuntimeException(converted);
}
}
}
@Override
public void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
@NonNull Set<String> domains, boolean enabled)
throws IllegalArgumentException, NameNotFoundException {
try {
mDomainVerificationManager.setDomainVerificationUserSelection(domainSetId.toString(),
new DomainSet(domains), enabled, mContext.getUserId());
} catch (Exception e) {
Exception converted = rethrow(e, domainSetId);
if (converted instanceof NameNotFoundException) {
throw (NameNotFoundException) converted;
} else if (converted instanceof RuntimeException) {
throw (RuntimeException) converted;
} else {
throw new RuntimeException(converted);
}
}
}
@Nullable
@Override
public DomainVerificationUserSelection getDomainVerificationUserSelection(
@NonNull String packageName) throws NameNotFoundException {
try {
return mDomainVerificationManager.getDomainVerificationUserSelection(packageName,
mContext.getUserId());
} catch (Exception e) {
Exception converted = rethrow(e, packageName);
if (converted instanceof NameNotFoundException) {
throw (NameNotFoundException) converted;
} else if (converted instanceof RuntimeException) {
throw (RuntimeException) converted;
} else {
throw new RuntimeException(converted);
}
}
}
@NonNull
@Override
public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
try {
return mDomainVerificationManager.getOwnersForDomain(domain, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
private Exception rethrow(Exception exception, @Nullable UUID domainSetId) {
return rethrow(exception, domainSetId, null);
}
private Exception rethrow(Exception exception, @Nullable String packageName) {
return rethrow(exception, null, packageName);
}
private Exception rethrow(Exception exception, @Nullable UUID domainSetId,
@Nullable String packageName) {
if (exception instanceof ServiceSpecificException) {
int packedErrorCode = ((ServiceSpecificException) exception).errorCode;
if (packageName == null) {
packageName = exception.getMessage();
}
@Error int managerErrorCode = packedErrorCode & 0xFFFF;
switch (managerErrorCode) {
case ERROR_INVALID_DOMAIN_SET:
int errorSpecificCode = packedErrorCode >> 16;
return new IllegalArgumentException(InvalidDomainSetException.buildMessage(
domainSetId, packageName, errorSpecificCode));
case ERROR_NAME_NOT_FOUND:
return new NameNotFoundException(packageName);
default:
return exception;
}
} else if (exception instanceof RemoteException) {
return ((RemoteException) exception).rethrowFromSystemServer();
} else {
return exception;
}
}
}

View File

@@ -16,4 +16,4 @@
package android.content.pm.verify.domain;
parcelable DomainVerificationUserSelection;
parcelable DomainVerificationUserState;

View File

@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
@@ -29,39 +30,36 @@ import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
import java.util.Map;
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.
* <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 all links. Note that the
* toggle affects <b>all</b> links and is not based on the verification state of the domains.
* Applications should use {@link #getHostToStateMap()} if necessary to
* check if/how they are verified for a domain, which is required starting from platform
* {@link android.os.Build.VERSION_CODES#S} in order to open {@link Intent}s which declare
* {@link Intent#CATEGORY_BROWSABLE} or no category and also match against
* {@link Intent#CATEGORY_DEFAULT} {@link android.content.IntentFilter}s, either through an
* explicit declaration of {@link Intent#CATEGORY_DEFAULT} or through the use of
* {@link android.content.pm.PackageManager#MATCH_DEFAULT_ONLY}, which is usually added for the
* caller when using {@link Context#startActivity(Intent)} and similar.
* <p>
* By default, all apps are allowed to automatically open links for the above case for 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 all links. Note
* that the toggle affects <b>all</b> links and is not based on the verification state of the
* domains.
* <p>
* 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 #getHostToStateMap()}. 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,
* boolean)} and {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
* boolean)} APIs.
* <p>
* Note that because state is per user, if a different user needs to be changed, one will need to
* use {@link Context#createContextAsUser(UserHandle, int)} and hold the {@link
* android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
*
* @hide
*/
@SystemApi
@SuppressWarnings("DefaultAnnotationParam")
@DataClass(genAidl = true, genHiddenConstructor = true, genParcelable = true, genToString = true,
genEqualsHashCode = true, genHiddenConstDefs = true)
public final class DomainVerificationUserSelection implements Parcelable {
public final class DomainVerificationUserState implements Parcelable {
/**
* The domain is unverified and unselected, and the application is unable to open web links
@@ -70,9 +68,8 @@ public final class DomainVerificationUserSelection implements Parcelable {
public static final int DOMAIN_STATE_NONE = 0;
/**
* The domain has been selected through the
* {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)}
* API, under the assumption it has not been reset by the system.
* The domain has been selected by the user. This may be reset to {@link #DOMAIN_STATE_NONE} if
* another application is selected or verified for the same domain.
*/
public static final int DOMAIN_STATE_SELECTED = 1;
@@ -119,7 +116,16 @@ public final class DomainVerificationUserSelection implements Parcelable {
@NonNull
private Map<String, Integer> unparcelHostToStateMap(Parcel in) {
return DomainVerificationUtils.readHostMap(in, new ArrayMap<>(),
DomainVerificationUserSelection.class.getClassLoader());
DomainVerificationUserState.class.getClassLoader());
}
/**
* @see DomainVerificationInfo#getIdentifier
* @hide
*/
@SystemApi
public @NonNull UUID getIdentifier() {
return mIdentifier;
}
@@ -130,7 +136,7 @@ public final class DomainVerificationUserSelection implements Parcelable {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserState.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -162,7 +168,7 @@ public final class DomainVerificationUserSelection implements Parcelable {
}
/**
* Creates a new DomainVerificationUserSelection.
* Creates a new DomainVerificationUserState.
*
* @param packageName
* The package name that this data corresponds to.
@@ -175,7 +181,7 @@ public final class DomainVerificationUserSelection implements Parcelable {
* @hide
*/
@DataClass.Generated.Member
public DomainVerificationUserSelection(
public DomainVerificationUserState(
@NonNull UUID identifier,
@NonNull String packageName,
@NonNull UserHandle user,
@@ -200,14 +206,6 @@ public final class DomainVerificationUserSelection implements Parcelable {
// onConstructed(); // You can define this method to get a callback
}
/**
* @see DomainVerificationInfo#getIdentifier
*/
@DataClass.Generated.Member
public @NonNull UUID getIdentifier() {
return mIdentifier;
}
/**
* The package name that this data corresponds to.
*/
@@ -246,7 +244,7 @@ public final class DomainVerificationUserSelection implements Parcelable {
// You can override field toString logic by defining methods like:
// String fieldNameToString() { ... }
return "DomainVerificationUserSelection { " +
return "DomainVerificationUserState { " +
"identifier = " + mIdentifier + ", " +
"packageName = " + mPackageName + ", " +
"user = " + mUser + ", " +
@@ -259,13 +257,13 @@ public final class DomainVerificationUserSelection implements Parcelable {
@DataClass.Generated.Member
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(DomainVerificationUserState other) { ... }
// boolean fieldNameEquals(FieldType otherValue) { ... }
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@SuppressWarnings("unchecked")
DomainVerificationUserSelection that = (DomainVerificationUserSelection) o;
DomainVerificationUserState that = (DomainVerificationUserState) o;
//noinspection PointlessBooleanExpression
return true
&& java.util.Objects.equals(mIdentifier, that.mIdentifier)
@@ -323,7 +321,7 @@ public final class DomainVerificationUserSelection implements Parcelable {
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
/* package-private */ DomainVerificationUserSelection(@NonNull Parcel in) {
/* package-private */ DomainVerificationUserState(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
@@ -354,24 +352,24 @@ public final class DomainVerificationUserSelection implements Parcelable {
}
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<DomainVerificationUserSelection> CREATOR
= new Parcelable.Creator<DomainVerificationUserSelection>() {
public static final @NonNull Parcelable.Creator<DomainVerificationUserState> CREATOR
= new Parcelable.Creator<DomainVerificationUserState>() {
@Override
public DomainVerificationUserSelection[] newArray(int size) {
return new DomainVerificationUserSelection[size];
public DomainVerificationUserState[] newArray(int size) {
return new DomainVerificationUserState[size];
}
@Override
public DomainVerificationUserSelection createFromParcel(@NonNull Parcel in) {
return new DomainVerificationUserSelection(in);
public DomainVerificationUserState createFromParcel(@NonNull Parcel in) {
return new DomainVerificationUserState(in);
}
};
@DataClass.Generated(
time = 1613683603297L,
time = 1614721840152L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java",
inputSignatures = "public static final int DOMAIN_STATE_NONE\npublic static final int DOMAIN_STATE_SELECTED\npublic static final int DOMAIN_STATE_VERIFIED\nprivate 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.Integer> mHostToStateMap\nprivate void parcelHostToStateMap(android.os.Parcel,int)\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> unparcelHostToStateMap(android.os.Parcel)\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, genHiddenConstDefs=true)")
sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserState.java",
inputSignatures = "public static final int DOMAIN_STATE_NONE\npublic static final int DOMAIN_STATE_SELECTED\npublic static final int DOMAIN_STATE_VERIFIED\nprivate 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.Integer> mHostToStateMap\nprivate void parcelHostToStateMap(android.os.Parcel,int)\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> unparcelHostToStateMap(android.os.Parcel)\npublic @android.annotation.SystemApi @android.annotation.NonNull java.util.UUID getIdentifier()\nclass DomainVerificationUserState extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}

View File

@@ -19,7 +19,7 @@ package android.content.pm.verify.domain;
import android.content.pm.verify.domain.DomainOwner;
import android.content.pm.verify.domain.DomainSet;
import android.content.pm.verify.domain.DomainVerificationInfo;
import android.content.pm.verify.domain.DomainVerificationUserSelection;
import android.content.pm.verify.domain.DomainVerificationUserState;
import java.util.List;
/**
@@ -28,13 +28,13 @@ import java.util.List;
*/
interface IDomainVerificationManager {
List<String> getValidVerificationPackageNames();
List<String> queryValidVerificationPackageNames();
@nullable
DomainVerificationInfo getDomainVerificationInfo(String packageName);
@nullable
DomainVerificationUserSelection getDomainVerificationUserSelection(String packageName,
DomainVerificationUserState getDomainVerificationUserState(String packageName,
int userId);
@nullable

View File

@@ -33,9 +33,9 @@ import android.util.SparseArray;
import com.android.internal.util.CollectionUtils;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
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.function.Function;
@@ -169,8 +169,8 @@ public class DomainVerificationDebug {
}
ArraySet<String> allWebDomains = mCollector.collectAllWebDomains(pkg);
SparseArray<DomainVerificationUserState> userStates =
pkgState.getUserSelectionStates();
SparseArray<DomainVerificationInternalUserState> userStates =
pkgState.getUserStates();
if (userId == UserHandle.USER_ALL) {
int size = userStates.size();
if (size == 0) {
@@ -178,13 +178,13 @@ public class DomainVerificationDebug {
wasHeaderPrinted);
} else {
for (int index = 0; index < size; index++) {
DomainVerificationUserState userState = userStates.valueAt(index);
DomainVerificationInternalUserState userState = userStates.valueAt(index);
printState(writer, pkgState, userState.getUserId(), userState, reusedSet,
allWebDomains, wasHeaderPrinted);
}
}
} else {
DomainVerificationUserState userState = userStates.get(userId);
DomainVerificationInternalUserState userState = userStates.get(userId);
printState(writer, pkgState, userId, userState, reusedSet, allWebDomains,
wasHeaderPrinted);
}
@@ -192,8 +192,9 @@ public class DomainVerificationDebug {
boolean printState(@NonNull IndentingPrintWriter writer,
@NonNull DomainVerificationPkgState pkgState, @UserIdInt int userId,
@Nullable DomainVerificationUserState userState, @NonNull ArraySet<String> reusedSet,
@NonNull ArraySet<String> allWebDomains, boolean wasHeaderPrinted) {
@Nullable DomainVerificationInternalUserState userState,
@NonNull ArraySet<String> reusedSet, @NonNull ArraySet<String> allWebDomains,
boolean wasHeaderPrinted) {
reusedSet.clear();
reusedSet.addAll(allWebDomains);
if (userState != null) {

View File

@@ -129,6 +129,21 @@ public class DomainVerificationEnforcer {
}
}
/**
* Enforced when mutating user selection state inside an exposed API method.
*/
public boolean assertApprovedUserStateQuerent(int callingUid, @UserIdInt int callingUserId,
@NonNull String packageName, @UserIdInt int targetUserId) throws SecurityException {
if (callingUserId != targetUserId) {
mContext.enforcePermission(
Manifest.permission.INTERACT_ACROSS_USERS,
Binder.getCallingPid(), callingUid,
"Caller is not allowed to edit other users");
}
return !mCallback.filterAppAccess(packageName, callingUid, targetUserId);
}
/**
* Enforced when mutating user selection state inside an exposed API method.
*/

View File

@@ -48,7 +48,7 @@ import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
public interface DomainVerificationManagerInternal extends DomainVerificationManager {
public interface DomainVerificationManagerInternal {
UUID DISABLED_ID = new UUID(0, 0);
@@ -69,8 +69,8 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan
* 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.
* shipped. These values are not stable, so just deleting the constant and shifting others is
* fine.
*/
int APPROVAL_LEVEL_LEGACY_ASK = 1;
@@ -84,14 +84,15 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan
/**
* 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.
* {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)},
* indicating 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
* it is capturing. This is set through
* {@link DomainVerificationManager#setDomainVerificationStatus(UUID, Set, int)} by
* the domain verification agent on device.
*/
int APPROVAL_LEVEL_VERIFIED = 3;
@@ -102,7 +103,7 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan
* 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)}.
* {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String, boolean)}.
*/
int APPROVAL_LEVEL_INSTANT_APP = 4;
@@ -122,7 +123,17 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan
APPROVAL_LEVEL_VERIFIED,
APPROVAL_LEVEL_INSTANT_APP
})
@interface ApprovalLevel{}
@interface ApprovalLevel {
}
/** @see DomainVerificationManager#getDomainVerificationInfo(String) */
@Nullable
@RequiresPermission(anyOf = {
android.Manifest.permission.DOMAIN_VERIFICATION_AGENT,
android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
})
DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
throws NameNotFoundException;
/**
* Generate a new domain set ID to be used for attaching new packages.
@@ -173,9 +184,9 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan
/**
* Migrates verification state from a previous install to a new one. It is expected that the
* {@link PackageSetting#getDomainSetId()} already be set to the correct value, usually from
* {@link #generateNewId()}. This will preserve {@link #STATE_SUCCESS} domains under the
* assumption that the new package will pass the same server side config as the previous
* package, as they have matching signatures.
* {@link #generateNewId()}. This will preserve {@link DomainVerificationManager#STATE_SUCCESS}
* domains under the assumption that the new package will pass the same server side config as
* the previous package, as they have matching signatures.
* <p>
* This will mutate internal {@link DomainVerificationPkgState} and so will hold the internal
* lock. This should never be called from within the domain verification classes themselves.
@@ -229,8 +240,10 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan
* tag has already been entered.
* <p>
* This is <b>only</b> for restore, and will override package states, ignoring if their {@link
* DomainVerificationInfo#getIdentifier()}s match. It's expected that any restored domains marked
* as success verify against the server correctly, although the verification agent may decide to
* DomainVerificationInfo#getIdentifier()}s match. It's expected that any restored domains
* marked
* as success verify against the server correctly, although the verification agent may decide
* to
* re-verify them when it gets the chance.
*/
/*

View File

@@ -23,29 +23,29 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.verify.domain.DomainOwner;
import android.content.pm.verify.domain.DomainSet;
import android.content.pm.verify.domain.DomainVerificationInfo;
import android.content.pm.verify.domain.DomainVerificationManager;
import android.content.pm.verify.domain.DomainVerificationManager.InvalidDomainSetException;
import android.content.pm.verify.domain.DomainVerificationManagerImpl;
import android.content.pm.verify.domain.DomainVerificationUserSelection;
import android.content.pm.verify.domain.DomainVerificationUserState;
import android.content.pm.verify.domain.IDomainVerificationManager;
import android.os.ServiceSpecificException;
import java.util.List;
import java.util.UUID;
class DomainVerificationManagerStub extends IDomainVerificationManager.Stub {
public class DomainVerificationManagerStub extends IDomainVerificationManager.Stub {
@NonNull
private DomainVerificationService mService;
private final DomainVerificationService mService;
DomainVerificationManagerStub(DomainVerificationService service) {
public DomainVerificationManagerStub(DomainVerificationService service) {
mService = service;
}
@NonNull
@Override
public List<String> getValidVerificationPackageNames() {
public List<String> queryValidVerificationPackageNames() {
try {
return mService.getValidVerificationPackageNames();
return mService.queryValidVerificationPackageNames();
} catch (Exception e) {
throw rethrow(e);
}
@@ -95,10 +95,10 @@ class DomainVerificationManagerStub extends IDomainVerificationManager.Stub {
@Nullable
@Override
public DomainVerificationUserSelection getDomainVerificationUserSelection(
public DomainVerificationUserState getDomainVerificationUserState(
String packageName, @UserIdInt int userId) {
try {
return mService.getDomainVerificationUserSelection(packageName, userId);
return mService.getDomainVerificationUserState(packageName, userId);
} catch (Exception e) {
throw rethrow(e);
}
@@ -117,13 +117,13 @@ class DomainVerificationManagerStub extends IDomainVerificationManager.Stub {
private RuntimeException rethrow(Exception exception) throws RuntimeException {
if (exception instanceof InvalidDomainSetException) {
int packedErrorCode = DomainVerificationManagerImpl.ERROR_INVALID_DOMAIN_SET;
int packedErrorCode = DomainVerificationManager.ERROR_INVALID_DOMAIN_SET;
packedErrorCode |= ((InvalidDomainSetException) exception).getReason() << 16;
return new ServiceSpecificException(packedErrorCode,
((InvalidDomainSetException) exception).getPackageName());
} else if (exception instanceof NameNotFoundException) {
return new ServiceSpecificException(
DomainVerificationManagerImpl.ERROR_NAME_NOT_FOUND);
DomainVerificationManager.ERROR_NAME_NOT_FOUND);
} else if (exception instanceof RuntimeException) {
return (RuntimeException) exception;
} else {

View File

@@ -27,9 +27,9 @@ import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import com.android.server.pm.SettingsXml;
import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
import com.android.server.pm.verify.domain.models.DomainVerificationUserState;
import org.xmlpull.v1.XmlPullParserException;
@@ -157,7 +157,7 @@ public class DomainVerificationPersistence {
UUID id = UUID.fromString(idString);
final ArrayMap<String, Integer> stateMap = new ArrayMap<>();
final SparseArray<DomainVerificationUserState> userStates = new SparseArray<>();
final SparseArray<DomainVerificationInternalUserState> userStates = new SparseArray<>();
SettingsXml.ChildSection child = section.children();
while (child.moveToNext()) {
@@ -176,10 +176,10 @@ public class DomainVerificationPersistence {
}
private static void readUserStates(@NonNull SettingsXml.ReadSection section,
@NonNull SparseArray<DomainVerificationUserState> userStates) {
@NonNull SparseArray<DomainVerificationInternalUserState> userStates) {
SettingsXml.ChildSection child = section.children();
while (child.moveToNext(TAG_USER_STATE)) {
DomainVerificationUserState userState = createUserStateFromXml(child);
DomainVerificationInternalUserState userState = createUserStateFromXml(child);
if (userState != null) {
userStates.put(userState.getUserId(), userState);
}
@@ -205,12 +205,12 @@ public class DomainVerificationPersistence {
.attribute(ATTR_HAS_AUTO_VERIFY_DOMAINS,
pkgState.isHasAutoVerifyDomains())) {
writeStateMap(parentSection, pkgState.getStateMap());
writeUserStates(parentSection, pkgState.getUserSelectionStates());
writeUserStates(parentSection, pkgState.getUserStates());
}
}
private static void writeUserStates(@NonNull SettingsXml.WriteSection parentSection,
@NonNull SparseArray<DomainVerificationUserState> states) throws IOException {
@NonNull SparseArray<DomainVerificationInternalUserState> states) throws IOException {
int size = states.size();
if (size == 0) {
return;
@@ -245,7 +245,7 @@ public class DomainVerificationPersistence {
* entered.
*/
@Nullable
public static DomainVerificationUserState createUserStateFromXml(
public static DomainVerificationInternalUserState createUserStateFromXml(
@NonNull SettingsXml.ReadSection section) {
int userId = section.getInt(ATTR_USER_ID);
if (userId == -1) {
@@ -260,7 +260,7 @@ public class DomainVerificationPersistence {
readEnabledHosts(child, enabledHosts);
}
return new DomainVerificationUserState(userId, enabledHosts, allowLinkHandling);
return new DomainVerificationInternalUserState(userId, enabledHosts, allowLinkHandling);
}
private static void readEnabledHosts(@NonNull SettingsXml.ReadSection section,
@@ -275,7 +275,7 @@ public class DomainVerificationPersistence {
}
public static void writeUserStateToXml(@NonNull SettingsXml.WriteSection parentSection,
@NonNull DomainVerificationUserState userState) throws IOException {
@NonNull DomainVerificationInternalUserState userState) throws IOException {
try (SettingsXml.WriteSection section =
parentSection.startSection(TAG_USER_STATE)
.attribute(ATTR_USER_ID, userState.getUserId())

View File

@@ -34,8 +34,9 @@ import android.content.pm.parsing.component.ParsedActivity;
import android.content.pm.verify.domain.DomainOwner;
import android.content.pm.verify.domain.DomainVerificationInfo;
import android.content.pm.verify.domain.DomainVerificationManager;
import android.content.pm.verify.domain.DomainVerificationManager.InvalidDomainSetException;
import android.content.pm.verify.domain.DomainVerificationState;
import android.content.pm.verify.domain.DomainVerificationUserSelection;
import android.content.pm.verify.domain.DomainVerificationUserState;
import android.content.pm.verify.domain.IDomainVerificationManager;
import android.os.UserHandle;
import android.util.ArrayMap;
@@ -55,9 +56,9 @@ import com.android.server.SystemService;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
import com.android.server.pm.verify.domain.models.DomainVerificationUserState;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyUnavailable;
@@ -208,8 +209,7 @@ public class DomainVerificationService extends SystemService
}
@NonNull
@Override
public List<String> getValidVerificationPackageNames() {
public List<String> queryValidVerificationPackageNames() {
mEnforcer.assertApprovedVerifier(mConnection.getCallingUid(), mProxy);
List<String> packageNames = new ArrayList<>();
synchronized (mLock) {
@@ -272,7 +272,6 @@ public class DomainVerificationService extends SystemService
}
}
@Override
public void setDomainVerificationStatus(@NonNull UUID domainSetId, @NonNull Set<String> domains,
int state) throws InvalidDomainSetException, NameNotFoundException {
if (state < DomainVerificationState.STATE_FIRST_VERIFIER_DEFINED) {
@@ -314,7 +313,7 @@ public class DomainVerificationService extends SystemService
int size = verifiedDomains.size();
for (int index = 0; index < size; index++) {
removeUserSelectionsForDomain(verifiedDomains.get(index));
removeUserStatesForDomain(verifiedDomains.get(index));
}
}
@@ -401,12 +400,12 @@ public class DomainVerificationService extends SystemService
}
}
private void removeUserSelectionsForDomain(@NonNull String domain) {
private void removeUserStatesForDomain(@NonNull String domain) {
synchronized (mLock) {
final int size = mAttachedPkgStates.size();
for (int index = 0; index < size; index++) {
DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
SparseArray<DomainVerificationUserState> array = pkgState.getUserSelectionStates();
SparseArray<DomainVerificationInternalUserState> array = pkgState.getUserStates();
int arraySize = array.size();
for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) {
array.valueAt(arrayIndex).removeHost(domain);
@@ -415,13 +414,6 @@ public class DomainVerificationService extends SystemService
}
}
@Override
public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
boolean allowed) throws NameNotFoundException {
setDomainVerificationLinkHandlingAllowed(packageName, allowed,
mConnection.getCallingUserId());
}
public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
boolean allowed, @UserIdInt int userId) throws NameNotFoundException {
if (!mEnforcer.assertApprovedUserSelector(mConnection.getCallingUid(),
@@ -434,7 +426,7 @@ public class DomainVerificationService extends SystemService
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
pkgState.getOrCreateUserSelectionState(userId)
pkgState.getOrCreateUserState(userId)
.setLinkHandlingAllowed(allowed);
}
@@ -452,11 +444,11 @@ public class DomainVerificationService extends SystemService
DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(pkgStateIndex);
if (userId == UserHandle.USER_ALL) {
for (int aUserId : mConnection.getAllUserIds()) {
pkgState.getOrCreateUserSelectionState(aUserId)
pkgState.getOrCreateUserState(aUserId)
.setLinkHandlingAllowed(allowed);
}
} else {
pkgState.getOrCreateUserSelectionState(userId)
pkgState.getOrCreateUserState(userId)
.setLinkHandlingAllowed(allowed);
}
}
@@ -468,7 +460,7 @@ public class DomainVerificationService extends SystemService
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
pkgState.getOrCreateUserSelectionState(userId)
pkgState.getOrCreateUserState(userId)
.setLinkHandlingAllowed(allowed);
}
}
@@ -476,14 +468,6 @@ public class DomainVerificationService extends SystemService
mConnection.scheduleWriteSettings();
}
@Override
public void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
@NonNull Set<String> domains, boolean enabled)
throws InvalidDomainSetException, NameNotFoundException {
setDomainVerificationUserSelection(domainSetId, domains, enabled,
mConnection.getCallingUserId());
}
public void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
@NonNull Set<String> domains, boolean enabled, @UserIdInt int userId)
throws InvalidDomainSetException, NameNotFoundException {
@@ -500,7 +484,8 @@ public class DomainVerificationService extends SystemService
DomainVerificationPkgState pkgState = getAndValidateAttachedLocked(domainSetId, domains,
false /* forAutoVerify */, callingUid, userId);
DomainVerificationUserState userState = pkgState.getOrCreateUserSelectionState(userId);
DomainVerificationInternalUserState userState =
pkgState.getOrCreateUserState(userId);
// Disable other packages if approving this one. Note that this check is only done for
// enabling. This allows an escape hatch in case multiple packages somehow get selected.
@@ -540,8 +525,8 @@ public class DomainVerificationService extends SystemService
continue;
}
DomainVerificationUserState approvedUserState =
approvedPkgState.getUserSelectionState(userId);
DomainVerificationInternalUserState approvedUserState =
approvedPkgState.getUserState(userId);
if (approvedUserState == null) {
continue;
}
@@ -623,8 +608,8 @@ public class DomainVerificationService extends SystemService
if (userId == UserHandle.USER_ALL) {
for (int aUserId : mConnection.getAllUserIds()) {
DomainVerificationUserState userState =
pkgState.getOrCreateUserSelectionState(aUserId);
DomainVerificationInternalUserState userState =
pkgState.getOrCreateUserState(aUserId);
if (enabled) {
userState.addHosts(domains);
} else {
@@ -632,7 +617,8 @@ public class DomainVerificationService extends SystemService
}
}
} else {
DomainVerificationUserState userState = pkgState.getOrCreateUserSelectionState(userId);
DomainVerificationInternalUserState userState =
pkgState.getOrCreateUserState(userId);
if (enabled) {
userState.addHosts(domains);
} else {
@@ -643,17 +629,9 @@ public class DomainVerificationService extends SystemService
@Nullable
@Override
public DomainVerificationUserSelection getDomainVerificationUserSelection(
@NonNull String packageName) throws NameNotFoundException {
return getDomainVerificationUserSelection(packageName,
mConnection.getCallingUserId());
}
@Nullable
@Override
public DomainVerificationUserSelection getDomainVerificationUserSelection(
public DomainVerificationUserState getDomainVerificationUserState(
@NonNull String packageName, @UserIdInt int userId) throws NameNotFoundException {
if (!mEnforcer.assertApprovedUserSelector(mConnection.getCallingUid(),
if (!mEnforcer.assertApprovedUserStateQuerent(mConnection.getCallingUid(),
mConnection.getCallingUserId(), packageName, userId)) {
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
@@ -673,7 +651,7 @@ public class DomainVerificationService extends SystemService
Map<String, Integer> domains = new ArrayMap<>(webDomainsSize);
ArrayMap<String, Integer> stateMap = pkgState.getStateMap();
DomainVerificationUserState userState = pkgState.getUserSelectionState(userId);
DomainVerificationInternalUserState userState = pkgState.getUserState(userId);
Set<String> enabledHosts = userState == null ? emptySet() : userState.getEnabledHosts();
for (int index = 0; index < webDomainsSize; index++) {
@@ -682,11 +660,11 @@ public class DomainVerificationService extends SystemService
int domainState;
if (state != null && DomainVerificationManager.isStateVerified(state)) {
domainState = DomainVerificationUserSelection.DOMAIN_STATE_VERIFIED;
domainState = DomainVerificationUserState.DOMAIN_STATE_VERIFIED;
} else if (enabledHosts.contains(host)) {
domainState = DomainVerificationUserSelection.DOMAIN_STATE_SELECTED;
domainState = DomainVerificationUserState.DOMAIN_STATE_SELECTED;
} else {
domainState = DomainVerificationUserSelection.DOMAIN_STATE_NONE;
domainState = DomainVerificationUserState.DOMAIN_STATE_NONE;
}
domains.put(host, domainState);
@@ -694,17 +672,11 @@ public class DomainVerificationService extends SystemService
boolean linkHandlingAllowed = userState == null || userState.isLinkHandlingAllowed();
return new DomainVerificationUserSelection(pkgState.getId(), packageName,
return new DomainVerificationUserState(pkgState.getId(), packageName,
UserHandle.of(userId), linkHandlingAllowed, domains);
}
}
@NonNull
@Override
public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
return getOwnersForDomain(domain, mConnection.getCallingUserId());
}
public List<DomainOwner> getOwnersForDomain(@NonNull String domain, @UserIdInt int userId) {
mEnforcer.assertOwnerQuerent(mConnection.getCallingUid(), mConnection.getCallingUserId(),
userId);
@@ -795,7 +767,7 @@ public class DomainVerificationService extends SystemService
AndroidPackage newPkg = newPkgSetting.getPkg();
ArrayMap<String, Integer> newStateMap = new ArrayMap<>();
SparseArray<DomainVerificationUserState> newUserStates = new SparseArray<>();
SparseArray<DomainVerificationInternalUserState> newUserStates = new SparseArray<>();
if (oldPkgState == null || oldPkg == null || newPkg == null) {
// Should be impossible, but to be safe, continue with a new blank state instead
@@ -838,21 +810,22 @@ public class DomainVerificationService extends SystemService
}
}
SparseArray<DomainVerificationUserState> oldUserStates =
oldPkgState.getUserSelectionStates();
SparseArray<DomainVerificationInternalUserState> oldUserStates =
oldPkgState.getUserStates();
int oldUserStatesSize = oldUserStates.size();
if (oldUserStatesSize > 0) {
ArraySet<String> newWebDomains = mCollector.collectValidAutoVerifyDomains(newPkg);
for (int oldUserStatesIndex = 0; oldUserStatesIndex < oldUserStatesSize;
oldUserStatesIndex++) {
int userId = oldUserStates.keyAt(oldUserStatesIndex);
DomainVerificationUserState oldUserState = oldUserStates.valueAt(
DomainVerificationInternalUserState oldUserState = oldUserStates.valueAt(
oldUserStatesIndex);
ArraySet<String> oldEnabledHosts = oldUserState.getEnabledHosts();
ArraySet<String> newEnabledHosts = new ArraySet<>(oldEnabledHosts);
newEnabledHosts.retainAll(newWebDomains);
DomainVerificationUserState newUserState = new DomainVerificationUserState(
userId, newEnabledHosts, oldUserState.isLinkHandlingAllowed());
DomainVerificationInternalUserState newUserState =
new DomainVerificationInternalUserState(userId, newEnabledHosts,
oldUserState.isLinkHandlingAllowed());
newUserStates.put(userId, newUserState);
}
}
@@ -926,7 +899,7 @@ public class DomainVerificationService extends SystemService
webDomains = mCollector.collectAllWebDomains(pkg);
}
pkgState.getOrCreateUserSelectionState(userId).addHosts(webDomains);
pkgState.getOrCreateUserState(userId).addHosts(webDomains);
}
}
@@ -1295,7 +1268,7 @@ public class DomainVerificationService extends SystemService
}
@Override
public void clearUserSelections(@Nullable List<String> packageNames, @UserIdInt int userId) {
public void clearUserStates(@Nullable List<String> packageNames, @UserIdInt int userId) {
mEnforcer.assertInternal(mConnection.getCallingUid());
synchronized (mLock) {
if (packageNames == null) {
@@ -1545,7 +1518,7 @@ public class DomainVerificationService extends SystemService
return APPROVAL_LEVEL_NONE;
}
DomainVerificationUserState userState = pkgState.getUserSelectionState(userId);
DomainVerificationInternalUserState userState = pkgState.getUserState(userId);
if (userState != null && !userState.isLinkHandlingAllowed()) {
if (DEBUG_APPROVAL) {

View File

@@ -29,9 +29,9 @@ import android.util.TypedXmlSerializer;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
import com.android.server.pm.verify.domain.models.DomainVerificationUserState;
import org.xmlpull.v1.XmlPullParserException;
@@ -216,21 +216,22 @@ class DomainVerificationSettings {
}
}
SparseArray<DomainVerificationUserState> oldSelectionStates =
oldState.getUserSelectionStates();
SparseArray<DomainVerificationInternalUserState> oldSelectionStates =
oldState.getUserStates();
SparseArray<DomainVerificationUserState> newSelectionStates =
newState.getUserSelectionStates();
SparseArray<DomainVerificationInternalUserState> newSelectionStates =
newState.getUserStates();
DomainVerificationUserState newUserState = newSelectionStates.get(UserHandle.USER_SYSTEM);
DomainVerificationInternalUserState newUserState =
newSelectionStates.get(UserHandle.USER_SYSTEM);
if (newUserState != null) {
ArraySet<String> newEnabledHosts = newUserState.getEnabledHosts();
DomainVerificationUserState oldUserState =
DomainVerificationInternalUserState oldUserState =
oldSelectionStates.get(UserHandle.USER_SYSTEM);
boolean linkHandlingAllowed = newUserState.isLinkHandlingAllowed();
if (oldUserState == null) {
oldUserState = new DomainVerificationUserState(UserHandle.USER_SYSTEM,
oldUserState = new DomainVerificationInternalUserState(UserHandle.USER_SYSTEM,
newEnabledHosts, linkHandlingAllowed);
oldSelectionStates.put(UserHandle.USER_SYSTEM, oldUserState);
} else {

View File

@@ -24,7 +24,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.verify.domain.DomainVerificationManager;
import android.content.pm.verify.domain.DomainVerificationState;
import android.content.pm.verify.domain.DomainVerificationUserSelection;
import android.content.pm.verify.domain.DomainVerificationUserState;
import android.os.Binder;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -118,7 +118,7 @@ public class DomainVerificationShell {
case "set-app-links":
return runSetAppLinks(commandHandler);
case "set-app-links-user-selection":
return runSetAppLinksUserSelection(commandHandler);
return runSetAppLinksUserState(commandHandler);
case "set-app-links-allowed":
return runSetAppLinksAllowed(commandHandler);
}
@@ -193,7 +193,7 @@ public class DomainVerificationShell {
}
// pm set-app-links-user-selection --user <USER_ID> [--package <PACKAGE>] <ENABLED> <DOMAINS>...
private boolean runSetAppLinksUserSelection(@NonNull BasicShellCommandHandler commandHandler) {
private boolean runSetAppLinksUserState(@NonNull BasicShellCommandHandler commandHandler) {
Integer userId = null;
String packageName = null;
@@ -224,7 +224,7 @@ public class DomainVerificationShell {
return false;
}
userId = translateUserId(userId, "runSetAppLinksUserSelection");
userId = translateUserId(userId, "runSetAppLinksUserState");
String enabledString = commandHandler.getNextArgRequired();
@@ -326,7 +326,7 @@ public class DomainVerificationShell {
}
if (userId != null) {
mCallback.clearUserSelections(packageNames, userId);
mCallback.clearUserStates(packageNames, userId);
} else {
mCallback.clearDomainVerificationState(packageNames);
}
@@ -457,10 +457,10 @@ public class DomainVerificationShell {
throws PackageManager.NameNotFoundException;
/**
* @see DomainVerificationManager#getDomainVerificationUserSelection(String)
* @see DomainVerificationManager#getDomainVerificationUserState(String)
*/
@Nullable
DomainVerificationUserSelection getDomainVerificationUserSelection(
DomainVerificationUserState getDomainVerificationUserState(
@NonNull String packageName, @UserIdInt int userId)
throws PackageManager.NameNotFoundException;
@@ -486,7 +486,7 @@ public class DomainVerificationShell {
* Reset all the user selections for the given package names, or all package names if null
* is provided.
*/
void clearUserSelections(@Nullable List<String> packageNames, @UserIdInt int userId);
void clearUserStates(@Nullable List<String> packageNames, @UserIdInt int userId);
/**
* Broadcast a verification request for the given package names, or all package names if

View File

@@ -29,7 +29,7 @@ import java.util.Set;
* when a web URL Intent is sent and the application is the highest priority for that domain.
*/
@DataClass(genSetters = true, genEqualsHashCode = true, genToString = true, genBuilder = false)
public class DomainVerificationUserState {
public class DomainVerificationInternalUserState {
@UserIdInt
private final int mUserId;
@@ -43,32 +43,32 @@ public class DomainVerificationUserState {
*/
private boolean mLinkHandlingAllowed = true;
public DomainVerificationUserState(@UserIdInt int userId) {
public DomainVerificationInternalUserState(@UserIdInt int userId) {
mUserId = userId;
mEnabledHosts = new ArraySet<>();
}
public DomainVerificationUserState addHosts(@NonNull ArraySet<String> newHosts) {
public DomainVerificationInternalUserState addHosts(@NonNull ArraySet<String> newHosts) {
mEnabledHosts.addAll(newHosts);
return this;
}
public DomainVerificationUserState addHosts(@NonNull Set<String> newHosts) {
public DomainVerificationInternalUserState addHosts(@NonNull Set<String> newHosts) {
mEnabledHosts.addAll(newHosts);
return this;
}
public DomainVerificationUserState removeHost(String host) {
public DomainVerificationInternalUserState removeHost(String host) {
mEnabledHosts.remove(host);
return this;
}
public DomainVerificationUserState removeHosts(@NonNull ArraySet<String> newHosts) {
public DomainVerificationInternalUserState removeHosts(@NonNull ArraySet<String> newHosts) {
mEnabledHosts.removeAll(newHosts);
return this;
}
public DomainVerificationUserState removeHosts(@NonNull Set<String> newHosts) {
public DomainVerificationInternalUserState removeHosts(@NonNull Set<String> newHosts) {
mEnabledHosts.removeAll(newHosts);
return this;
}
@@ -81,8 +81,7 @@ public class DomainVerificationUserState {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm
// /verify/domain/models/DomainVerificationUserState.java
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationInternalUserState.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -90,7 +89,7 @@ public class DomainVerificationUserState {
/**
* Creates a new DomainVerificationUserState.
* Creates a new DomainVerificationInternalUserState.
*
* @param enabledHosts
* List of domains which have been enabled by the user. *
@@ -98,7 +97,7 @@ public class DomainVerificationUserState {
* Whether to allow this package to automatically open links by auto verification.
*/
@DataClass.Generated.Member
public DomainVerificationUserState(
public DomainVerificationInternalUserState(
@UserIdInt int userId,
@NonNull ArraySet<String> enabledHosts,
boolean linkHandlingAllowed) {
@@ -138,7 +137,7 @@ public class DomainVerificationUserState {
* Whether to allow this package to automatically open links by auto verification.
*/
@DataClass.Generated.Member
public @NonNull DomainVerificationUserState setLinkHandlingAllowed( boolean value) {
public @NonNull DomainVerificationInternalUserState setLinkHandlingAllowed( boolean value) {
mLinkHandlingAllowed = value;
return this;
}
@@ -149,7 +148,7 @@ public class DomainVerificationUserState {
// You can override field toString logic by defining methods like:
// String fieldNameToString() { ... }
return "DomainVerificationUserState { " +
return "DomainVerificationInternalUserState { " +
"userId = " + mUserId + ", " +
"enabledHosts = " + mEnabledHosts + ", " +
"linkHandlingAllowed = " + mLinkHandlingAllowed +
@@ -160,13 +159,13 @@ public class DomainVerificationUserState {
@DataClass.Generated.Member
public boolean equals(@android.annotation.Nullable Object o) {
// You can override field equality logic by defining either of the methods like:
// boolean fieldNameEquals(DomainVerificationUserState other) { ... }
// boolean fieldNameEquals(DomainVerificationInternalUserState other) { ... }
// boolean fieldNameEquals(FieldType otherValue) { ... }
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@SuppressWarnings("unchecked")
DomainVerificationUserState that = (DomainVerificationUserState) o;
DomainVerificationInternalUserState that = (DomainVerificationInternalUserState) o;
//noinspection PointlessBooleanExpression
return true
&& mUserId == that.mUserId
@@ -188,10 +187,10 @@ public class DomainVerificationUserState {
}
@DataClass.Generated(
time = 1612894390039L,
time = 1614714563905L,
codegenVersion = "1.0.22",
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)")
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationInternalUserState.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.DomainVerificationInternalUserState addHosts(android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState addHosts(java.util.Set<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState removeHost(java.lang.String)\npublic com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState removeHosts(android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState removeHosts(java.util.Set<java.lang.String>)\nclass DomainVerificationInternalUserState 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

@@ -19,7 +19,6 @@ package com.android.server.pm.verify.domain.models;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.verify.domain.DomainVerificationManager;
import android.content.pm.verify.domain.DomainVerificationState;
import android.util.ArrayMap;
import android.util.SparseArray;
@@ -44,9 +43,9 @@ public class DomainVerificationPkgState {
/**
* Whether or not the package declares any autoVerify domains. This is separate from an empty
* check on the map itself, because an empty map means no response recorded, not necessarily no
* domains declared. When this is false, {@link #mStateMap} will be empty, but
* {@link #mUserSelectionStates} may contain any domains the user has explicitly chosen to
* check on the map itself, because an empty map means no response recorded, not necessarily
* no domains declared. When this is false, {@link #mStateMap} will be empty, but
* {@link #mUserStates} may contain any domains the user has explicitly chosen to
* allow this package to open, which may or may not be marked autoVerify.
*/
private final boolean mHasAutoVerifyDomains;
@@ -62,7 +61,7 @@ public class DomainVerificationPkgState {
private final ArrayMap<String, Integer> mStateMap;
@NonNull
private final SparseArray<DomainVerificationUserState> mUserSelectionStates;
private final SparseArray<DomainVerificationInternalUserState> mUserStates;
public DomainVerificationPkgState(@NonNull String packageName, @NonNull UUID id,
boolean hasAutoVerifyDomains) {
@@ -70,16 +69,17 @@ public class DomainVerificationPkgState {
}
@Nullable
public DomainVerificationUserState getUserSelectionState(@UserIdInt int userId) {
return mUserSelectionStates.get(userId);
public DomainVerificationInternalUserState getUserState(@UserIdInt int userId) {
return mUserStates.get(userId);
}
@Nullable
public DomainVerificationUserState getOrCreateUserSelectionState(@UserIdInt int userId) {
DomainVerificationUserState userState = mUserSelectionStates.get(userId);
public DomainVerificationInternalUserState getOrCreateUserState(
@UserIdInt int userId) {
DomainVerificationInternalUserState userState = mUserStates.get(userId);
if (userState == null) {
userState = new DomainVerificationUserState(userId);
mUserSelectionStates.put(userId, userState);
userState = new DomainVerificationInternalUserState(userId);
mUserStates.put(userId, userState);
}
return userState;
}
@@ -89,20 +89,20 @@ public class DomainVerificationPkgState {
}
public void removeUser(@UserIdInt int userId) {
mUserSelectionStates.remove(userId);
mUserStates.remove(userId);
}
public void removeAllUsers() {
mUserSelectionStates.clear();
mUserStates.clear();
}
private int userSelectionStatesHashCode() {
return mUserSelectionStates.contentHashCode();
private int userStatesHashCode() {
return mUserStates.contentHashCode();
}
private boolean userSelectionStatesEquals(
@NonNull SparseArray<DomainVerificationUserState> other) {
return mUserSelectionStates.contentEquals(other);
private boolean userStatesEquals(
@NonNull SparseArray<DomainVerificationInternalUserState> other) {
return mUserStates.contentEquals(other);
}
@@ -113,7 +113,7 @@ public class DomainVerificationPkgState {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/domain/verify/models/DomainVerificationPkgState.java
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -123,9 +123,15 @@ public class DomainVerificationPkgState {
/**
* Creates a new DomainVerificationPkgState.
*
* @param hasAutoVerifyDomains
* Whether or not the package declares any autoVerify domains. This is separate from an empty
* check on the map itself, because an empty map means no response recorded, not necessarily
* no domains declared. When this is false, {@link #mStateMap} will be empty, but
* {@link #mUserStates} may contain any domains the user has explicitly chosen to
* allow this package to open, which may or may not be marked autoVerify.
* @param stateMap
* Map of domains to state integers. Only domains that are not set to the default value of
* {@link DomainVerificationManager#STATE_NO_RESPONSE} are included.
* {@link DomainVerificationState#STATE_NO_RESPONSE} are included.
*
* TODO(b/159952358): Hide the state map entirely from the caller, to allow optimizations,
* such as storing no state when the package is marked as a linked app in SystemConfig.
@@ -136,7 +142,7 @@ public class DomainVerificationPkgState {
@NonNull UUID id,
boolean hasAutoVerifyDomains,
@NonNull ArrayMap<String,Integer> stateMap,
@NonNull SparseArray<DomainVerificationUserState> userSelectionStates) {
@NonNull SparseArray<DomainVerificationInternalUserState> userStates) {
this.mPackageName = packageName;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mPackageName);
@@ -147,9 +153,9 @@ public class DomainVerificationPkgState {
this.mStateMap = stateMap;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mStateMap);
this.mUserSelectionStates = userSelectionStates;
this.mUserStates = userStates;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mUserSelectionStates);
NonNull.class, null, mUserStates);
// onConstructed(); // You can define this method to get a callback
}
@@ -164,6 +170,13 @@ public class DomainVerificationPkgState {
return mId;
}
/**
* Whether or not the package declares any autoVerify domains. This is separate from an empty
* check on the map itself, because an empty map means no response recorded, not necessarily
* no domains declared. When this is false, {@link #mStateMap} will be empty, but
* {@link #mUserStates} may contain any domains the user has explicitly chosen to
* allow this package to open, which may or may not be marked autoVerify.
*/
@DataClass.Generated.Member
public boolean isHasAutoVerifyDomains() {
return mHasAutoVerifyDomains;
@@ -171,7 +184,7 @@ public class DomainVerificationPkgState {
/**
* Map of domains to state integers. Only domains that are not set to the default value of
* {@link DomainVerificationManager#STATE_NO_RESPONSE} are included.
* {@link DomainVerificationState#STATE_NO_RESPONSE} are included.
*
* TODO(b/159952358): Hide the state map entirely from the caller, to allow optimizations,
* such as storing no state when the package is marked as a linked app in SystemConfig.
@@ -182,8 +195,8 @@ public class DomainVerificationPkgState {
}
@DataClass.Generated.Member
public @NonNull SparseArray<DomainVerificationUserState> getUserSelectionStates() {
return mUserSelectionStates;
public @NonNull SparseArray<DomainVerificationInternalUserState> getUserStates() {
return mUserStates;
}
@Override
@@ -197,7 +210,7 @@ public class DomainVerificationPkgState {
"id = " + mId + ", " +
"hasAutoVerifyDomains = " + mHasAutoVerifyDomains + ", " +
"stateMap = " + mStateMap + ", " +
"userSelectionStates = " + mUserSelectionStates +
"userStates = " + mUserStates +
" }";
}
@@ -218,7 +231,7 @@ public class DomainVerificationPkgState {
&& Objects.equals(mId, that.mId)
&& mHasAutoVerifyDomains == that.mHasAutoVerifyDomains
&& Objects.equals(mStateMap, that.mStateMap)
&& userSelectionStatesEquals(that.mUserSelectionStates);
&& userStatesEquals(that.mUserStates);
}
@Override
@@ -232,15 +245,15 @@ public class DomainVerificationPkgState {
_hash = 31 * _hash + Objects.hashCode(mId);
_hash = 31 * _hash + Boolean.hashCode(mHasAutoVerifyDomains);
_hash = 31 * _hash + Objects.hashCode(mStateMap);
_hash = 31 * _hash + userSelectionStatesHashCode();
_hash = 31 * _hash + userStatesHashCode();
return _hash;
}
@DataClass.Generated(
time = 1608234185474L,
time = 1614818362549L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/domain/verify/models/DomainVerificationPkgState.java",
inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate @android.annotation.NonNull java.util.UUID mId\nprivate final boolean mHasAutoVerifyDomains\nprivate final @android.annotation.NonNull android.util.ArrayMap<java.lang.String,java.lang.Integer> mStateMap\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.verify.domain.models.DomainVerificationUserState> mUserSelectionStates\npublic @android.annotation.Nullable com.android.server.pm.verify.domain.models.DomainVerificationUserState getUserSelectionState(int)\npublic @android.annotation.Nullable com.android.server.pm.verify.domain.models.DomainVerificationUserState getOrCreateUserSelectionState(int)\npublic void setId(java.util.UUID)\npublic void removeUser(int)\npublic void removeAllUsers()\nprivate int userSelectionStatesHashCode()\nprivate boolean userSelectionStatesEquals(android.util.SparseArray<com.android.server.pm.verify.domain.models.DomainVerificationUserState>)\nclass DomainVerificationPkgState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java",
inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate @android.annotation.NonNull java.util.UUID mId\nprivate final boolean mHasAutoVerifyDomains\nprivate final @android.annotation.NonNull android.util.ArrayMap<java.lang.String,java.lang.Integer> mStateMap\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState> mUserStates\npublic @android.annotation.Nullable com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState getUserState(int)\npublic @android.annotation.Nullable com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState getOrCreateUserState(int)\npublic void setId(java.util.UUID)\npublic void removeUser(int)\npublic void removeAllUsers()\nprivate int userStatesHashCode()\nprivate boolean userStatesEquals(android.util.SparseArray<com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState>)\nclass DomainVerificationPkgState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}

View File

@@ -19,7 +19,7 @@ package com.android.server.pm.test.verify.domain
import android.content.pm.verify.domain.DomainSet
import android.content.pm.verify.domain.DomainVerificationInfo
import android.content.pm.verify.domain.DomainVerificationRequest
import android.content.pm.verify.domain.DomainVerificationUserSelection
import android.content.pm.verify.domain.DomainVerificationUserState
import android.os.Parcel
import android.os.Parcelable
import android.os.UserHandle
@@ -28,7 +28,6 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import java.util.UUID
import kotlin.random.Random
@RunWith(Parameterized::class)
class DomainVerificationCoreApiTest {
@@ -92,9 +91,9 @@ class DomainVerificationCoreApiTest {
}
),
Parameter(
testName = "DomainVerificationUserSelection",
testName = "DomainVerificationUserState",
initial = {
DomainVerificationUserSelection(
DomainVerificationUserState(
UUID.fromString("703f6d34-6241-4cfd-8176-2e1d23355811"),
"com.test.pkg",
UserHandle.of(10),
@@ -103,22 +102,22 @@ class DomainVerificationCoreApiTest {
.associate { it.value to (it.index % 3) }
)
},
unparcel = { DomainVerificationUserSelection.CREATOR.createFromParcel(it) },
unparcel = { DomainVerificationUserState.CREATOR.createFromParcel(it) },
assertion = { first, second ->
assertAll<DomainVerificationUserSelection, UUID>(first, second,
assertAll<DomainVerificationUserState, UUID>(first, second,
{ it.identifier }, { it.component1() }, IS_EQUAL_TO
)
assertAll<DomainVerificationUserSelection, String>(first, second,
assertAll<DomainVerificationUserState, String>(first, second,
{ it.packageName }, { it.component2() }, IS_EQUAL_TO
)
assertAll<DomainVerificationUserSelection, UserHandle>(first, second,
assertAll<DomainVerificationUserState, UserHandle>(first, second,
{ it.user }, { it.component3() }, IS_EQUAL_TO
)
assertAll<DomainVerificationUserSelection, Boolean>(
assertAll<DomainVerificationUserState, Boolean>(
first, second, { it.isLinkHandlingAllowed },
{ it.component4() }, IS_EQUAL_TO
)
assertAll<DomainVerificationUserSelection, Map<String, Int>>(
assertAll<DomainVerificationUserState, Map<String, Int>>(
first, second, { it.hostToStateMap },
{ it.component5() }, IS_MAP_EQUAL_TO
)

View File

@@ -154,6 +154,15 @@ class DomainVerificationEnforcerTest {
enforcer(Type.VERIFIER, "approvedVerifier") {
assertApprovedVerifier(it.callingUid, it.proxy)
},
enforcer(
Type.SELECTION_QUERENT,
"approvedUserStateQuerent"
) {
assertApprovedUserStateQuerent(
it.callingUid, it.callingUserId,
it.targetPackageName, it.userId
)
},
enforcer(
Type.SELECTOR,
"approvedUserSelector"
@@ -170,7 +179,7 @@ class DomainVerificationEnforcerTest {
ArraySet(setOf("example.com"))
)
},
service(Type.INTERNAL, "setUserSelectionInternal") {
service(Type.INTERNAL, "setUserStateInternal") {
setDomainVerificationUserSelectionInternal(
it.userId,
it.targetPackageName,
@@ -184,11 +193,11 @@ class DomainVerificationEnforcerTest {
service(Type.INTERNAL, "clearState") {
clearDomainVerificationState(listOf(it.targetPackageName))
},
service(Type.INTERNAL, "clearUserSelections") {
clearUserSelections(listOf(it.targetPackageName), it.userId)
service(Type.INTERNAL, "clearUserStates") {
clearUserStates(listOf(it.targetPackageName), it.userId)
},
service(Type.VERIFIER, "getPackageNames") {
validVerificationPackageNames
service(Type.VERIFIER, "queryValidPackageNames") {
queryValidVerificationPackageNames()
},
service(Type.QUERENT, "getInfo") {
getDomainVerificationInfo(it.targetPackageName)
@@ -208,26 +217,13 @@ class DomainVerificationEnforcerTest {
DomainVerificationManager.STATE_SUCCESS
)
},
service(Type.SELECTOR, "setLinkHandlingAllowed") {
setDomainVerificationLinkHandlingAllowed(it.targetPackageName, true)
},
service(Type.SELECTOR_USER, "setLinkHandlingAllowedUserId") {
setDomainVerificationLinkHandlingAllowed(it.targetPackageName, true, it.userId)
},
service(Type.SELECTOR, "getUserSelection") {
getDomainVerificationUserSelection(it.targetPackageName)
service(Type.SELECTION_QUERENT, "getUserStateUserId") {
getDomainVerificationUserState(it.targetPackageName, it.userId)
},
service(Type.SELECTOR_USER, "getUserSelectionUserId") {
getDomainVerificationUserSelection(it.targetPackageName, it.userId)
},
service(Type.SELECTOR, "setUserSelection") {
setDomainVerificationUserSelection(
it.targetDomainSetId,
setOf("example.com"),
true
)
},
service(Type.SELECTOR_USER, "setUserSelectionUserId") {
service(Type.SELECTOR_USER, "setUserStateUserId") {
setDomainVerificationUserSelection(
it.targetDomainSetId,
setOf("example.com"),
@@ -244,10 +240,6 @@ class DomainVerificationEnforcerTest {
service(Type.LEGACY_QUERENT, "getLegacyUserState") {
getLegacyState(it.targetPackageName, it.userId)
},
service(Type.OWNER_QUERENT, "getOwnersForDomain") {
// Re-use package name, since the result itself isn't relevant
getOwnersForDomain(it.targetPackageName)
},
service(Type.OWNER_QUERENT_USER, "getOwnersForDomainUserId") {
// Re-use package name, since the result itself isn't relevant
getOwnersForDomain(it.targetPackageName, it.userId)
@@ -362,6 +354,7 @@ class DomainVerificationEnforcerTest {
Type.INTERNAL -> internal()
Type.QUERENT -> approvedQuerent()
Type.VERIFIER -> approvedVerifier()
Type.SELECTION_QUERENT -> approvedUserStateQuerent(verifyCrossUser = true)
Type.SELECTOR -> approvedUserSelector(verifyCrossUser = false)
Type.SELECTOR_USER -> approvedUserSelector(verifyCrossUser = true)
Type.LEGACY_QUERENT -> legacyQuerent()
@@ -371,7 +364,7 @@ class DomainVerificationEnforcerTest {
}.run { /*exhaust*/ }
}
fun internal() {
private fun internal() {
val context: Context = mockThrowOnUnmocked()
val target = params.construct(context)
@@ -385,13 +378,13 @@ class DomainVerificationEnforcerTest {
}
}
fun approvedQuerent() {
val allowUserSelection = AtomicBoolean(false)
private fun approvedQuerent() {
val allowUserState = AtomicBoolean(false)
val allowPreferredApps = AtomicBoolean(false)
val allowQueryAll = AtomicBoolean(false)
val context: Context = mockThrowOnUnmocked {
initPermission(
allowUserSelection,
allowUserState,
android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
)
initPermission(
@@ -418,7 +411,7 @@ class DomainVerificationEnforcerTest {
assertFails { runMethod(target, NON_VERIFIER_UID) }
allowUserSelection.set(true)
allowUserState.set(true)
assertFails { runMethod(target, NON_VERIFIER_UID) }
@@ -427,7 +420,7 @@ class DomainVerificationEnforcerTest {
runMethod(target, NON_VERIFIER_UID)
}
fun approvedVerifier() {
private fun approvedVerifier() {
val allowDomainVerificationAgent = AtomicBoolean(false)
val allowIntentVerificationAgent = AtomicBoolean(false)
val allowQueryAll = AtomicBoolean(false)
@@ -469,12 +462,61 @@ class DomainVerificationEnforcerTest {
assertFails { runMethod(target, NON_VERIFIER_UID) }
}
fun approvedUserSelector(verifyCrossUser: Boolean) {
val allowUserSelection = AtomicBoolean(false)
private fun approvedUserStateQuerent(verifyCrossUser: Boolean) {
val allowInteractAcrossUsers = AtomicBoolean(false)
val context: Context = mockThrowOnUnmocked {
initPermission(
allowUserSelection,
allowInteractAcrossUsers,
android.Manifest.permission.INTERACT_ACROSS_USERS
)
}
val target = params.construct(context)
fun runTestCases(callingUserId: Int, targetUserId: Int, throws: Boolean) {
// User selector makes no distinction by UID
val allUids = INTERNAL_UIDS + VERIFIER_UID + NON_VERIFIER_UID
if (throws) {
allUids.forEach {
assertFails {
runMethod(target, it, visible = true, callingUserId, targetUserId)
}
}
} else {
allUids.forEach {
runMethod(target, it, visible = true, callingUserId, targetUserId)
}
}
// User selector doesn't use QUERY_ALL, so the invisible package should always fail
allUids.forEach {
assertFails {
runMethod(target, it, visible = false, callingUserId, targetUserId)
}
}
}
val callingUserId = 0
val notCallingUserId = 1
runTestCases(callingUserId, callingUserId, throws = false)
if (verifyCrossUser) {
runTestCases(callingUserId, notCallingUserId, throws = true)
}
allowInteractAcrossUsers.set(true)
runTestCases(callingUserId, callingUserId, throws = false)
if (verifyCrossUser) {
runTestCases(callingUserId, notCallingUserId, throws = false)
}
}
private fun approvedUserSelector(verifyCrossUser: Boolean) {
val allowUserState = AtomicBoolean(false)
val allowInteractAcrossUsers = AtomicBoolean(false)
val context: Context = mockThrowOnUnmocked {
initPermission(
allowUserState,
android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
)
initPermission(
@@ -515,7 +557,7 @@ class DomainVerificationEnforcerTest {
runTestCases(callingUserId, notCallingUserId, throws = true)
}
allowUserSelection.set(true)
allowUserState.set(true)
runTestCases(callingUserId, callingUserId, throws = false)
if (verifyCrossUser) {
@@ -641,7 +683,7 @@ class DomainVerificationEnforcerTest {
private fun ownerQuerent(verifyCrossUser: Boolean) {
val allowQueryAll = AtomicBoolean(false)
val allowUserSelection = AtomicBoolean(false)
val allowUserState = AtomicBoolean(false)
val allowInteractAcrossUsers = AtomicBoolean(false)
val context: Context = mockThrowOnUnmocked {
initPermission(
@@ -649,7 +691,7 @@ class DomainVerificationEnforcerTest {
android.Manifest.permission.QUERY_ALL_PACKAGES
)
initPermission(
allowUserSelection,
allowUserState,
android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
)
initPermission(
@@ -690,7 +732,7 @@ class DomainVerificationEnforcerTest {
runTestCases(callingUserId, notCallingUserId, throws = true)
}
allowUserSelection.set(true)
allowUserState.set(true)
runTestCases(callingUserId, callingUserId, throws = false)
if (verifyCrossUser) {
@@ -769,6 +811,9 @@ class DomainVerificationEnforcerTest {
// INTERNAL || domain verification agent
VERIFIER,
// No permissions, allows all apps to view domain state for visible packages
SELECTION_QUERENT,
// Holding the user setting permission
SELECTOR,

View File

@@ -18,7 +18,7 @@ package com.android.server.pm.test.verify.domain
import android.content.pm.verify.domain.DomainVerificationRequest
import android.content.pm.verify.domain.DomainVerificationInfo
import android.content.pm.verify.domain.DomainVerificationUserSelection
import android.content.pm.verify.domain.DomainVerificationUserState
import com.android.server.pm.verify.domain.DomainVerificationPersistence
operator fun <F> android.util.Pair<F, *>.component1() = first
@@ -30,11 +30,11 @@ operator fun DomainVerificationInfo.component1() = identifier
operator fun DomainVerificationInfo.component2() = packageName
operator fun DomainVerificationInfo.component3() = hostToStateMap
operator fun DomainVerificationUserSelection.component1() = identifier
operator fun DomainVerificationUserSelection.component2() = packageName
operator fun DomainVerificationUserSelection.component3() = user
operator fun DomainVerificationUserSelection.component4() = isLinkHandlingAllowed
operator fun DomainVerificationUserSelection.component5() = hostToStateMap
operator fun DomainVerificationUserState.component1() = identifier
operator fun DomainVerificationUserState.component2() = packageName
operator fun DomainVerificationUserState.component3() = user
operator fun DomainVerificationUserState.component4() = isLinkHandlingAllowed
operator fun DomainVerificationUserState.component5() = hostToStateMap
operator fun DomainVerificationPersistence.ReadResult.component1() = active
operator fun DomainVerificationPersistence.ReadResult.component2() = restored

View File

@@ -22,9 +22,9 @@ import android.util.TypedXmlPullParser
import android.util.TypedXmlSerializer
import android.util.Xml
import com.android.server.pm.verify.domain.DomainVerificationPersistence
import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState
import com.android.server.pm.verify.domain.models.DomainVerificationStateMap
import com.android.server.pm.verify.domain.models.DomainVerificationUserState
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.Rule
@@ -102,14 +102,14 @@ class DomainVerificationPersistenceTest {
// A domain without a written state falls back to default
stateMap["missing-state.com"] = DomainVerificationManager.STATE_NO_RESPONSE
userSelectionStates[1] = DomainVerificationUserState(1).apply {
userStates[1] = DomainVerificationInternalUserState(1).apply {
addHosts(setOf("example-user1.com", "example-user1.org"))
isLinkHandlingAllowed = true
}
}
val stateOne = mockEmptyPkgState(1).apply {
// It's valid to have a user selection without any autoVerify domains
userSelectionStates[1] = DomainVerificationUserState(1).apply {
userStates[1] = DomainVerificationInternalUserState(1).apply {
addHosts(setOf("example-user1.com", "example-user1.org"))
isLinkHandlingAllowed = false
}
@@ -214,7 +214,7 @@ class DomainVerificationPersistenceTest {
private fun mockPkgState(id: Int) = mockEmptyPkgState(id).apply {
stateMap["$packageName.com"] = id
userSelectionStates[id] = DomainVerificationUserState(id).apply {
userStates[id] = DomainVerificationInternalUserState(id).apply {
addHosts(setOf("$packageName-user.com"))
isLinkHandlingAllowed = true
}

View File

@@ -122,8 +122,8 @@ class DomainVerificationSettingsMutationTest {
service("clearState") {
clearDomainVerificationState(listOf(TEST_PKG))
},
service("clearUserSelections") {
clearUserSelections(listOf(TEST_PKG), TEST_USER_ID)
service("clearUserStates") {
clearUserStates(listOf(TEST_PKG), TEST_USER_ID)
},
service("setStatus") {
setDomainVerificationStatus(
@@ -147,19 +147,13 @@ class DomainVerificationSettingsMutationTest {
DomainVerificationManager.STATE_SUCCESS
)
},
service("setLinkHandlingAllowed") {
setDomainVerificationLinkHandlingAllowed(TEST_PKG, true)
},
service("setLinkHandlingAllowedUserId") {
setDomainVerificationLinkHandlingAllowed(TEST_PKG, true, TEST_USER_ID)
},
service("setLinkHandlingAllowedInternal") {
setDomainVerificationLinkHandlingAllowedInternal(TEST_PKG, true, TEST_USER_ID)
},
service("setUserSelection") {
setDomainVerificationUserSelection(TEST_UUID, setOf("example.com"), true)
},
service("setUserSelectionUserId") {
service("setUserStateUserId") {
setDomainVerificationUserSelection(
TEST_UUID,
setOf("example.com"),
@@ -167,7 +161,7 @@ class DomainVerificationSettingsMutationTest {
TEST_USER_ID
)
},
service("setUserSelectionInternal") {
service("setUserStateInternal") {
setDomainVerificationUserSelectionInternal(
TEST_USER_ID,
TEST_PKG,

View File

@@ -16,18 +16,16 @@
package com.android.server.pm.test.verify.domain
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.parsing.component.ParsedActivity
import android.content.pm.parsing.component.ParsedIntentInfo
import android.content.pm.verify.domain.DomainVerificationManager
import android.content.pm.verify.domain.DomainVerificationUserSelection
import android.content.pm.verify.domain.DomainVerificationUserState
import android.os.Build
import android.os.PatternMatcher
import android.os.Process
import android.util.ArraySet
import androidx.test.InstrumentationRegistry
import com.android.server.pm.PackageSetting
import com.android.server.pm.parsing.pkg.AndroidPackage
import com.android.server.pm.verify.domain.DomainVerificationService
@@ -41,7 +39,7 @@ import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString
import java.util.UUID
class DomainVerificationManagerUserSelectionOverrideTest {
class DomainVerificationUserStateOverrideTest {
companion object {
private const val PKG_ONE = "com.test.one"
@@ -50,17 +48,19 @@ class DomainVerificationManagerUserSelectionOverrideTest {
private val UUID_TWO = UUID.fromString("a3389c16-7f9f-4e86-85e3-500d1249c74c")
private val DOMAIN_ONE =
DomainVerificationManagerUserSelectionOverrideTest::class.java.packageName
DomainVerificationUserStateOverrideTest::class.java.packageName
private const val STATE_NONE = DomainVerificationUserSelection.DOMAIN_STATE_NONE
private const val STATE_SELECTED = DomainVerificationUserSelection.DOMAIN_STATE_SELECTED
private const val STATE_VERIFIED = DomainVerificationUserSelection.DOMAIN_STATE_VERIFIED
private const val STATE_NONE = DomainVerificationUserState.DOMAIN_STATE_NONE
private const val STATE_SELECTED = DomainVerificationUserState.DOMAIN_STATE_SELECTED
private const val STATE_VERIFIED = DomainVerificationUserState.DOMAIN_STATE_VERIFIED
private const val USER_ID = 0
}
private val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE)
private val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO)
fun makeManager(): DomainVerificationManager =
fun makeService() =
DomainVerificationService(mockThrowOnUnmocked {
// Assume the test has every permission necessary
whenever(enforcePermission(anyString(), anyInt(), anyInt(), anyString()))
@@ -88,7 +88,7 @@ class DomainVerificationManagerUserSelectionOverrideTest {
addPackage(pkg2)
// Starting state for all tests is to have domain 1 enabled for the first package
setDomainVerificationUserSelection(UUID_ONE, setOf(DOMAIN_ONE), true)
setDomainVerificationUserSelection(UUID_ONE, setOf(DOMAIN_ONE), true, USER_ID)
assertThat(stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_SELECTED)
}
@@ -138,37 +138,37 @@ class DomainVerificationManagerUserSelectionOverrideTest {
@Test
fun anotherPackageTakeoverSuccess() {
val manager = makeManager()
val service = makeService()
// Attempt override by package 2
manager.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true)
service.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true, USER_ID)
// 1 loses approval
assertThat(manager.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_NONE)
assertThat(service.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_NONE)
// 2 gains approval
assertThat(manager.stateFor(PKG_TWO, DOMAIN_ONE)).isEqualTo(STATE_SELECTED)
assertThat(service.stateFor(PKG_TWO, DOMAIN_ONE)).isEqualTo(STATE_SELECTED)
// 2 is the only owner
assertThat(manager.getOwnersForDomain(DOMAIN_ONE).map { it.packageName })
assertThat(service.getOwnersForDomain(DOMAIN_ONE, USER_ID).map { it.packageName })
.containsExactly(PKG_TWO)
}
@Test(expected = IllegalArgumentException::class)
fun anotherPackageTakeoverFailure() {
val manager = makeManager()
val service = makeService()
// Verify 1 to give it a higher approval level
manager.setDomainVerificationStatus(UUID_ONE, setOf(DOMAIN_ONE),
service.setDomainVerificationStatus(UUID_ONE, setOf(DOMAIN_ONE),
DomainVerificationManager.STATE_SUCCESS)
assertThat(manager.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_VERIFIED)
assertThat(manager.getOwnersForDomain(DOMAIN_ONE).map { it.packageName })
assertThat(service.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_VERIFIED)
assertThat(service.getOwnersForDomain(DOMAIN_ONE, USER_ID).map { it.packageName })
.containsExactly(PKG_ONE)
// Attempt override by package 2
manager.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true)
service.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true, USER_ID)
}
private fun DomainVerificationManager.stateFor(pkgName: String, host: String) =
getDomainVerificationUserSelection(pkgName)!!.hostToStateMap[host]
private fun DomainVerificationService.stateFor(pkgName: String, host: String) =
getDomainVerificationUserState(pkgName, USER_ID)!!.hostToStateMap[host]
}