/* * 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.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.net.Network; import android.net.NetworkCapabilities; import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtils; import android.os.PersistableBundle; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; import com.android.server.vcn.util.PersistableBundleUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.concurrent.TimeUnit; /** * This class represents a configuration for a connection to a Virtual Carrier Network gateway. * *

Each VcnGatewayConnectionConfig represents a single logical connection to a carrier gateway, * and may provide one or more telephony services (as represented by network capabilities). Each * gateway is expected to provide mobility for a given session as the device roams across {@link * Network}s. * *

A VCN connection based on this configuration will be brought up dynamically based on device * settings, and filed NetworkRequests. Underlying Networks must provide INTERNET connectivity, and * must be part of the subscription group under which this configuration is registered (see {@link * VcnManager#setVcnConfig}). * *

As an abstraction of a cellular network, services that can be provided by a VCN network are * limited to services provided by cellular networks: * *

*/ public final class VcnGatewayConnectionConfig { /** @hide */ public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; /** @hide */ public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS = 120; // TODO: Use MIN_MTU_V6 once it is public, @hide @VisibleForTesting(visibility = Visibility.PRIVATE) static final int MIN_MTU_V6 = 1280; /** * The set of allowed capabilities for exposed capabilities. * * @hide */ public static final Set ALLOWED_CAPABILITIES; static { Set allowedCaps = new ArraySet<>(); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MMS); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_SUPL); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_DUN); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_FOTA); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IMS); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_CBS); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IA); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_RCS); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_XCAP); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_EIMS); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_INTERNET); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MCX); ALLOWED_CAPABILITIES = Collections.unmodifiableSet(allowedCaps); } /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef( prefix = {"NET_CAPABILITY_"}, value = { NetworkCapabilities.NET_CAPABILITY_MMS, NetworkCapabilities.NET_CAPABILITY_SUPL, NetworkCapabilities.NET_CAPABILITY_DUN, NetworkCapabilities.NET_CAPABILITY_FOTA, NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_CBS, NetworkCapabilities.NET_CAPABILITY_IA, NetworkCapabilities.NET_CAPABILITY_RCS, NetworkCapabilities.NET_CAPABILITY_XCAP, NetworkCapabilities.NET_CAPABILITY_EIMS, NetworkCapabilities.NET_CAPABILITY_INTERNET, NetworkCapabilities.NET_CAPABILITY_MCX, }) public @interface VcnSupportedCapability {} /** * Perform mobility update to attempt recovery from suspected data stalls. * *

If set, the gateway connection will monitor the data stall detection of the VCN network. * When there is a suspected data stall, the gateway connection will attempt recovery by * performing a mobility update on the underlying IKE session. */ public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef( prefix = {"VCN_GATEWAY_OPTION_"}, value = { VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY, }) public @interface VcnGatewayOption {} private static final Set ALLOWED_GATEWAY_OPTIONS = new ArraySet<>(); static { ALLOWED_GATEWAY_OPTIONS.add(VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY); } private static final int DEFAULT_MAX_MTU = 1500; /** * The maximum number of retry intervals that may be specified. * *

Limited to ensure an upper bound on config sizes. */ private static final int MAX_RETRY_INTERVAL_COUNT = 10; /** * The minimum allowable repeating retry interval * *

To ensure the device is not constantly being woken up, this retry interval MUST be greater * than this value. * * @see {@link Builder#setRetryIntervalsMillis()} */ private static final long MINIMUM_REPEATING_RETRY_INTERVAL_MS = TimeUnit.MINUTES.toMillis(15); private static final long[] DEFAULT_RETRY_INTERVALS_MS = new long[] { TimeUnit.SECONDS.toMillis(1), TimeUnit.SECONDS.toMillis(2), TimeUnit.SECONDS.toMillis(5), TimeUnit.SECONDS.toMillis(30), TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(5), TimeUnit.MINUTES.toMillis(15) }; /** @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static final List DEFAULT_UNDERLYING_NETWORK_TEMPLATES = new ArrayList<>(); static { DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnCellUnderlyingNetworkTemplate.Builder() .setOpportunistic(MATCH_REQUIRED) .build()); DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnWifiUnderlyingNetworkTemplate.Builder() .build()); DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnCellUnderlyingNetworkTemplate.Builder() .build()); } private static final String GATEWAY_CONNECTION_NAME_KEY = "mGatewayConnectionName"; @NonNull private final String mGatewayConnectionName; private static final String TUNNEL_CONNECTION_PARAMS_KEY = "mTunnelConnectionParams"; @NonNull private IkeTunnelConnectionParams mTunnelConnectionParams; private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; @NonNull private final SortedSet mExposedCapabilities; /** @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static final String UNDERLYING_NETWORK_TEMPLATES_KEY = "mUnderlyingNetworkTemplates"; @NonNull private final List mUnderlyingNetworkTemplates; private static final String MAX_MTU_KEY = "mMaxMtu"; private final int mMaxMtu; private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs"; @NonNull private final long[] mRetryIntervalsMs; private static final String MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY = "mMinUdpPort4500NatTimeoutSeconds"; private final int mMinUdpPort4500NatTimeoutSeconds; private static final String IS_SAFE_MODE_DISABLED_KEY = "mIsSafeModeDisabled"; private final boolean mIsSafeModeDisabled; private static final String GATEWAY_OPTIONS_KEY = "mGatewayOptions"; @NonNull private final Set mGatewayOptions; /** Builds a VcnGatewayConnectionConfig with the specified parameters. */ private VcnGatewayConnectionConfig( @NonNull String gatewayConnectionName, @NonNull IkeTunnelConnectionParams tunnelConnectionParams, @NonNull Set exposedCapabilities, @NonNull List underlyingNetworkTemplates, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu, @NonNull int minUdpPort4500NatTimeoutSeconds, boolean isSafeModeDisabled, @NonNull Set gatewayOptions) { mGatewayConnectionName = gatewayConnectionName; mTunnelConnectionParams = tunnelConnectionParams; mExposedCapabilities = new TreeSet(exposedCapabilities); mRetryIntervalsMs = retryIntervalsMs; mMaxMtu = maxMtu; mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; mGatewayOptions = Collections.unmodifiableSet(new ArraySet(gatewayOptions)); mIsSafeModeDisabled = isSafeModeDisabled; mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates); if (mUnderlyingNetworkTemplates.isEmpty()) { mUnderlyingNetworkTemplates.addAll(DEFAULT_UNDERLYING_NETWORK_TEMPLATES); } validate(); } // Null check MUST be done for all new fields added to VcnGatewayConnectionConfig, to avoid // crashes when parsing PersistableBundle built on old platforms. /** @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) { final PersistableBundle tunnelConnectionParamsBundle = in.getPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY); Objects.requireNonNull( tunnelConnectionParamsBundle, "tunnelConnectionParamsBundle was null"); final PersistableBundle exposedCapsBundle = in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY); mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY); mTunnelConnectionParams = TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle); mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList( exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); final PersistableBundle networkTemplatesBundle = in.getPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY); if (networkTemplatesBundle == null) { // UNDERLYING_NETWORK_TEMPLATES_KEY was added in Android T. Thus // VcnGatewayConnectionConfig created on old platforms will not have this data and will // be assigned with the default value mUnderlyingNetworkTemplates = new ArrayList<>(DEFAULT_UNDERLYING_NETWORK_TEMPLATES); } else { mUnderlyingNetworkTemplates = PersistableBundleUtils.toList( networkTemplatesBundle, VcnUnderlyingNetworkTemplate::fromPersistableBundle); } final PersistableBundle gatewayOptionsBundle = in.getPersistableBundle(GATEWAY_OPTIONS_KEY); if (gatewayOptionsBundle == null) { // GATEWAY_OPTIONS_KEY was added in Android U. Thus VcnGatewayConnectionConfig created // on old platforms will not have this data and will be assigned with the default value mGatewayOptions = Collections.emptySet(); } else { mGatewayOptions = new ArraySet<>( PersistableBundleUtils.toList( gatewayOptionsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); } mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); mMaxMtu = in.getInt(MAX_MTU_KEY); mMinUdpPort4500NatTimeoutSeconds = in.getInt( MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); mIsSafeModeDisabled = in.getBoolean(IS_SAFE_MODE_DISABLED_KEY); validate(); } private void validate() { Objects.requireNonNull(mGatewayConnectionName, "gatewayConnectionName was null"); Objects.requireNonNull(mTunnelConnectionParams, "tunnel connection parameter was null"); Preconditions.checkArgument( mExposedCapabilities != null && !mExposedCapabilities.isEmpty(), "exposedCapsBundle was null or empty"); for (Integer cap : getAllExposedCapabilities()) { checkValidCapability(cap); } validateNetworkTemplateList(mUnderlyingNetworkTemplates); Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null"); validateRetryInterval(mRetryIntervalsMs); Preconditions.checkArgument( mMaxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)"); Preconditions.checkArgument( mMinUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET || mMinUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, "minUdpPort4500NatTimeoutSeconds must be at least 120s"); for (int option : mGatewayOptions) { validateGatewayOption(option); } } private static void checkValidCapability(int capability) { Preconditions.checkArgument( ALLOWED_CAPABILITIES.contains(capability), "NetworkCapability " + capability + "out of range"); } private static void validateRetryInterval(@Nullable long[] retryIntervalsMs) { Preconditions.checkArgument( retryIntervalsMs != null && retryIntervalsMs.length > 0 && retryIntervalsMs.length <= MAX_RETRY_INTERVAL_COUNT, "retryIntervalsMs was null, empty or exceed max interval count"); final long repeatingInterval = retryIntervalsMs[retryIntervalsMs.length - 1]; if (repeatingInterval < MINIMUM_REPEATING_RETRY_INTERVAL_MS) { throw new IllegalArgumentException( "Repeating retry interval was too short, must be a minimum of 15 minutes: " + repeatingInterval); } } private static void validateNetworkTemplateList( List networkPriorityRules) { Objects.requireNonNull(networkPriorityRules, "networkPriorityRules is null"); Set existingRules = new ArraySet<>(); for (VcnUnderlyingNetworkTemplate rule : networkPriorityRules) { Objects.requireNonNull(rule, "Found null value VcnUnderlyingNetworkTemplate"); if (!existingRules.add(rule)) { throw new IllegalArgumentException("Found duplicate VcnUnderlyingNetworkTemplate"); } } } private static void validateGatewayOption(int option) { if (!ALLOWED_GATEWAY_OPTIONS.contains(option)) { throw new IllegalArgumentException("Invalid vcn gateway option: " + option); } } /** * Returns the configured Gateway Connection name. * *

