Merge "Send domains through Parcel#writeBlob to avoid size limit" into sc-dev

This commit is contained in:
Winson Chiu
2021-02-26 18:11:03 +00:00
committed by Android (Google) Code Review
11 changed files with 581 additions and 144 deletions

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2021 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;
parcelable DomainSet;

View File

@@ -0,0 +1,160 @@
/*
* Copyright (C) 2021 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.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.DataClass;
import java.util.Set;
/**
* Wraps an input set of domains from the client process, to be sent to the server. Handles cases
* where the data size is too large by writing data using {@link Parcel#writeBlob(byte[])}.
*
* @hide
*/
@DataClass(genParcelable = true, genAidl = true, genEqualsHashCode = true)
public class DomainSet implements Parcelable {
@NonNull
private final Set<String> mDomains;
private void parcelDomains(@NonNull Parcel dest, @SuppressWarnings("unused") int flags) {
DomainVerificationUtils.writeHostSet(dest, mDomains);
}
private Set<String> unparcelDomains(@NonNull Parcel in) {
return DomainVerificationUtils.readHostSet(in);
}
// Code below generated by codegen v1.0.22.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
// /DomainSet.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
@DataClass.Generated.Member
public DomainSet(
@NonNull Set<String> domains) {
this.mDomains = domains;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mDomains);
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public @NonNull Set<String> getDomains() {
return mDomains;
}
@Override
@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(DomainSet other) { ... }
// boolean fieldNameEquals(FieldType otherValue) { ... }
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@SuppressWarnings("unchecked")
DomainSet that = (DomainSet) o;
//noinspection PointlessBooleanExpression
return true
&& java.util.Objects.equals(mDomains, that.mDomains);
}
@Override
@DataClass.Generated.Member
public int hashCode() {
// You can override field hashCode logic by defining methods like:
// int fieldNameHashCode() { ... }
int _hash = 1;
_hash = 31 * _hash + java.util.Objects.hashCode(mDomains);
return _hash;
}
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
parcelDomains(dest, flags);
}
@Override
@DataClass.Generated.Member
public int describeContents() { return 0; }
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
protected DomainSet(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
Set<String> domains = unparcelDomains(in);
this.mDomains = domains;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mDomains);
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<DomainSet> CREATOR
= new Parcelable.Creator<DomainSet>() {
@Override
public DomainSet[] newArray(int size) {
return new DomainSet[size];
}
@Override
public DomainSet createFromParcel(@NonNull Parcel in) {
return new DomainSet(in);
}
};
@DataClass.Generated(
time = 1613169242020L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainSet.java",
inputSignatures = "private final @android.annotation.NonNull java.util.Set<java.lang.String> mDomains\nprivate void parcelDomains(android.os.Parcel,int)\nprivate java.util.Set<java.lang.String> unparcelDomains(android.os.Parcel)\nclass DomainSet extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
//@formatter:on
// End of generated code
}

View File

