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:
Winson
2020-12-15 14:50:45 -08:00
parent dea682ad80
commit 477f87d56b
8 changed files with 745 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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