This name is used by the configuring apps to distinguish between * VcnGatewayConnectionConfigs configured on a single {@link VcnConfig}. This will be used as * the identifier in VcnStatusCallback invocations. * * @see VcnManager.VcnStatusCallback#onGatewayConnectionError */ @NonNull public String getGatewayConnectionName() { return mGatewayConnectionName; } /** * Returns tunnel connection parameters. * * @hide */ @NonNull public IkeTunnelConnectionParams getTunnelConnectionParams() { return mTunnelConnectionParams; } /** * Returns all exposed capabilities. * *

The returned integer-value capabilities will not contain duplicates, and will be sorted in * ascending numerical order. * * @see Builder#addExposedCapability(int) * @see Builder#removeExposedCapability(int) */ @NonNull public int[] getExposedCapabilities() { // Sorted set guarantees ordering return ArrayUtils.convertToIntArray(new ArrayList<>(mExposedCapabilities)); } /** * Returns all exposed capabilities. * *

Left to prevent the need to make major changes while changes are actively in flight. * * @deprecated use getExposedCapabilities() instead * @hide */ @Deprecated @NonNull public Set getAllExposedCapabilities() { return Collections.unmodifiableSet(mExposedCapabilities); } /** * Retrieve the VcnUnderlyingNetworkTemplate list, or a default list if it is not configured. * * @see Builder#setVcnUnderlyingNetworkPriorities(List) */ @NonNull public List getVcnUnderlyingNetworkPriorities() { return new ArrayList<>(mUnderlyingNetworkTemplates); } /** * Retrieves the configured retry intervals. * * @see Builder#setRetryIntervalsMillis(long[]) */ @NonNull public long[] getRetryIntervalsMillis() { return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length); } /** * Retrieves the maximum MTU allowed for this Gateway Connection. * * @see Builder#setMaxMtu(int) */ @IntRange(from = MIN_MTU_V6) public int getMaxMtu() { return mMaxMtu; } /** * Retrieves the maximum supported IKEv2/IPsec NATT keepalive timeout. * * @see Builder#setMinUdpPort4500NatTimeoutSeconds(int) */ public int getMinUdpPort4500NatTimeoutSeconds() { return mMinUdpPort4500NatTimeoutSeconds; } /** * Check whether safe mode is enabled * * @see Builder#setSafeModeEnabled(boolean) */ @FlaggedApi(FLAG_SAFE_MODE_CONFIG) public boolean isSafeModeEnabled() { return !mIsSafeModeDisabled; } /** * Checks if the given VCN gateway option is enabled. * * @param option the option to check. * @throws IllegalArgumentException if the provided option is invalid. * @see Builder#addGatewayOption(int) * @see Builder#removeGatewayOption(int) */ public boolean hasGatewayOption(@VcnGatewayOption int option) { validateGatewayOption(option); return mGatewayOptions.contains(option); } /** * Converts this config to a PersistableBundle. * * @hide */ @NonNull @VisibleForTesting(visibility = Visibility.PROTECTED) public PersistableBundle toPersistableBundle() { final PersistableBundle result = new PersistableBundle(); final PersistableBundle tunnelConnectionParamsBundle = TunnelConnectionParamsUtils.toPersistableBundle(mTunnelConnectionParams); final PersistableBundle exposedCapsBundle = PersistableBundleUtils.fromList( new ArrayList<>(mExposedCapabilities), PersistableBundleUtils.INTEGER_SERIALIZER); final PersistableBundle networkTemplatesBundle = PersistableBundleUtils.fromList( mUnderlyingNetworkTemplates, VcnUnderlyingNetworkTemplate::toPersistableBundle); final PersistableBundle gatewayOptionsBundle = PersistableBundleUtils.fromList( new ArrayList<>(mGatewayOptions), PersistableBundleUtils.INTEGER_SERIALIZER); result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName); result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle); result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle); result.putPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY, networkTemplatesBundle); result.putPersistableBundle(GATEWAY_OPTIONS_KEY, gatewayOptionsBundle); result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); result.putInt(MAX_MTU_KEY, mMaxMtu); result.putInt(MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, mMinUdpPort4500NatTimeoutSeconds); result.putBoolean(IS_SAFE_MODE_DISABLED_KEY, mIsSafeModeDisabled); return result; } @Override public int hashCode() { return Objects.hash( mGatewayConnectionName, mTunnelConnectionParams, mExposedCapabilities, mUnderlyingNetworkTemplates, Arrays.hashCode(mRetryIntervalsMs), mMaxMtu, mMinUdpPort4500NatTimeoutSeconds, mIsSafeModeDisabled, mGatewayOptions); } @Override public boolean equals(@Nullable Object other) { if (!(other instanceof VcnGatewayConnectionConfig)) { return false; } final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other; return mGatewayConnectionName.equals(rhs.mGatewayConnectionName) && mTunnelConnectionParams.equals(rhs.mTunnelConnectionParams) && mExposedCapabilities.equals(rhs.mExposedCapabilities) && mUnderlyingNetworkTemplates.equals(rhs.mUnderlyingNetworkTemplates) && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) && mMaxMtu == rhs.mMaxMtu && mMinUdpPort4500NatTimeoutSeconds == rhs.mMinUdpPort4500NatTimeoutSeconds && mIsSafeModeDisabled == rhs.mIsSafeModeDisabled && mGatewayOptions.equals(rhs.mGatewayOptions); } /** * This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. */ public static final class Builder { @NonNull private final String mGatewayConnectionName; @NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams; @NonNull private final Set mExposedCapabilities = new ArraySet(); @NonNull private final List mUnderlyingNetworkTemplates = new ArrayList<>(DEFAULT_UNDERLYING_NETWORK_TEMPLATES); @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; private int mMaxMtu = DEFAULT_MAX_MTU; private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; private boolean mIsSafeModeDisabled = false; @NonNull private final Set mGatewayOptions = new ArraySet<>(); // TODO: (b/175829816) Consider VCN-exposed capabilities that may be transport dependent. // Consider the case where the VCN might only expose MMS on WiFi, but defer to MMS // when on Cell. /** * Construct a Builder object. * * @param gatewayConnectionName the String GatewayConnection name for this * VcnGatewayConnectionConfig. Each VcnGatewayConnectionConfig within a {@link * VcnConfig} must be given a unique name. This name is used by the caller to * distinguish between VcnGatewayConnectionConfigs configured on a single {@link * VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations. * @param tunnelConnectionParams the IKE tunnel connection configuration * @throws IllegalArgumentException if the provided IkeTunnelConnectionParams is not * configured to support MOBIKE * @see IkeTunnelConnectionParams * @see VcnManager.VcnStatusCallback#onGatewayConnectionError */ public Builder( @NonNull String gatewayConnectionName, @NonNull IkeTunnelConnectionParams tunnelConnectionParams) { Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null"); Objects.requireNonNull(tunnelConnectionParams, "tunnelConnectionParams was null"); if (!tunnelConnectionParams.getIkeSessionParams().hasIkeOption(IKE_OPTION_MOBIKE)) { throw new IllegalArgumentException( "MOBIKE must be configured for the provided IkeSessionParams"); } mGatewayConnectionName = gatewayConnectionName; mTunnelConnectionParams = tunnelConnectionParams; } /** * Add a capability that this VCN Gateway Connection will support. * * @param exposedCapability the app-facing capability to be exposed by this VCN Gateway * Connection (i.e., the capabilities that this VCN Gateway Connection will support). * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection */ @NonNull public Builder addExposedCapability(@VcnSupportedCapability int exposedCapability) { checkValidCapability(exposedCapability); mExposedCapabilities.add(exposedCapability); return this; } /** * Remove a capability that this VCN Gateway Connection will support. * * @param exposedCapability the app-facing capability to not be exposed by this VCN Gateway * Connection (i.e., the capabilities that this VCN Gateway Connection will support) * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection */ @NonNull @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap public Builder removeExposedCapability(@VcnSupportedCapability int exposedCapability) { checkValidCapability(exposedCapability); mExposedCapabilities.remove(exposedCapability); return this; } /** * Set the list of templates to match underlying networks against, in high-to-low priority * order. * *

To select the VCN underlying network, the VCN connection will go through all the * network candidates and return a network matching the highest priority rule. * *

If multiple networks match the same rule, the VCN will prefer an already-selected * network as opposed to a new/unselected network. However, if both are new/unselected * networks, a network will be chosen arbitrarily amongst the networks matching the highest * priority rule. * *

If all networks fail to match the rules provided, a carrier-owned underlying network * will still be selected (if available, at random if necessary). * * @param underlyingNetworkTemplates a list of unique VcnUnderlyingNetworkTemplates that are * ordered from most to least preferred, or an empty list to use the default * prioritization. The default network prioritization order is Opportunistic cellular, * Carrier WiFi and then Macro cellular. * @return this {@link Builder} instance, for chaining */ @NonNull public Builder setVcnUnderlyingNetworkPriorities( @NonNull List underlyingNetworkTemplates) { validateNetworkTemplateList(underlyingNetworkTemplates); mUnderlyingNetworkTemplates.clear(); if (underlyingNetworkTemplates.isEmpty()) { mUnderlyingNetworkTemplates.addAll(DEFAULT_UNDERLYING_NETWORK_TEMPLATES); } else { mUnderlyingNetworkTemplates.addAll(underlyingNetworkTemplates); } return this; } /** * Set the retry interval between VCN establishment attempts upon successive failures. * *

The last retry interval will be repeated until safe mode is entered, or a connection * is successfully established, at which point the retry timers will be reset. For power * reasons, the last (repeated) retry interval MUST be at least 15 minutes. * *

Retry intervals MAY be subject to system power saving modes. That is to say that if * the system enters a power saving mode, the retry may not occur until the device leaves * the specified power saving mode. Intervals are sequential, and intervals will NOT be * skipped if system power saving results in delaying retries (even if it exceed multiple * retry intervals). * *

Each Gateway Connection will retry according to the retry intervals configured, but if * safe mode is enabled, all Gateway Connection(s) will be disabled. * * @param retryIntervalsMs an array of between 1 and 10 millisecond intervals after which * the VCN will attempt to retry a session initiation. The last (repeating) retry * interval must be at least 15 minutes. Defaults to: {@code [1s, 2s, 5s, 30s, 1m, 5m, * 15m]} * @return this {@link Builder} instance, for chaining * @see VcnManager for additional discussion on fail-safe mode */ @NonNull public Builder setRetryIntervalsMillis(@NonNull long[] retryIntervalsMs) { validateRetryInterval(retryIntervalsMs); mRetryIntervalsMs = retryIntervalsMs; return this; } /** * Sets the maximum MTU allowed for this VCN Gateway Connection. * *

This MTU is applied to the VCN Gateway Connection exposed Networks, and represents the * MTU of the virtualized network. * *

The system may reduce the MTU below the maximum specified based on signals such as the * MTU of the underlying networks (and adjusted for Gateway Connection overhead). * * @param maxMtu the maximum MTU allowed for this Gateway Connection. Must be greater than * the IPv6 minimum MTU of 1280. Defaults to 1500. * @return this {@link Builder} instance, for chaining */ @NonNull public Builder setMaxMtu(@IntRange(from = MIN_MTU_V6) int maxMtu) { Preconditions.checkArgument( maxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)"); mMaxMtu = maxMtu; return this; } /** * Sets the maximum supported IKEv2/IPsec NATT keepalive timeout. * *

This is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs, * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data. * * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN * Gateway. * @return this {@link Builder} instance, for chaining */ @NonNull public Builder setMinUdpPort4500NatTimeoutSeconds( @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) int minUdpPort4500NatTimeoutSeconds) { Preconditions.checkArgument( minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, "Timeout must be at least 120s"); mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; return this; } /** * Enables the specified VCN gateway option. * * @param option the option to be enabled * @return this {@link Builder} instance, for chaining * @throws IllegalArgumentException if the provided option is invalid */ @NonNull public Builder addGatewayOption(@VcnGatewayOption int option) { validateGatewayOption(option); mGatewayOptions.add(option); return this; } /** * Resets (disables) the specified VCN gateway option. * * @param option the option to be disabled * @return this {@link Builder} instance, for chaining * @throws IllegalArgumentException if the provided option is invalid */ @NonNull public Builder removeGatewayOption(@VcnGatewayOption int option) { validateGatewayOption(option); mGatewayOptions.remove(option); return this; } /** * Enable/disable safe mode * *

If a VCN fails to provide connectivity within a system-provided timeout, it will enter * safe mode. In safe mode, the VCN Network will be torn down and the system will restore * connectivity by allowing underlying cellular or WiFi networks to be used as default. At * the same time, VCN will continue to retry until it succeeds. * *

When safe mode is disabled and VCN connection fails to provide connectivity, end users * might not have connectivity, and may not have access to carrier-owned underlying * networks. * * @param enabled whether safe mode should be enabled. Defaults to {@code true} */ @FlaggedApi(FLAG_SAFE_MODE_CONFIG) @NonNull public Builder setSafeModeEnabled(boolean enabled) { mIsSafeModeDisabled = !enabled; return this; } /** * Builds and validates the VcnGatewayConnectionConfig. * * @return an immutable VcnGatewayConnectionConfig instance */ @NonNull public VcnGatewayConnectionConfig build() { return new VcnGatewayConnectionConfig( mGatewayConnectionName, mTunnelConnectionParams, mExposedCapabilities, mUnderlyingNetworkTemplates, mRetryIntervalsMs, mMaxMtu, mMinUdpPort4500NatTimeoutSeconds, mIsSafeModeDisabled, mGatewayOptions); } } }