@@ -19,7 +19,9 @@ package android.content.pm.verify.domain;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.pm.PackageManager;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
@@ -34,12 +36,12 @@ import java.util.UUID;
* against the digital asset links response from the server hosting that domain.
* <p>
* These values for each domain can be modified through
* {@link DomainVerificationManager#setDomainVerificationStatus(UUID, Set, int)}.
* {@link DomainVerificationManager#setDomainVerificationStatus(UUID,
* Set, int)}.
*
* @hide
*/
@SystemApi
@SuppressWarnings("DefaultAnnotationParam")
@DataClass(genAidl = true, genHiddenConstructor = true, genParcelable = true, genToString = true,
genEqualsHashCode = true)
public final class DomainVerificationInfo implements Parcelable {
@@ -71,22 +73,30 @@ public final class DomainVerificationInfo implements Parcelable {
private final String mPackageName;
/**
* Map of host names to their current state. State is an integer, which defaults to
* {@link DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the
* domain verification agent (the intended consumer of this API), which can be equal
* to {@link DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or
* greater than {@link DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for
* any unsuccessful response.
* Map of host names to their current state. State is an integer, which defaults to {@link
* DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the domain
* verification agent (the intended consumer of this API), which can be equal to {@link
* DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or greater than {@link
* DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for any unsuccessful response.
* <p>
* Any value non-inclusive between those 2 values are reserved for use by the system.
* The domain verification agent may be able to act on these reserved values, and this
* ability can be queried using {@link DomainVerificationManager#isStateModifiable(int)}.
* It is expected that the agent attempt to verify all domains that it can modify the
* state of, even if it does not understand the meaning of those values.
* Any value non-inclusive between those 2 values are reserved for use by the system. The domain
* verification agent may be able to act on these reserved values, and this ability can be
* queried using {@link DomainVerificationManager#isStateModifiable(int)}. It is expected that
* the agent attempt to verify all domains that it can modify the state of, even if it does not
* understand the meaning of those values.
*/
@NonNull
private final Map<String, Integer> mHostToStateMap;
private void parcelHostToStateMap(Parcel dest, @SuppressWarnings("unused") int flags) {
DomainVerificationUtils.writeHostMap(dest, mHostToStateMap);
}
private Map<String, Integer> unparcelHostToStateMap(Parcel in) {
return DomainVerificationUtils.readHostMap(in, new ArrayMap<>(),
DomainVerificationUserSelection.class.getClassLoader());
}
// Code below generated by codegen v1.0.22.
@@ -95,7 +105,8 @@ 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
@@ -123,18 +134,17 @@ public final class DomainVerificationInfo implements Parcelable {
* @param packageName
* The package name that this data corresponds to.
* @param hostToStateMap
* Map of host names to their current state. State is an integer, which defaults to
* {@link DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the
* domain verification agent (the intended consumer of this API), which can be equal
* to {@link DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or
* greater than {@link DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for
* any unsuccessful response.
* Map of host names to their current state. State is an integer, which defaults to {@link
* DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the domain
* verification agent (the intended consumer of this API), which can be equal to {@link
* DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or greater than {@link
* DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for any unsuccessful response.
* <p>
* Any value non-inclusive between those 2 values are reserved for use by the system.
* The domain verification agent may be able to act on these reserved values, and this
* ability can be queried using {@link DomainVerificationManager#isStateModifiable(int)}.
* It is expected that the agent attempt to verify all domains that it can modify the
* state of, even if it does not understand the meaning of those values.
* Any value non-inclusive between those 2 values are reserved for use by the system. The domain
* verification agent may be able to act on these reserved values, and this ability can be
* queried using {@link DomainVerificationManager#isStateModifiable(int)}. It is expected that
* the agent attempt to verify all domains that it can modify the state of, even if it does not
* understand the meaning of those values.
* @hide
*/
@DataClass.Generated.Member
@@ -185,18 +195,17 @@ public final class DomainVerificationInfo implements Parcelable {
}
/**
* Map of host names to their current state. State is an integer, which defaults to
* {@link DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the
* domain verification agent (the intended consumer of this API), which can be equal
* to {@link DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or
* greater than {@link DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for
* any unsuccessful response.
* Map of host names to their current state. State is an integer, which defaults to {@link
* DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the domain
* verification agent (the intended consumer of this API), which can be equal to {@link
* DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or greater than {@link
* DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for any unsuccessful response.
* <p>
* Any value non-inclusive between those 2 values are reserved for use by the system.
* The domain verification agent may be able to act on these reserved values, and this
* ability can be queried using {@link DomainVerificationManager#isStateModifiable(int)}.
* It is expected that the agent attempt to verify all domains that it can modify the
* state of, even if it does not understand the meaning of those values.
* Any value non-inclusive between those 2 values are reserved for use by the system. The domain
* verification agent may be able to act on these reserved values, and this ability can be
* queried using {@link DomainVerificationManager#isStateModifiable(int)}. It is expected that
* the agent attempt to verify all domains that it can modify the state of, even if it does not
* understand the meaning of those values.
*/
@DataClass.Generated.Member
public @NonNull Map<String,Integer> getHostToStateMap() {
@@ -260,13 +269,13 @@ public final class DomainVerificationInfo implements Parcelable {
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
sParcellingForIdentifier.parcel(mIdentifier, dest, flags);
dest.writeString(mPackageName);
dest.writeMap(mHostToStateMap);
parcelHostToStateMap(dest, flags);
}
@Override
@@ -276,14 +285,13 @@ public final class DomainVerificationInfo implements Parcelable {
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
/* package-private */ DomainVerificationInfo(@NonNull android.os.Parcel in) {
/* package-private */ DomainVerificationInfo(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
UUID identifier = sParcellingForIdentifier.unparcel(in);
String packageName = in.readString();
Map<String,Integer> hostToStateMap = new java.util.LinkedHashMap<>();
in.readMap(hostToStateMap, Integer.class.getClassLoader());
Map<String,Integer> hostToStateMap = unparcelHostToStateMap(in);
this.mIdentifier = identifier;
com.android.internal.util.AnnotationValidations.validate(
@@ -307,16 +315,16 @@ public final class DomainVerificationInfo implements Parcelable {
}
@Override
public DomainVerificationInfo createFromParcel(@NonNull android.os.Parcel in) {
public DomainVerificationInfo createFromParcel(@NonNull Parcel in) {
return new DomainVerificationInfo(in);
}
};
@DataClass.Generated(
time = 1611862790369L,
time = 1613002530369L,
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\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)")
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)")
@Deprecated
private void __metadata() {}

View File

@@ -89,7 +89,7 @@ public class DomainVerificationManagerImpl implements DomainVerificationManager
int state) throws IllegalArgumentException, NameNotFoundException {
try {
mDomainVerificationManager.setDomainVerificationStatus(domainSetId.toString(),
new ArrayList<>(domains), state);
new DomainSet(domains), state);
} catch (Exception e) {
Exception converted = rethrow(e, domainSetId);
if (converted instanceof NameNotFoundException) {
@@ -126,7 +126,7 @@ public class DomainVerificationManagerImpl implements DomainVerificationManager
throws IllegalArgumentException, NameNotFoundException {
try {
mDomainVerificationManager.setDomainVerificationUserSelection(domainSetId.toString(),
new ArrayList<>(domains), enabled, mContext.getUserId());
new DomainSet(domains), enabled, mContext.getUserId());
} catch (Exception e) {
Exception converted = rethrow(e, domainSetId);
if (converted instanceof NameNotFoundException) {

View File

@@ -19,6 +19,7 @@ package android.content.pm.verify.domain;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.DataClass;
@@ -27,11 +28,11 @@ import com.android.internal.util.Parcelling;
import java.util.Set;
/**
* Request object sent in the {@link Intent} that's broadcast to the domain verification
* agent, retrieved through {@link DomainVerificationManager#EXTRA_VERIFICATION_REQUEST}.
* Request object sent in the {@link Intent} that's broadcast to the domain verification agent,
* retrieved through {@link DomainVerificationManager#EXTRA_VERIFICATION_REQUEST}.
* <p>
* This contains the set of packages which have been invalidated and will require
* re-verification. The exact domains can be retrieved with
* This contains the set of packages which have been invalidated and will require re-verification.
* The exact domains can be retrieved with
* {@link DomainVerificationManager#getDomainVerificationInfo(String)}
*
* @hide
@@ -42,14 +43,22 @@ import java.util.Set;
public final class DomainVerificationRequest implements Parcelable {
/**
* The package names of the apps that need to be verified. The receiver should call
* {@link DomainVerificationManager#getDomainVerificationInfo(String)} with each of
* these values to get the actual set of domains that need to be acted on.
* The package names of the apps that need to be verified. The receiver should call {@link
* DomainVerificationManager#getDomainVerificationInfo(String)} with each of these values to get
* the actual set of domains that need to be acted on.
*/
@NonNull
@DataClass.ParcelWith(Parcelling.BuiltIn.ForStringSet.class)
private final Set<String> mPackageNames;
private void parcelPackageNames(@NonNull Parcel dest, @SuppressWarnings("unused") int flags) {
DomainVerificationUtils.writeHostSet(dest, mPackageNames);
}
private Set<String> unparcelPackageNames(@NonNull Parcel in) {
return DomainVerificationUtils.readHostSet(in);
}
// Code below generated by codegen v1.0.22.
@@ -58,7 +67,8 @@ public final class DomainVerificationRequest implements Parcelable {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
// /DomainVerificationRequest.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -69,9 +79,9 @@ public final class DomainVerificationRequest implements Parcelable {
* Creates a new DomainVerificationRequest.
*
* @param packageNames
* The package names of the apps that need to be verified. The receiver should call
* {@link DomainVerificationManager#getDomainVerificationInfo(String)} with each of
* these values to get the actual set of domains that need to be acted on.
* The package names of the apps that need to be verified. The receiver should call {@link
* DomainVerificationManager#getDomainVerificationInfo(String)} with each of these values to get
* the actual set of domains that need to be acted on.
* @hide
*/
@DataClass.Generated.Member
@@ -85,9 +95,9 @@ public final class DomainVerificationRequest implements Parcelable {
}
/**
* The package names of the apps that need to be verified. The receiver should call
* {@link DomainVerificationManager#getDomainVerificationInfo(String)} with each of
* these values to get the actual set of domains that need to be acted on.
* The package names of the apps that need to be verified. The receiver should call {@link
* DomainVerificationManager#getDomainVerificationInfo(String)} with each of these values to get
* the actual set of domains that need to be acted on.
*/
@DataClass.Generated.Member
public @NonNull Set<String> getPackageNames() {
@@ -134,11 +144,11 @@ public final class DomainVerificationRequest implements Parcelable {
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
sParcellingForPackageNames.parcel(mPackageNames, dest, flags);
parcelPackageNames(dest, flags);
}
@Override
@@ -148,11 +158,11 @@ public final class DomainVerificationRequest implements Parcelable {
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
/* package-private */ DomainVerificationRequest(@NonNull android.os.Parcel in) {
/* package-private */ DomainVerificationRequest(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
Set<String> packageNames = sParcellingForPackageNames.unparcel(in);
Set<String> packageNames = unparcelPackageNames(in);
this.mPackageNames = packageNames;
com.android.internal.util.AnnotationValidations.validate(
@@ -170,16 +180,16 @@ public final class DomainVerificationRequest implements Parcelable {
}
@Override
public DomainVerificationRequest createFromParcel(@NonNull android.os.Parcel in) {
public DomainVerificationRequest createFromParcel(@NonNull Parcel in) {
return new DomainVerificationRequest(in);
}
};
@DataClass.Generated(
time = 1611862814990L,
time = 1613169505495L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java",
inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForStringSet.class) java.util.Set<java.lang.String> mPackageNames\nclass DomainVerificationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genAidl=false, genEqualsHashCode=true)")
inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForStringSet.class) java.util.Set<java.lang.String> mPackageNames\nprivate void parcelPackageNames(android.os.Parcel,int)\nprivate java.util.Set<java.lang.String> unparcelPackageNames(android.os.Parcel)\nclass DomainVerificationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genAidl=false, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}

View File

@@ -20,8 +20,10 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import android.util.ArrayMap;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
@@ -46,13 +48,12 @@ import java.util.UUID;
* <p>
* These values can be changed through the
* {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
* boolean)} and
* {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
* 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.
* 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
*/
@@ -88,16 +89,24 @@ public final class DomainVerificationUserSelection implements Parcelable {
private final boolean mLinkHandlingAllowed;
/**
* Retrieve the existing user selection state for the matching
* {@link #getPackageName()}, as was previously set by
* {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
* boolean)}.
* Retrieve the existing user selection state for the matching {@link #getPackageName()}, as was
* previously set by {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
* Set, boolean)}.
*
* @return Map of hosts to enabled state for the given package and user.
*/
@NonNull
private final Map<String, Boolean> mHostToUserSelectionMap;
private void parcelHostToUserSelectionMap(Parcel dest, @SuppressWarnings("unused") int flags) {
DomainVerificationUtils.writeHostMap(dest, mHostToUserSelectionMap);
}
private Map<String, Boolean> unparcelHostToUserSelectionMap(Parcel in) {
return DomainVerificationUtils.readHostMap(in, new ArrayMap<>(),
DomainVerificationUserSelection.class.getClassLoader());
}
// Code below generated by codegen v1.0.22.
@@ -124,10 +133,9 @@ public final class DomainVerificationUserSelection implements Parcelable {
* @param linkHandlingAllowed
* Whether or not this package is allowed to open links.
* @param hostToUserSelectionMap
* Retrieve the existing user selection state for the matching
* {@link #getPackageName()}, as was previously set by
* {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
* boolean)}.
* Retrieve the existing user selection state for the matching {@link #getPackageName()}, as was
* previously set by {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
* Set, boolean)}.
* @hide
*/
@DataClass.Generated.Member
@@ -189,10 +197,9 @@ public final class DomainVerificationUserSelection implements Parcelable {
}
/**
* Retrieve the existing user selection state for the matching
* {@link #getPackageName()}, as was previously set by
* {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
* boolean)}.
* Retrieve the existing user selection state for the matching {@link #getPackageName()}, as was
* previously set by {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
* Set, boolean)}.
*
* @return Map of hosts to enabled state for the given package and user.
*/
@@ -264,7 +271,7 @@ public final class DomainVerificationUserSelection implements Parcelable {
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
@@ -274,7 +281,7 @@ public final class DomainVerificationUserSelection implements Parcelable {
sParcellingForIdentifier.parcel(mIdentifier, dest, flags);
dest.writeString(mPackageName);
dest.writeTypedObject(mUser, flags);
dest.writeMap(mHostToUserSelectionMap);
parcelHostToUserSelectionMap(dest, flags);
}
@Override
@@ -284,7 +291,7 @@ public final class DomainVerificationUserSelection implements Parcelable {
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
/* package-private */ DomainVerificationUserSelection(@NonNull android.os.Parcel in) {
/* package-private */ DomainVerificationUserSelection(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
@@ -293,8 +300,7 @@ public final class DomainVerificationUserSelection implements Parcelable {
UUID identifier = sParcellingForIdentifier.unparcel(in);
String packageName = in.readString();
UserHandle user = (UserHandle) in.readTypedObject(UserHandle.CREATOR);
Map<String,Boolean> hostToUserSelectionMap = new java.util.LinkedHashMap<>();
in.readMap(hostToUserSelectionMap, Boolean.class.getClassLoader());
Map<String,Boolean> hostToUserSelectionMap = unparcelHostToUserSelectionMap(in);
this.mIdentifier = identifier;
com.android.internal.util.AnnotationValidations.validate(
@@ -324,16 +330,16 @@ public final class DomainVerificationUserSelection implements Parcelable {
}
@Override
public DomainVerificationUserSelection createFromParcel(@NonNull android.os.Parcel in) {
public DomainVerificationUserSelection createFromParcel(@NonNull Parcel in) {
return new DomainVerificationUserSelection(in);
}
};
@DataClass.Generated(
time = 1612829797220L,
time = 1613002353615L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java",
inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull android.os.UserHandle mUser\nprivate final @android.annotation.NonNull boolean mLinkHandlingAllowed\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Boolean> mHostToUserSelectionMap\nclass DomainVerificationUserSelection extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true)")
inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull android.os.UserHandle mUser\nprivate final @android.annotation.NonNull boolean mLinkHandlingAllowed\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Boolean> mHostToUserSelectionMap\nprivate void parcelHostToUserSelectionMap(android.os.Parcel,int)\nprivate java.util.Map<java.lang.String,java.lang.Boolean> unparcelHostToUserSelectionMap(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)")
@Deprecated
private void __metadata() {}

View File

@@ -0,0 +1,181 @@
/*
* Copyright (C) 2021 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.NonNull;
import android.annotation.Nullable;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.util.ArrayMap;
import android.util.ArraySet;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
/** @hide */
public class DomainVerificationUtils {
private static final int STRINGS_TARGET_BYTE_SIZE = IBinder.getSuggestedMaxIpcSizeBytes() / 2;
/**
* Write a map containing web hosts to the given parcel, using {@link Parcel#writeBlob(byte[])}
* if the limit exceeds {@link IBinder#getSuggestedMaxIpcSizeBytes()} / 2. This assumes that
* the written map is the only data structure in the caller that varies based on the host data
* set. Other data that will be written to the parcel after this method will not be considered
* in the calculation.
*/
public static void writeHostMap(@NonNull Parcel dest, @NonNull Map<String, ?> map) {
boolean targetSizeExceeded = false;
int totalSize = dest.dataSize();
for (String host : map.keySet()) {
totalSize += estimatedByteSizeOf(host);
if (totalSize > STRINGS_TARGET_BYTE_SIZE) {
targetSizeExceeded = true;
break;
}
}
dest.writeBoolean(targetSizeExceeded);
if (!targetSizeExceeded) {
dest.writeMap(map);
return;
}
Parcel data = Parcel.obtain();
try {
data.writeMap(map);
dest.writeBlob(data.marshall());
} finally {
data.recycle();
}
}
/**
* Retrieve a map previously written by {@link #writeHostMap(Parcel, Map)}.
*/
@NonNull
@SuppressWarnings("rawtypes")
public static <T extends Map> T readHostMap(@NonNull Parcel in, @NonNull T map,
@NonNull ClassLoader classLoader) {
boolean targetSizeExceeded = in.readBoolean();
if (!targetSizeExceeded) {
in.readMap(map, classLoader);
return map;
}
Parcel data = Parcel.obtain();
try {
byte[] blob = in.readBlob();
data.unmarshall(blob, 0, blob.length);
data.setDataPosition(0);
data.readMap(map, classLoader);
} finally {
data.recycle();
}
return map;
}
/**
* {@link ArraySet} variant of {@link #writeHostMap(Parcel, Map)}.
*/
public static void writeHostSet(@NonNull Parcel dest, @NonNull Set<String> set) {
boolean targetSizeExceeded = false;
int totalSize = dest.dataSize();
for (String host : set) {
totalSize += estimatedByteSizeOf(host);
if (totalSize > STRINGS_TARGET_BYTE_SIZE) {
targetSizeExceeded = true;
break;
}
}
dest.writeBoolean(targetSizeExceeded);
if (!targetSizeExceeded) {
writeSet(dest, set);
return;
}
Parcel data = Parcel.obtain();
try {
writeSet(data, set);
dest.writeBlob(data.marshall());
} finally {
data.recycle();
}
}
/**
* {@link ArraySet} variant of {@link #readHostMap(Parcel, Map, ClassLoader)}.
*/
@NonNull
public static Set<String> readHostSet(@NonNull Parcel in) {
boolean targetSizeExceeded = in.readBoolean();
if (!targetSizeExceeded) {
return readSet(in);
}
Parcel data = Parcel.obtain();
try {
byte[] blob = in.readBlob();
data.unmarshall(blob, 0, blob.length);
data.setDataPosition(0);
return readSet(data);
} finally {
data.recycle();
}
}
private static void writeSet(@NonNull Parcel dest, @Nullable Set<String> set) {
if (set == null) {
dest.writeInt(-1);
return;
}
dest.writeInt(set.size());
for (String string : set) {
dest.writeString(string);
}
}
@NonNull
private static Set<String> readSet(@NonNull Parcel in) {
int size = in.readInt();
if (size == -1) {
return Collections.emptySet();
}
ArraySet<String> set = new ArraySet<>(size);
for (int count = 0; count < size; count++) {
set.add(in.readString());
}
return set;
}
/**
* Ballpark the size of domains to avoid unnecessary allocation of ashmem when sending domains
* across the client-server API.
*/
public static int estimatedByteSizeOf(String string) {
return string.length() * 2 + 12;
}
}

View File

@@ -16,6 +16,7 @@
package android.content.pm.verify.domain;
import android.content.pm.verify.domain.DomainSet;
import android.content.pm.verify.domain.DomainVerificationInfo;
import android.content.pm.verify.domain.DomainVerificationUserSelection;
import java.util.List;
@@ -35,10 +36,10 @@ interface IDomainVerificationManager {
DomainVerificationUserSelection getDomainVerificationUserSelection(String packageName,
int userId);
void setDomainVerificationStatus(String domainSetId, in List<String> domains, int state);
void setDomainVerificationStatus(String domainSetId, in DomainSet domains, int state);
void setDomainVerificationLinkHandlingAllowed(String packageName, boolean allowed, int userId);
void setDomainVerificationUserSelection(String domainSetId, in List<String> domains,
void setDomainVerificationUserSelection(String domainSetId, in DomainSet domains,
boolean enabled, int userId);
}

View File

@@ -42,6 +42,8 @@ public class DomainVerificationCollector {
private static final Pattern DOMAIN_NAME_WITH_WILDCARD =
Pattern.compile("(\\*\\.)?" + Patterns.DOMAIN_NAME.pattern());
private static final int MAX_DOMAINS_BYTE_SIZE = 1024 * 1024;
@NonNull
private final PlatformCompat mPlatformCompat;
@@ -71,7 +73,7 @@ public class DomainVerificationCollector {
* <li>- Only IntentFilter.SCHEME_HTTP and/or IntentFilter.SCHEME_HTTPS,
* with no other schemes</li>
* </ul>
*
* <p>
* On prior versions of Android, Intent.CATEGORY_BROWSABLE was not a requirement, other
* schemes were allowed, and setting autoVerify to true in any intent filter would implicitly
* pretend that all intent filters were set to autoVerify="true".
@@ -86,8 +88,8 @@ public class DomainVerificationCollector {
}
/**
* Effectively {@link #collectAllWebDomains(AndroidPackage)}, but requires
* {@link IntentFilter#getAutoVerify()} == true.
* Effectively {@link #collectAllWebDomains(AndroidPackage)}, but requires {@link
* IntentFilter#getAutoVerify()} == true.
*/
@NonNull
public ArraySet<String> collectAutoVerifyDomains(@NonNull AndroidPackage pkg) {
@@ -100,24 +102,21 @@ public class DomainVerificationCollector {
boolean restrictDomains =
DomainVerificationUtils.isChangeEnabled(mPlatformCompat, pkg, RESTRICT_DOMAINS);
ArraySet<String> domains = new ArraySet<>();
if (restrictDomains) {
collectDomains(domains, pkg, checkAutoVerify);
return collectDomainsInternal(pkg, checkAutoVerify);
} else {
collectDomainsLegacy(domains, pkg, checkAutoVerify);
return collectDomainsLegacy(pkg, checkAutoVerify);
}
return domains;
}
/** @see #RESTRICT_DOMAINS */
private void collectDomainsLegacy(@NonNull Set<String> domains,
@NonNull AndroidPackage pkg, boolean checkAutoVerify) {
/**
* @see #RESTRICT_DOMAINS
*/
private ArraySet<String> collectDomainsLegacy(@NonNull AndroidPackage pkg,
boolean checkAutoVerify) {
if (!checkAutoVerify) {
// Per-domain user selection state doesn't have a V1 equivalent on S, so just use V2
collectDomains(domains, pkg, false);
return;
return collectDomainsInternal(pkg, false);
}
List<ParsedActivity> activities = pkg.getActivities();
@@ -140,39 +139,54 @@ public class DomainVerificationCollector {
}
if (!needsAutoVerify) {
return;
return new ArraySet<>();
}
}
for (int activityIndex = 0; activityIndex < activitiesSize; activityIndex++) {
ArraySet<String> domains = new ArraySet<>();
int totalSize = 0;
boolean underMaxSize = true;
for (int activityIndex = 0; activityIndex < activitiesSize && underMaxSize;
activityIndex++) {
ParsedActivity activity = activities.get(activityIndex);
List<ParsedIntentInfo> intents = activity.getIntents();
int intentsSize = intents.size();
for (int intentIndex = 0; intentIndex < intentsSize; intentIndex++) {
for (int intentIndex = 0; intentIndex < intentsSize && underMaxSize; intentIndex++) {
ParsedIntentInfo intent = intents.get(intentIndex);
if (intent.handlesWebUris(false)) {
int authorityCount = intent.countDataAuthorities();
for (int index = 0; index < authorityCount; index++) {
String host = intent.getDataAuthority(index).getHost();
if (isValidHost(host)) {
totalSize += byteSizeOf(host);
underMaxSize = totalSize < MAX_DOMAINS_BYTE_SIZE;
domains.add(host);
}
}
}
}
}
return domains;
}
/** @see #RESTRICT_DOMAINS */
private void collectDomains(@NonNull Set<String> domains,
@NonNull AndroidPackage pkg, boolean checkAutoVerify) {
/**
* @see #RESTRICT_DOMAINS
*/
private ArraySet<String> collectDomainsInternal(@NonNull AndroidPackage pkg,
boolean checkAutoVerify) {
ArraySet<String> domains = new ArraySet<>();
int totalSize = 0;
boolean underMaxSize = true;
List<ParsedActivity> activities = pkg.getActivities();
int activitiesSize = activities.size();
for (int activityIndex = 0; activityIndex < activitiesSize; activityIndex++) {
for (int activityIndex = 0; activityIndex < activitiesSize && underMaxSize;
activityIndex++) {
ParsedActivity activity = activities.get(activityIndex);
List<ParsedIntentInfo> intents = activity.getIntents();
int intentsSize = intents.size();
for (int intentIndex = 0; intentIndex < intentsSize; intentIndex++) {
for (int intentIndex = 0; intentIndex < intentsSize && underMaxSize; intentIndex++) {
ParsedIntentInfo intent = intents.get(intentIndex);
if (checkAutoVerify && !intent.getAutoVerify()) {
continue;
@@ -198,14 +212,27 @@ public class DomainVerificationCollector {
// app developer by declaring a separate intent-filter. This may not be worth
// fixing.
int authorityCount = intent.countDataAuthorities();
for (int index = 0; index < authorityCount; index++) {
for (int index = 0; index < authorityCount && underMaxSize; index++) {
String host = intent.getDataAuthority(index).getHost();
if (isValidHost(host)) {
totalSize += byteSizeOf(host);
underMaxSize = totalSize < MAX_DOMAINS_BYTE_SIZE;
domains.add(host);
}
}
}
}
return domains;
}
/**
* Ballpark the size of domains to avoid a ridiculous amount of domains that could slow
* down client-server communication.
*/
private int byteSizeOf(String string) {
// Use the same method from core for the data objects so that restrictions are consistent
return android.content.pm.verify.domain.DomainVerificationUtils.estimatedByteSizeOf(string);
}
/**

View File

@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.verify.domain.DomainSet;
import android.content.pm.verify.domain.DomainVerificationManager.InvalidDomainSetException;
import android.content.pm.verify.domain.DomainVerificationManagerImpl;
import android.content.pm.verify.domain.DomainVerificationInfo;
@@ -61,11 +62,11 @@ class DomainVerificationManagerStub extends IDomainVerificationManager.Stub {
}
@Override
public void setDomainVerificationStatus(String domainSetId, List<String> domains,
public void setDomainVerificationStatus(String domainSetId, @NonNull DomainSet domainSet,
int state) {
try {
mService.setDomainVerificationStatus(UUID.fromString(domainSetId),
new ArraySet<>(domains), state);
domainSet.getDomains(), state);
} catch (Exception e) {
throw rethrow(e);
}
@@ -82,11 +83,11 @@ class DomainVerificationManagerStub extends IDomainVerificationManager.Stub {
}
@Override
public void setDomainVerificationUserSelection(String domainSetId, List<String> domains,
public void setDomainVerificationUserSelection(String domainSetId, @NonNull DomainSet domainSet,
boolean enabled, @UserIdInt int userId) {
try {
mService.setDomainVerificationUserSelection(UUID.fromString(domainSetId),
new ArraySet<>(domains), enabled, userId);
domainSet.getDomains(), enabled, userId);
} catch (Exception e) {
throw rethrow(e);
}

View File

@@ -16,8 +16,9 @@
package com.android.server.pm.test.verify.domain
import android.content.pm.verify.domain.DomainVerificationRequest
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.os.Parcel
import android.os.Parcelable
@@ -27,6 +28,7 @@ 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 {
@@ -40,18 +42,25 @@ class DomainVerificationCoreApiTest {
assertThat(value).containsExactlyEntriesIn(other)
}
private val massiveSet by lazy {
val fragmentOf21 = ".com.example.test.app"
val list = mutableListOf("prefix$fragmentOf21")
var totalSize = 0
// Slightly overshoot a size of 1MB
while (totalSize < (1024 * 512)) {
val nextValue = "${list.last()}$fragmentOf21"
totalSize += nextValue.length
list += nextValue
}
list.toSet()
}
@JvmStatic
@Parameterized.Parameters
@Parameterized.Parameters(name = "{0}")
fun parameters() = arrayOf(
Parameter(
initial = {
DomainVerificationRequest(
setOf(
"com.test.pkg.one",
"com.test.pkg.two"
)
)
},
testName = "DomainVerificationRequest",
initial = { DomainVerificationRequest(massiveSet) },
unparcel = { DomainVerificationRequest.CREATOR.createFromParcel(it) },
assertion = { first, second ->
assertAll<DomainVerificationRequest, Set<String>>(first, second,
@@ -61,15 +70,12 @@ class DomainVerificationCoreApiTest {
}
),
Parameter(
testName = "DomainVerificationInfo",
initial = {
DomainVerificationInfo(
UUID.fromString("703f6d34-6241-4cfd-8176-2e1d23355811"),
"com.test.pkg",
mapOf(
"example.com" to 0,
"example.org" to 1,
"example.new" to 1000
)
massiveSet.withIndex().associate { it.value to it.index }
)
},
unparcel = { DomainVerificationInfo.CREATOR.createFromParcel(it) },
@@ -86,17 +92,15 @@ class DomainVerificationCoreApiTest {
}
),
Parameter(
testName = "DomainVerificationUserSelection",
initial = {
DomainVerificationUserSelection(
UUID.fromString("703f6d34-6241-4cfd-8176-2e1d23355811"),
"com.test.pkg",
UserHandle.of(10),
true,
mapOf(
"example.com" to true,
"example.org" to false,
"example.new" to true
)
massiveSet.withIndex()
.associate { it.value to (it.index % 2 == 0) }
)
},
unparcel = { DomainVerificationUserSelection.CREATOR.createFromParcel(it) },
@@ -119,16 +123,30 @@ class DomainVerificationCoreApiTest {
{ it.component5() }, IS_MAP_EQUAL_TO
)
}
),
Parameter(
testName = "DomainSet",
initial = { DomainSet(massiveSet) },
unparcel = { DomainSet.CREATOR.createFromParcel(it) },
assertion = { first, second ->
assertAll<DomainSet, Set<String>>(
first, second,
{ it.domains }, assertion = IS_EQUAL_TO
)
}
)
)
class Parameter<T : Parcelable>(
val testName: String,
val initial: () -> T,
val unparcel: (Parcel) -> T,
private val assertion: (first: T, second: T) -> Unit
) {
@Suppress("UNCHECKED_CAST")
fun assert(first: Any, second: Any) = assertion(first as T, second as T)
override fun toString() = testName
}
private fun <T> assertAll(vararg values: T, block: (value: T, other: T) -> Unit) {
@@ -141,11 +159,17 @@ class DomainVerificationCoreApiTest {
first: T,
second: T,
fieldValue: (T) -> V,
componentValue: (T) -> V,
componentValue: ((T) -> V)? = null,
assertion: (value: V, other: V) -> Unit
) {
val values = arrayOf<Any>(fieldValue(first), fieldValue(second),
componentValue(first), componentValue(second))
val values = mutableListOf<Any>(fieldValue(first), fieldValue(second))
.apply {
componentValue?.let {
add(it(first))
add(it(second))
}
}
.toTypedArray()
values.indices.drop(1).forEach {
@Suppress("UNCHECKED_CAST")
assertion(values[0] as V, values[it] as V)