Add DomainVerificationManager
Contains the core SDK @SystemApi portion of the domain verification APIs, including the state codes and get/set methods for package/user state. Set methods are gated by corresponding permissions, but get methods were left available as general @SystemApi in case someone finds a use case for them. Adds a new exception which allows the manager to be more specific in what caused a failure. Exempt-From-Owner-Approval: Already approved by owners on main branch Bug: 163565712 Test: none, just API interfaces, will be tested with implementation Change-Id: I86802fe4b88a8a0f63a1798944c5d8c3a3bab09b
This commit is contained in:
@@ -2103,6 +2103,7 @@ package android.content {
|
||||
field public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
|
||||
field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
|
||||
field public static final String CONTEXTHUB_SERVICE = "contexthub";
|
||||
field public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification";
|
||||
field public static final String ETHERNET_SERVICE = "ethernet";
|
||||
field public static final String EUICC_CARD_SERVICE = "euicc_card";
|
||||
field public static final String FONT_SERVICE = "font";
|
||||
@@ -2146,6 +2147,7 @@ package android.content {
|
||||
field public static final String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";
|
||||
field public static final String ACTION_DEVICE_CUSTOMIZATION_READY = "android.intent.action.DEVICE_CUSTOMIZATION_READY";
|
||||
field public static final String ACTION_DIAL_EMERGENCY = "android.intent.action.DIAL_EMERGENCY";
|
||||
field public static final String ACTION_DOMAINS_NEED_VERIFICATION = "android.intent.action.DOMAINS_NEED_VERIFICATION";
|
||||
field public static final String ACTION_FACTORY_RESET = "android.intent.action.FACTORY_RESET";
|
||||
field public static final String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON";
|
||||
field public static final String ACTION_INCIDENT_REPORT_READY = "android.intent.action.INCIDENT_REPORT_READY";
|
||||
@@ -2701,6 +2703,31 @@ package android.content.pm.dex {
|
||||
|
||||
package android.content.pm.domain.verify {
|
||||
|
||||
public interface DomainVerificationManager {
|
||||
method @Nullable @RequiresPermission(allOf={android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, android.Manifest.permission.QUERY_ALL_PACKAGES, android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION}, conditional=true) public android.content.pm.domain.verify.DomainVerificationSet getDomainVerificationSet(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
|
||||
method @Nullable @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public android.content.pm.domain.verify.DomainVerificationUserSelection getDomainVerificationUserSelection(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
|
||||
method @NonNull @RequiresPermission(allOf={android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, android.Manifest.permission.QUERY_ALL_PACKAGES}) public java.util.List<java.lang.String> getValidVerificationPackageNames();
|
||||
method public static boolean isStateModifiable(int);
|
||||
method public static boolean isStateVerified(int);
|
||||
method @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public void setDomainVerificationLinkHandlingAllowed(@NonNull String, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, android.Manifest.permission.QUERY_ALL_PACKAGES}) public void setDomainVerificationStatus(@NonNull java.util.UUID, @NonNull java.util.Set<java.lang.String>, int) throws android.content.pm.domain.verify.DomainVerificationManager.InvalidDomainSetException, 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.domain.verify.DomainVerificationManager.InvalidDomainSetException, android.content.pm.PackageManager.NameNotFoundException;
|
||||
field public static final String EXTRA_VERIFICATION_REQUEST = "android.content.pm.domain.verify.extra.VERIFICATION_REQUEST";
|
||||
field public static final int STATE_FIRST_VERIFIER_DEFINED = 1024; // 0x400
|
||||
field public static final int STATE_NO_RESPONSE = 0; // 0x0
|
||||
field public static final int STATE_SUCCESS = 1; // 0x1
|
||||
}
|
||||
|
||||
public static class DomainVerificationManager.InvalidDomainSetException extends android.util.AndroidException {
|
||||
method @Nullable public java.util.UUID getDomainSetId();
|
||||
method @Nullable public String getPackageName();
|
||||
method public int getReason();
|
||||
field public static final int REASON_ID_INVALID = 2; // 0x2
|
||||
field public static final int REASON_ID_NULL = 1; // 0x1
|
||||
field public static final int REASON_SET_NULL_OR_EMPTY = 3; // 0x3
|
||||
field public static final int REASON_UNKNOWN_DOMAIN = 4; // 0x4
|
||||
}
|
||||
|
||||
public final class DomainVerificationRequest implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @NonNull public java.util.Set<java.lang.String> getPackageNames();
|
||||
|
||||
@@ -5450,6 +5450,15 @@ public abstract class Context {
|
||||
*/
|
||||
public static final String GAME_SERVICE = "game";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to access domain verification service.
|
||||
*
|
||||
* @see #getSystemService(String)
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification";
|
||||
|
||||
/**
|
||||
* Determine whether the given permission is allowed for a particular
|
||||
* process and user ID running in the system.
|
||||
|
||||
@@ -2846,6 +2846,21 @@ public class Intent implements Parcelable, Cloneable {
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION";
|
||||
|
||||
|
||||
/**
|
||||
* Broadcast Action: Sent to the system domain verification agent when an app's domains need
|
||||
* to be verified. The data contains the domains hosts to be verified against.
|
||||
* <p class="note">
|
||||
* This is a protected intent that can only be sent by the system.
|
||||
* </p>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_DOMAINS_NEED_VERIFICATION =
|
||||
"android.intent.action.DOMAINS_NEED_VERIFICATION";
|
||||
|
||||
/**
|
||||
* Broadcast Action: Resources for a set of packages (which were
|
||||
* previously unavailable) are currently
|
||||
|
||||
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* 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.domain.verify;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SystemService;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.AndroidException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* System service to access the 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 #getDomainVerificationSet(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
|
||||
*/
|
||||
@SystemApi
|
||||
@SystemService(Context.DOMAIN_VERIFICATION_SERVICE)
|
||||
public interface DomainVerificationManager {
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
String EXTRA_VERIFICATION_REQUEST =
|
||||
"android.content.pm.domain.verify.extra.VERIFICATION_REQUEST";
|
||||
|
||||
/**
|
||||
* No response has been recorded by either the system or any verification agent.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
int STATE_FIRST_VERIFIER_DEFINED = DomainVerificationState.STATE_FIRST_VERIFIER_DEFINED;
|
||||
|
||||
/** @hide */
|
||||
@NonNull
|
||||
static String stateToDebugString(@DomainVerificationState.State int state) {
|
||||
switch (state) {
|
||||
case DomainVerificationState.STATE_NO_RESPONSE:
|
||||
return "none";
|
||||
case DomainVerificationState.STATE_SUCCESS:
|
||||
return "verified";
|
||||
case DomainVerificationState.STATE_APPROVED:
|
||||
return "approved";
|
||||
case DomainVerificationState.STATE_DENIED:
|
||||
return "denied";
|
||||
case DomainVerificationState.STATE_MIGRATED:
|
||||
return "migrated";
|
||||
case DomainVerificationState.STATE_RESTORED:
|
||||
return "restored";
|
||||
case DomainVerificationState.STATE_LEGACY_FAILURE:
|
||||
return "legacy_failure";
|
||||
default:
|
||||
return String.valueOf(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
static boolean isStateVerified(@DomainVerificationState.State int state) {
|
||||
switch (state) {
|
||||
case DomainVerificationState.STATE_SUCCESS:
|
||||
case DomainVerificationState.STATE_APPROVED:
|
||||
case DomainVerificationState.STATE_MIGRATED:
|
||||
case DomainVerificationState.STATE_RESTORED:
|
||||
return true;
|
||||
case DomainVerificationState.STATE_NO_RESPONSE:
|
||||
case DomainVerificationState.STATE_DENIED:
|
||||
case DomainVerificationState.STATE_LEGACY_FAILURE:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
static boolean isStateModifiable(@DomainVerificationState.State int state) {
|
||||
switch (state) {
|
||||
case DomainVerificationState.STATE_NO_RESPONSE:
|
||||
case DomainVerificationState.STATE_SUCCESS:
|
||||
case DomainVerificationState.STATE_MIGRATED:
|
||||
case DomainVerificationState.STATE_RESTORED:
|
||||
case DomainVerificationState.STATE_LEGACY_FAILURE:
|
||||
return true;
|
||||
case DomainVerificationState.STATE_APPROVED:
|
||||
case DomainVerificationState.STATE_DENIED:
|
||||
return false;
|
||||
default:
|
||||
return state >= DomainVerificationState.STATE_FIRST_VERIFIER_DEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
switch (state) {
|
||||
case DomainVerificationState.STATE_NO_RESPONSE:
|
||||
case DomainVerificationState.STATE_MIGRATED:
|
||||
case DomainVerificationState.STATE_RESTORED:
|
||||
return true;
|
||||
case DomainVerificationState.STATE_SUCCESS:
|
||||
case DomainVerificationState.STATE_APPROVED:
|
||||
case DomainVerificationState.STATE_DENIED:
|
||||
case DomainVerificationState.STATE_LEGACY_FAILURE:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to iterate all {@link DomainVerificationSet} 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.
|
||||
*/
|
||||
@NonNull
|
||||
@RequiresPermission(allOf = {
|
||||
android.Manifest.permission.DOMAIN_VERIFICATION_AGENT,
|
||||
android.Manifest.permission.QUERY_ALL_PACKAGES
|
||||
})
|
||||
List<String> getValidVerificationPackageNames();
|
||||
|
||||
/**
|
||||
* Retrieves the domain verification state for a given package. The caller must be the domain
|
||||
* verification agent for the device with
|
||||
* {@link android.Manifest.permission#DOMAIN_VERIFICATION_AGENT}, or hold
|
||||
* {@link android.Manifest.permission#UPDATE_DOMAIN_VERIFICATION_USER_SELECTION}.
|
||||
* Also requires that the caller have the
|
||||
* {@link android.Manifest.permission#QUERY_ALL_PACKAGES} permission in addition to either of
|
||||
* the requirements above.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
@Nullable
|
||||
@RequiresPermission(allOf = {
|
||||
android.Manifest.permission.DOMAIN_VERIFICATION_AGENT,
|
||||
android.Manifest.permission.QUERY_ALL_PACKAGES,
|
||||
android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
|
||||
}, conditional = true)
|
||||
DomainVerificationSet getDomainVerificationSet(@NonNull String packageName)
|
||||
throws NameNotFoundException;
|
||||
|
||||
/**
|
||||
* Change the verification status of the {@param domains} of the package associated with
|
||||
* {@param domainSetId}.
|
||||
*
|
||||
* @param domainSetId See {@link DomainVerificationSet#getIdentifier()}.
|
||||
* @param domains List of host names to change the state of.
|
||||
* @param state See {@link DomainVerificationSet#getHostToStateMap()}.
|
||||
* @throws InvalidDomainSetException 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.
|
||||
* @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.
|
||||
*/
|
||||
@RequiresPermission(allOf = {
|
||||
android.Manifest.permission.DOMAIN_VERIFICATION_AGENT,
|
||||
android.Manifest.permission.QUERY_ALL_PACKAGES
|
||||
})
|
||||
void setDomainVerificationStatus(@NonNull UUID domainSetId, @NonNull Set<String> domains,
|
||||
@DomainVerificationState.State int state)
|
||||
throws InvalidDomainSetException, NameNotFoundException;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* By default, all apps are allowed to open verified links. Users must disable them explicitly.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
|
||||
void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName, boolean allowed)
|
||||
throws NameNotFoundException;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This will be combined with the verification status and other system state to determine which
|
||||
* application is launched to handle an app link.
|
||||
*
|
||||
* @param domainSetId See {@link DomainVerificationSet#getIdentifier()}.
|
||||
* @param domains The domains to toggle the state of.
|
||||
* @param enabled Whether or not the app should automatically open the domains specified.
|
||||
* @throws InvalidDomainSetException 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.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
|
||||
void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
|
||||
@NonNull Set<String> domains, boolean enabled)
|
||||
throws InvalidDomainSetException, NameNotFoundException;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Nullable
|
||||
@RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
|
||||
DomainVerificationUserSelection getDomainVerificationUserSelection(@NonNull String packageName)
|
||||
throws NameNotFoundException;
|
||||
|
||||
/**
|
||||
* Thrown if a {@link DomainVerificationSet#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 #getDomainVerificationSet(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.
|
||||
*/
|
||||
class InvalidDomainSetException extends AndroidException {
|
||||
|
||||
public static final int REASON_ID_NULL = 1;
|
||||
public static final int REASON_ID_INVALID = 2;
|
||||
public static final int REASON_SET_NULL_OR_EMPTY = 3;
|
||||
public static final int REASON_UNKNOWN_DOMAIN = 4;
|
||||
|
||||
/** @hide */
|
||||
@IntDef({
|
||||
REASON_ID_NULL,
|
||||
REASON_ID_INVALID,
|
||||
REASON_SET_NULL_OR_EMPTY,
|
||||
REASON_UNKNOWN_DOMAIN
|
||||
})
|
||||
public @interface Reason {
|
||||
}
|
||||
|
||||
private static String buildMessage(@Nullable UUID domainSetId, @Nullable String packageName,
|
||||
@Reason int reason) {
|
||||
switch (reason) {
|
||||
case REASON_ID_NULL:
|
||||
return "Domain set ID cannot be null";
|
||||
case REASON_ID_INVALID:
|
||||
return "Domain set ID " + domainSetId + " has been invalidated";
|
||||
case REASON_SET_NULL_OR_EMPTY:
|
||||
return "Domain set cannot be null or empty";
|
||||
case REASON_UNKNOWN_DOMAIN:
|
||||
return "Domain set contains value that was not declared by the target package "
|
||||
+ packageName;
|
||||
default:
|
||||
return "Unknown failure";
|
||||
}
|
||||
}
|
||||
|
||||
@Reason
|
||||
private final int mReason;
|
||||
|
||||
@Nullable
|
||||
private final UUID mDomainSetId;
|
||||
|
||||
@Nullable
|
||||
private final String mPackageName;
|
||||
|
||||
/** @hide */
|
||||
public InvalidDomainSetException(@Nullable UUID domainSetId, @Nullable String packageName,
|
||||
@Reason int reason) {
|
||||
super(buildMessage(domainSetId, packageName, reason));
|
||||
mDomainSetId = domainSetId;
|
||||
mPackageName = packageName;
|
||||
mReason = reason;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UUID getDomainSetId() {
|
||||
return mDomainSetId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
}
|
||||
|
||||
@Reason
|
||||
public int getReason() {
|
||||
return mReason;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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.domain.verify;
|
||||
|
||||
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.ArrayList;
|
||||
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 DomainVerificationSet getDomainVerificationSet(@NonNull String packageName)
|
||||
throws NameNotFoundException {
|
||||
try {
|
||||
return mDomainVerificationManager.getDomainVerificationSet(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 InvalidDomainSetException, NameNotFoundException {
|
||||
try {
|
||||
mDomainVerificationManager.setDomainVerificationStatus(domainSetId.toString(),
|
||||
new ArrayList<>(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 InvalidDomainSetException, NameNotFoundException {
|
||||
try {
|
||||
mDomainVerificationManager.setDomainVerificationUserSelection(domainSetId.toString(),
|
||||
new ArrayList<>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 InvalidDomainSetException(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.domain.verify;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public interface DomainVerificationState {
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@IntDef({
|
||||
STATE_NO_RESPONSE,
|
||||
STATE_SUCCESS,
|
||||
STATE_MIGRATED,
|
||||
STATE_RESTORED,
|
||||
STATE_APPROVED,
|
||||
STATE_DENIED,
|
||||
STATE_LEGACY_FAILURE,
|
||||
STATE_FIRST_VERIFIER_DEFINED
|
||||
})
|
||||
@interface State {
|
||||
}
|
||||
|
||||
// TODO(b/159952358): Document all the places that states need to be updated when one is added
|
||||
/**
|
||||
* @see DomainVerificationManager#STATE_NO_RESPONSE
|
||||
*/
|
||||
int STATE_NO_RESPONSE = 0;
|
||||
|
||||
/**
|
||||
* @see DomainVerificationManager#STATE_SUCCESS
|
||||
*/
|
||||
int STATE_SUCCESS = 1;
|
||||
|
||||
/**
|
||||
* The system has chosen to ignore the verification agent's opinion on whether the domain should
|
||||
* be verified. This will treat the domain as verified.
|
||||
* <p>
|
||||
* TODO: This currently combines SysConfig and instant app. Is it worth separating those?
|
||||
*/
|
||||
int STATE_APPROVED = 2;
|
||||
|
||||
/**
|
||||
* The system has chosen to ignore the verification agent's opinion on whether the domain should
|
||||
* be verified. This will treat the domain as unverified.
|
||||
*/
|
||||
int STATE_DENIED = 3;
|
||||
|
||||
/**
|
||||
* The state was migrated from the previous intent filter verification API. This will treat the
|
||||
* domain as verified, but it should be updated by the verification agent. The older API's
|
||||
* collection and handling of verifying domains may lead to improperly migrated state.
|
||||
*/
|
||||
int STATE_MIGRATED = 4;
|
||||
|
||||
/**
|
||||
* The state was restored from a user backup or by the system. This is treated as if the domain
|
||||
* was verified, but the verification agent may choose to re-verify this domain to be certain
|
||||
* nothing has changed since the snapshot.
|
||||
*/
|
||||
int STATE_RESTORED = 5;
|
||||
|
||||
/**
|
||||
* The domain was failed by a legacy intent filter verification agent from v1 of the API. This
|
||||
* is made distinct from {@link #STATE_FIRST_VERIFIER_DEFINED} to prevent any v2 verification
|
||||
* agent from misinterpreting the result, since {@link #STATE_FIRST_VERIFIER_DEFINED} is agent
|
||||
* specific and can be defined as a special error code.
|
||||
*/
|
||||
int STATE_LEGACY_FAILURE = 6;
|
||||
|
||||
/**
|
||||
* @see DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED
|
||||
*/
|
||||
int STATE_FIRST_VERIFIER_DEFINED = 0b10000000000;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 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.domain.verify;
|
||||
|
||||
import android.content.pm.domain.verify.DomainVerificationSet;
|
||||
import android.content.pm.domain.verify.DomainVerificationUserSelection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @see DomainVerificationManager
|
||||
* @hide
|
||||
*/
|
||||
interface IDomainVerificationManager {
|
||||
|
||||
List<String> getValidVerificationPackageNames();
|
||||
|
||||
@nullable
|
||||
DomainVerificationSet getDomainVerificationSet(String packageName);
|
||||
|
||||
@nullable
|
||||
DomainVerificationUserSelection getDomainVerificationUserSelection(String packageName,
|
||||
int userId);
|
||||
|
||||
void setDomainVerificationStatus(String domainSetId, in List<String> domains, int state);
|
||||
|
||||
void setDomainVerificationLinkHandlingAllowed(String packageName, boolean allowed, int userId);
|
||||
|
||||
void setDomainVerificationUserSelection(String domainSetId, in List<String> domains,
|
||||
boolean enabled, int userId);
|
||||
}
|
||||
@@ -93,6 +93,7 @@
|
||||
<protected-broadcast android:name="android.intent.action.USER_SWITCHED" />
|
||||
<protected-broadcast android:name="android.intent.action.USER_INITIALIZE" />
|
||||
<protected-broadcast android:name="android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION" />
|
||||
<protected-broadcast android:name="android.intent.action.DOMAINS_NEED_VERIFICATION" />
|
||||
<protected-broadcast android:name="android.intent.action.OVERLAY_ADDED" />
|
||||
<protected-broadcast android:name="android.intent.action.OVERLAY_CHANGED" />
|
||||
<protected-broadcast android:name="android.intent.action.OVERLAY_REMOVED" />
|
||||
|
||||
Reference in New Issue
Block a user