• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.net.vcn;
17 
18 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
19 import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API;
20 import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG;
21 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
22 
23 import static com.android.internal.annotations.VisibleForTesting.Visibility;
24 
25 import android.annotation.FlaggedApi;
26 import android.annotation.IntDef;
27 import android.annotation.IntRange;
28 import android.annotation.NonNull;
29 import android.annotation.Nullable;
30 import android.annotation.SuppressLint;
31 import android.net.Network;
32 import android.net.NetworkCapabilities;
33 import android.net.ipsec.ike.IkeTunnelConnectionParams;
34 import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtils;
35 import android.net.vcn.util.PersistableBundleUtils;
36 import android.os.PersistableBundle;
37 import android.util.ArraySet;
38 
39 import com.android.internal.annotations.VisibleForTesting;
40 import com.android.internal.util.Preconditions;
41 
42 import java.lang.annotation.Retention;
43 import java.lang.annotation.RetentionPolicy;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.Collections;
47 import java.util.List;
48 import java.util.Objects;
49 import java.util.Set;
50 import java.util.SortedSet;
51 import java.util.TreeSet;
52 import java.util.concurrent.TimeUnit;
53 
54 /**
55  * This class represents a configuration for a connection to a Virtual Carrier Network gateway.
56  *
57  * <p>Each VcnGatewayConnectionConfig represents a single logical connection to a carrier gateway,
58  * and may provide one or more telephony services (as represented by network capabilities). Each
59  * gateway is expected to provide mobility for a given session as the device roams across {@link
60  * Network}s.
61  *
62  * <p>A VCN connection based on this configuration will be brought up dynamically based on device
63  * settings, and filed NetworkRequests. Underlying Networks must provide INTERNET connectivity, and
64  * must be part of the subscription group under which this configuration is registered (see {@link
65  * VcnManager#setVcnConfig}).
66  *
67  * <p>As an abstraction of a cellular network, services that can be provided by a VCN network are
68  * limited to services provided by cellular networks:
69  *
70  * <ul>
71  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_MMS}
72  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_SUPL}
73  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_DUN}
74  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_FOTA}
75  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_IMS}
76  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_CBS}
77  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_IA}
78  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_RCS}
79  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_XCAP}
80  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_EIMS}
81  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_INTERNET}
82  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_MCX}
83  * </ul>
84  */
85 public final class VcnGatewayConnectionConfig {
86     /**
87      * Minimum NAT timeout not set.
88      *
89      * <p>When the timeout is not set, the device will automatically choose a keepalive interval and
90      * may reduce the keepalive frequency for power-optimization.
91      */
92     @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
93     // This constant does not represent a minimum value. It indicates the value is not configured.
94     @SuppressLint("MinMaxConstant")
95     public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1;
96 
97     /** @hide */
98     public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS = 120;
99 
100     // TODO: Use MIN_MTU_V6 once it is public, @hide
101     @VisibleForTesting(visibility = Visibility.PRIVATE)
102     static final int MIN_MTU_V6 = 1280;
103 
104     /**
105      * The set of allowed capabilities for exposed capabilities.
106      *
107      * @hide
108      */
109     public static final Set<Integer> ALLOWED_CAPABILITIES;
110 
111     static {
112         Set<Integer> allowedCaps = new ArraySet<>();
113         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MMS);
114         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_SUPL);
115         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_DUN);
116         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_FOTA);
117         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IMS);
118         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_CBS);
119         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IA);
120         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_RCS);
121         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_XCAP);
122         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_EIMS);
123         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_INTERNET);
124         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MCX);
125 
126         ALLOWED_CAPABILITIES = Collections.unmodifiableSet(allowedCaps);
127     }
128 
129     /** @hide */
130     @Retention(RetentionPolicy.SOURCE)
131     @IntDef(
132             prefix = {"NET_CAPABILITY_"},
133             value = {
134                 NetworkCapabilities.NET_CAPABILITY_MMS,
135                 NetworkCapabilities.NET_CAPABILITY_SUPL,
136                 NetworkCapabilities.NET_CAPABILITY_DUN,
137                 NetworkCapabilities.NET_CAPABILITY_FOTA,
138                 NetworkCapabilities.NET_CAPABILITY_IMS,
139                 NetworkCapabilities.NET_CAPABILITY_CBS,
140                 NetworkCapabilities.NET_CAPABILITY_IA,
141                 NetworkCapabilities.NET_CAPABILITY_RCS,
142                 NetworkCapabilities.NET_CAPABILITY_XCAP,
143                 NetworkCapabilities.NET_CAPABILITY_EIMS,
144                 NetworkCapabilities.NET_CAPABILITY_INTERNET,
145                 NetworkCapabilities.NET_CAPABILITY_MCX,
146             })
147     public @interface VcnSupportedCapability {}
148 
149     /**
150      * Perform mobility update to attempt recovery from suspected data stalls.
151      *
152      * <p>If set, the gateway connection will monitor the data stall detection of the VCN network.
153      * When there is a suspected data stall, the gateway connection will attempt recovery by
154      * performing a mobility update on the underlying IKE session.
155      */
156     public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0;
157 
158     /** @hide */
159     @Retention(RetentionPolicy.SOURCE)
160     @IntDef(
161             prefix = {"VCN_GATEWAY_OPTION_"},
162             value = {
163                 VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY,
164             })
165     public @interface VcnGatewayOption {}
166 
167     private static final Set<Integer> ALLOWED_GATEWAY_OPTIONS = new ArraySet<>();
168 
169     static {
170         ALLOWED_GATEWAY_OPTIONS.add(VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY);
171     }
172 
173     private static final int DEFAULT_MAX_MTU = 1500;
174 
175     /**
176      * The maximum number of retry intervals that may be specified.
177      *
178      * <p>Limited to ensure an upper bound on config sizes.
179      */
180     private static final int MAX_RETRY_INTERVAL_COUNT = 10;
181 
182     /**
183      * The minimum allowable repeating retry interval
184      *
185      * <p>To ensure the device is not constantly being woken up, this retry interval MUST be greater
186      * than this value.
187      *
188      * @see {@link Builder#setRetryIntervalsMillis()}
189      */
190     private static final long MINIMUM_REPEATING_RETRY_INTERVAL_MS = TimeUnit.MINUTES.toMillis(15);
191 
192     private static final long[] DEFAULT_RETRY_INTERVALS_MS =
193             new long[] {
194                 TimeUnit.SECONDS.toMillis(1),
195                 TimeUnit.SECONDS.toMillis(2),
196                 TimeUnit.SECONDS.toMillis(5),
197                 TimeUnit.SECONDS.toMillis(30),
198                 TimeUnit.MINUTES.toMillis(1),
199                 TimeUnit.MINUTES.toMillis(5),
200                 TimeUnit.MINUTES.toMillis(15)
201             };
202 
203     /** @hide */
204     @VisibleForTesting(visibility = Visibility.PRIVATE)
205     public static final List<VcnUnderlyingNetworkTemplate> DEFAULT_UNDERLYING_NETWORK_TEMPLATES =
206             new ArrayList<>();
207 
208     static {
DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnCellUnderlyingNetworkTemplate.Builder() .setOpportunistic(MATCH_REQUIRED) .build())209         DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add(
210                 new VcnCellUnderlyingNetworkTemplate.Builder()
211                         .setOpportunistic(MATCH_REQUIRED)
212                         .build());
213 
DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnWifiUnderlyingNetworkTemplate.Builder() .build())214         DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add(
215                 new VcnWifiUnderlyingNetworkTemplate.Builder()
216                         .build());
217 
DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnCellUnderlyingNetworkTemplate.Builder() .build())218         DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add(
219                 new VcnCellUnderlyingNetworkTemplate.Builder()
220                         .build());
221     }
222 
223     private static final String GATEWAY_CONNECTION_NAME_KEY = "mGatewayConnectionName";
224     @NonNull private final String mGatewayConnectionName;
225 
226     private static final String TUNNEL_CONNECTION_PARAMS_KEY = "mTunnelConnectionParams";
227     @NonNull private IkeTunnelConnectionParams mTunnelConnectionParams;
228 
229     private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities";
230     @NonNull private final SortedSet<Integer> mExposedCapabilities;
231 
232     /** @hide */
233     @VisibleForTesting(visibility = Visibility.PRIVATE)
234     public static final String UNDERLYING_NETWORK_TEMPLATES_KEY = "mUnderlyingNetworkTemplates";
235 
236     @NonNull private final List<VcnUnderlyingNetworkTemplate> mUnderlyingNetworkTemplates;
237 
238     private static final String MAX_MTU_KEY = "mMaxMtu";
239     private final int mMaxMtu;
240 
241     private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs";
242     @NonNull private final long[] mRetryIntervalsMs;
243 
244     private static final String MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY =
245             "mMinUdpPort4500NatTimeoutSeconds";
246     private final int mMinUdpPort4500NatTimeoutSeconds;
247 
248     private static final String IS_SAFE_MODE_DISABLED_KEY = "mIsSafeModeDisabled";
249     private final boolean mIsSafeModeDisabled;
250 
251     private static final String GATEWAY_OPTIONS_KEY = "mGatewayOptions";
252     @NonNull private final Set<Integer> mGatewayOptions;
253 
254     /** Builds a VcnGatewayConnectionConfig with the specified parameters. */
VcnGatewayConnectionConfig( @onNull String gatewayConnectionName, @NonNull IkeTunnelConnectionParams tunnelConnectionParams, @NonNull Set<Integer> exposedCapabilities, @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu, @NonNull int minUdpPort4500NatTimeoutSeconds, boolean isSafeModeDisabled, @NonNull Set<Integer> gatewayOptions)255     private VcnGatewayConnectionConfig(
256             @NonNull String gatewayConnectionName,
257             @NonNull IkeTunnelConnectionParams tunnelConnectionParams,
258             @NonNull Set<Integer> exposedCapabilities,
259             @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
260             @NonNull long[] retryIntervalsMs,
261             @IntRange(from = MIN_MTU_V6) int maxMtu,
262             @NonNull int minUdpPort4500NatTimeoutSeconds,
263             boolean isSafeModeDisabled,
264             @NonNull Set<Integer> gatewayOptions) {
265         mGatewayConnectionName = gatewayConnectionName;
266         mTunnelConnectionParams = tunnelConnectionParams;
267         mExposedCapabilities = new TreeSet(exposedCapabilities);
268         mRetryIntervalsMs = retryIntervalsMs;
269         mMaxMtu = maxMtu;
270         mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds;
271         mGatewayOptions = Collections.unmodifiableSet(new ArraySet(gatewayOptions));
272         mIsSafeModeDisabled = isSafeModeDisabled;
273 
274         mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates);
275         if (mUnderlyingNetworkTemplates.isEmpty()) {
276             mUnderlyingNetworkTemplates.addAll(DEFAULT_UNDERLYING_NETWORK_TEMPLATES);
277         }
278 
279         validate();
280     }
281 
282     // Null check MUST be done for all new fields added to VcnGatewayConnectionConfig, to avoid
283     // crashes when parsing PersistableBundle built on old platforms.
284     /** @hide */
285     @VisibleForTesting(visibility = Visibility.PRIVATE)
VcnGatewayConnectionConfig(@onNull PersistableBundle in)286     public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) {
287         final PersistableBundle tunnelConnectionParamsBundle =
288                 in.getPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY);
289         Objects.requireNonNull(
290                 tunnelConnectionParamsBundle, "tunnelConnectionParamsBundle was null");
291 
292         final PersistableBundle exposedCapsBundle =
293                 in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY);
294         mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY);
295         mTunnelConnectionParams =
296                 TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle);
297         mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
298                 exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
299 
300         final PersistableBundle networkTemplatesBundle =
301                 in.getPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY);
302 
303         if (networkTemplatesBundle == null) {
304             // UNDERLYING_NETWORK_TEMPLATES_KEY was added in Android T. Thus
305             // VcnGatewayConnectionConfig created on old platforms will not have this data and will
306             // be assigned with the default value
307             mUnderlyingNetworkTemplates = new ArrayList<>(DEFAULT_UNDERLYING_NETWORK_TEMPLATES);
308         } else {
309             mUnderlyingNetworkTemplates =
310                     PersistableBundleUtils.toList(
311                             networkTemplatesBundle,
312                             VcnUnderlyingNetworkTemplate::fromPersistableBundle);
313         }
314 
315         final PersistableBundle gatewayOptionsBundle = in.getPersistableBundle(GATEWAY_OPTIONS_KEY);
316 
317         if (gatewayOptionsBundle == null) {
318             // GATEWAY_OPTIONS_KEY was added in Android U. Thus VcnGatewayConnectionConfig created
319             // on old platforms will not have this data and will be assigned with the default value
320             mGatewayOptions = Collections.emptySet();
321         } else {
322             mGatewayOptions =
323                     new ArraySet<>(
324                             PersistableBundleUtils.toList(
325                                     gatewayOptionsBundle,
326                                     PersistableBundleUtils.INTEGER_DESERIALIZER));
327         }
328 
329         mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY);
330         mMaxMtu = in.getInt(MAX_MTU_KEY);
331         mMinUdpPort4500NatTimeoutSeconds =
332                 in.getInt(
333                         MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY,
334                         MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET);
335         mIsSafeModeDisabled = in.getBoolean(IS_SAFE_MODE_DISABLED_KEY);
336 
337         validate();
338     }
339 
validate()340     private void validate() {
341         Objects.requireNonNull(mGatewayConnectionName, "gatewayConnectionName was null");
342         Objects.requireNonNull(mTunnelConnectionParams, "tunnel connection parameter was null");
343 
344         Preconditions.checkArgument(
345                 mExposedCapabilities != null && !mExposedCapabilities.isEmpty(),
346                 "exposedCapsBundle was null or empty");
347         for (Integer cap : getAllExposedCapabilities()) {
348             checkValidCapability(cap);
349         }
350 
351         validateNetworkTemplateList(mUnderlyingNetworkTemplates);
352         Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null");
353         validateRetryInterval(mRetryIntervalsMs);
354 
355         Preconditions.checkArgument(
356                 mMaxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)");
357 
358         Preconditions.checkArgument(
359                 mMinUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET
360                         || mMinUdpPort4500NatTimeoutSeconds
361                                 >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
362                 "minUdpPort4500NatTimeoutSeconds must be at least 120s");
363 
364         for (int option : mGatewayOptions) {
365             validateGatewayOption(option);
366         }
367     }
368 
checkValidCapability(int capability)369     private static void checkValidCapability(int capability) {
370         Preconditions.checkArgument(
371                 ALLOWED_CAPABILITIES.contains(capability),
372                 "NetworkCapability " + capability + "out of range");
373     }
374 
validateRetryInterval(@ullable long[] retryIntervalsMs)375     private static void validateRetryInterval(@Nullable long[] retryIntervalsMs) {
376         Preconditions.checkArgument(
377                 retryIntervalsMs != null
378                         && retryIntervalsMs.length > 0
379                         && retryIntervalsMs.length <= MAX_RETRY_INTERVAL_COUNT,
380                 "retryIntervalsMs was null, empty or exceed max interval count");
381 
382         final long repeatingInterval = retryIntervalsMs[retryIntervalsMs.length - 1];
383         if (repeatingInterval < MINIMUM_REPEATING_RETRY_INTERVAL_MS) {
384             throw new IllegalArgumentException(
385                     "Repeating retry interval was too short, must be a minimum of 15 minutes: "
386                             + repeatingInterval);
387         }
388     }
389 
validateNetworkTemplateList( List<VcnUnderlyingNetworkTemplate> networkPriorityRules)390     private static void validateNetworkTemplateList(
391             List<VcnUnderlyingNetworkTemplate> networkPriorityRules) {
392         Objects.requireNonNull(networkPriorityRules, "networkPriorityRules is null");
393 
394         Set<VcnUnderlyingNetworkTemplate> existingRules = new ArraySet<>();
395         for (VcnUnderlyingNetworkTemplate rule : networkPriorityRules) {
396             Objects.requireNonNull(rule, "Found null value VcnUnderlyingNetworkTemplate");
397             if (!existingRules.add(rule)) {
398                 throw new IllegalArgumentException("Found duplicate VcnUnderlyingNetworkTemplate");
399             }
400         }
401     }
402 
validateGatewayOption(int option)403     private static void validateGatewayOption(int option) {
404         if (!ALLOWED_GATEWAY_OPTIONS.contains(option)) {
405             throw new IllegalArgumentException("Invalid vcn gateway option: " + option);
406         }
407     }
408 
409     /**
410      * Returns the configured Gateway Connection name.
411      *
412      * <p>This name is used by the configuring apps to distinguish between
413      * VcnGatewayConnectionConfigs configured on a single {@link VcnConfig}. This will be used as
414      * the identifier in VcnStatusCallback invocations.
415      *
416      * @see VcnManager.VcnStatusCallback#onGatewayConnectionError
417      */
418     @NonNull
getGatewayConnectionName()419     public String getGatewayConnectionName() {
420         return mGatewayConnectionName;
421     }
422 
423     /**
424      * Returns tunnel connection parameters.
425      *
426      * @hide
427      */
428     @NonNull
getTunnelConnectionParams()429     public IkeTunnelConnectionParams getTunnelConnectionParams() {
430         return mTunnelConnectionParams;
431     }
432 
433     /**
434      * Returns all exposed capabilities.
435      *
436      * <p>The returned integer-value capabilities will not contain duplicates, and will be sorted in
437      * ascending numerical order.
438      *
439      * @see Builder#addExposedCapability(int)
440      * @see Builder#removeExposedCapability(int)
441      */
442     @NonNull
getExposedCapabilities()443     public int[] getExposedCapabilities() {
444         // Sorted set guarantees ordering
445         final int[] caps = new int[mExposedCapabilities.size()];
446 
447         int i = 0;
448         for (int c : mExposedCapabilities) {
449             caps[i++] = c;
450         }
451 
452         return caps;
453     }
454 
455     /**
456      * Returns all exposed capabilities.
457      *
458      * <p>Left to prevent the need to make major changes while changes are actively in flight.
459      *
460      * @deprecated use getExposedCapabilities() instead
461      * @hide
462      */
463     @Deprecated
464     @NonNull
getAllExposedCapabilities()465     public Set<Integer> getAllExposedCapabilities() {
466         return Collections.unmodifiableSet(mExposedCapabilities);
467     }
468 
469     /**
470      * Retrieve the VcnUnderlyingNetworkTemplate list, or a default list if it is not configured.
471      *
472      * @see Builder#setVcnUnderlyingNetworkPriorities(List)
473      */
474     @NonNull
getVcnUnderlyingNetworkPriorities()475     public List<VcnUnderlyingNetworkTemplate> getVcnUnderlyingNetworkPriorities() {
476         return new ArrayList<>(mUnderlyingNetworkTemplates);
477     }
478 
479     /**
480      * Retrieves the configured retry intervals.
481      *
482      * @see Builder#setRetryIntervalsMillis(long[])
483      */
484     @NonNull
getRetryIntervalsMillis()485     public long[] getRetryIntervalsMillis() {
486         return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length);
487     }
488 
489     /**
490      * Retrieves the maximum MTU allowed for this Gateway Connection.
491      *
492      * @see Builder#setMaxMtu(int)
493      */
494     @IntRange(from = MIN_MTU_V6)
getMaxMtu()495     public int getMaxMtu() {
496         return mMaxMtu;
497     }
498 
499     /**
500      * Retrieves the maximum supported IKEv2/IPsec NATT keepalive timeout.
501      *
502      * @see Builder#setMinUdpPort4500NatTimeoutSeconds(int)
503      */
getMinUdpPort4500NatTimeoutSeconds()504     public int getMinUdpPort4500NatTimeoutSeconds() {
505         return mMinUdpPort4500NatTimeoutSeconds;
506     }
507 
508     /**
509      * Check whether safe mode is enabled
510      *
511      * @see Builder#setSafeModeEnabled(boolean)
512      */
513     @FlaggedApi(FLAG_SAFE_MODE_CONFIG)
isSafeModeEnabled()514     public boolean isSafeModeEnabled() {
515         return !mIsSafeModeDisabled;
516     }
517 
518     /**
519      * Checks if the given VCN gateway option is enabled.
520      *
521      * @param option the option to check.
522      * @throws IllegalArgumentException if the provided option is invalid.
523      * @see Builder#addGatewayOption(int)
524      * @see Builder#removeGatewayOption(int)
525      */
hasGatewayOption(@cnGatewayOption int option)526     public boolean hasGatewayOption(@VcnGatewayOption int option) {
527         validateGatewayOption(option);
528         return mGatewayOptions.contains(option);
529     }
530 
531     /**
532      * Converts this config to a PersistableBundle.
533      *
534      * @hide
535      */
536     @NonNull
537     @VisibleForTesting(visibility = Visibility.PROTECTED)
toPersistableBundle()538     public PersistableBundle toPersistableBundle() {
539         final PersistableBundle result = new PersistableBundle();
540 
541         final PersistableBundle tunnelConnectionParamsBundle =
542                 TunnelConnectionParamsUtils.toPersistableBundle(mTunnelConnectionParams);
543         final PersistableBundle exposedCapsBundle =
544                 PersistableBundleUtils.fromList(
545                         new ArrayList<>(mExposedCapabilities),
546                         PersistableBundleUtils.INTEGER_SERIALIZER);
547         final PersistableBundle networkTemplatesBundle =
548                 PersistableBundleUtils.fromList(
549                         mUnderlyingNetworkTemplates,
550                         VcnUnderlyingNetworkTemplate::toPersistableBundle);
551         final PersistableBundle gatewayOptionsBundle =
552                 PersistableBundleUtils.fromList(
553                         new ArrayList<>(mGatewayOptions),
554                         PersistableBundleUtils.INTEGER_SERIALIZER);
555 
556         result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName);
557         result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle);
558         result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle);
559         result.putPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY, networkTemplatesBundle);
560         result.putPersistableBundle(GATEWAY_OPTIONS_KEY, gatewayOptionsBundle);
561         result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
562         result.putInt(MAX_MTU_KEY, mMaxMtu);
563         result.putInt(MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, mMinUdpPort4500NatTimeoutSeconds);
564         result.putBoolean(IS_SAFE_MODE_DISABLED_KEY, mIsSafeModeDisabled);
565 
566         return result;
567     }
568 
569     @Override
hashCode()570     public int hashCode() {
571         return Objects.hash(
572                 mGatewayConnectionName,
573                 mTunnelConnectionParams,
574                 mExposedCapabilities,
575                 mUnderlyingNetworkTemplates,
576                 Arrays.hashCode(mRetryIntervalsMs),
577                 mMaxMtu,
578                 mMinUdpPort4500NatTimeoutSeconds,
579                 mIsSafeModeDisabled,
580                 mGatewayOptions);
581     }
582 
583     @Override
equals(@ullable Object other)584     public boolean equals(@Nullable Object other) {
585         if (!(other instanceof VcnGatewayConnectionConfig)) {
586             return false;
587         }
588 
589         final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other;
590         return mGatewayConnectionName.equals(rhs.mGatewayConnectionName)
591                 && mTunnelConnectionParams.equals(rhs.mTunnelConnectionParams)
592                 && mExposedCapabilities.equals(rhs.mExposedCapabilities)
593                 && mUnderlyingNetworkTemplates.equals(rhs.mUnderlyingNetworkTemplates)
594                 && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
595                 && mMaxMtu == rhs.mMaxMtu
596                 && mMinUdpPort4500NatTimeoutSeconds == rhs.mMinUdpPort4500NatTimeoutSeconds
597                 && mIsSafeModeDisabled == rhs.mIsSafeModeDisabled
598                 && mGatewayOptions.equals(rhs.mGatewayOptions);
599     }
600 
601     /**
602      * This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects.
603      */
604     public static final class Builder {
605         @NonNull private final String mGatewayConnectionName;
606         @NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams;
607         @NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
608 
609         @NonNull
610         private final List<VcnUnderlyingNetworkTemplate> mUnderlyingNetworkTemplates =
611                 new ArrayList<>(DEFAULT_UNDERLYING_NETWORK_TEMPLATES);
612 
613         @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
614         private int mMaxMtu = DEFAULT_MAX_MTU;
615         private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET;
616         private boolean mIsSafeModeDisabled = false;
617 
618         @NonNull private final Set<Integer> mGatewayOptions = new ArraySet<>();
619 
620         // TODO: (b/175829816) Consider VCN-exposed capabilities that may be transport dependent.
621         //       Consider the case where the VCN might only expose MMS on WiFi, but defer to MMS
622         //       when on Cell.
623 
624         /**
625          * Construct a Builder object.
626          *
627          * @param gatewayConnectionName the String GatewayConnection name for this
628          *     VcnGatewayConnectionConfig. Each VcnGatewayConnectionConfig within a {@link
629          *     VcnConfig} must be given a unique name. This name is used by the caller to
630          *     distinguish between VcnGatewayConnectionConfigs configured on a single {@link
631          *     VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations.
632          * @param tunnelConnectionParams the IKE tunnel connection configuration
633          * @throws IllegalArgumentException if the provided IkeTunnelConnectionParams is not
634          *     configured to support MOBIKE
635          * @see IkeTunnelConnectionParams
636          * @see VcnManager.VcnStatusCallback#onGatewayConnectionError
637          */
Builder( @onNull String gatewayConnectionName, @NonNull IkeTunnelConnectionParams tunnelConnectionParams)638         public Builder(
639                 @NonNull String gatewayConnectionName,
640                 @NonNull IkeTunnelConnectionParams tunnelConnectionParams) {
641             Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null");
642             Objects.requireNonNull(tunnelConnectionParams, "tunnelConnectionParams was null");
643             if (!tunnelConnectionParams.getIkeSessionParams().hasIkeOption(IKE_OPTION_MOBIKE)) {
644                 throw new IllegalArgumentException(
645                         "MOBIKE must be configured for the provided IkeSessionParams");
646             }
647 
648             mGatewayConnectionName = gatewayConnectionName;
649             mTunnelConnectionParams = tunnelConnectionParams;
650         }
651 
652         /**
653          * Add a capability that this VCN Gateway Connection will support.
654          *
655          * @param exposedCapability the app-facing capability to be exposed by this VCN Gateway
656          *     Connection (i.e., the capabilities that this VCN Gateway Connection will support).
657          * @return this {@link Builder} instance, for chaining
658          * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
659          *     Connection
660          */
661         @NonNull
addExposedCapability(@cnSupportedCapability int exposedCapability)662         public Builder addExposedCapability(@VcnSupportedCapability int exposedCapability) {
663             checkValidCapability(exposedCapability);
664 
665             mExposedCapabilities.add(exposedCapability);
666             return this;
667         }
668 
669         /**
670          * Remove a capability that this VCN Gateway Connection will support.
671          *
672          * @param exposedCapability the app-facing capability to not be exposed by this VCN Gateway
673          *     Connection (i.e., the capabilities that this VCN Gateway Connection will support)
674          * @return this {@link Builder} instance, for chaining
675          * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
676          *     Connection
677          */
678         @NonNull
679         @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap
removeExposedCapability(@cnSupportedCapability int exposedCapability)680         public Builder removeExposedCapability(@VcnSupportedCapability int exposedCapability) {
681             checkValidCapability(exposedCapability);
682 
683             mExposedCapabilities.remove(exposedCapability);
684             return this;
685         }
686 
687         /**
688          * Set the list of templates to match underlying networks against, in high-to-low priority
689          * order.
690          *
691          * <p>To select the VCN underlying network, the VCN connection will go through all the
692          * network candidates and return a network matching the highest priority rule.
693          *
694          * <p>If multiple networks match the same rule, the VCN will prefer an already-selected
695          * network as opposed to a new/unselected network. However, if both are new/unselected
696          * networks, a network will be chosen arbitrarily amongst the networks matching the highest
697          * priority rule.
698          *
699          * <p>If all networks fail to match the rules provided, a carrier-owned underlying network
700          * will still be selected (if available, at random if necessary).
701          *
702          * @param underlyingNetworkTemplates a list of unique VcnUnderlyingNetworkTemplates that are
703          *     ordered from most to least preferred, or an empty list to use the default
704          *     prioritization. The default network prioritization order is Opportunistic cellular,
705          *     Carrier WiFi and then Macro cellular.
706          * @return this {@link Builder} instance, for chaining
707          */
708         @NonNull
setVcnUnderlyingNetworkPriorities( @onNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates)709         public Builder setVcnUnderlyingNetworkPriorities(
710                 @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates) {
711             validateNetworkTemplateList(underlyingNetworkTemplates);
712 
713             mUnderlyingNetworkTemplates.clear();
714 
715             if (underlyingNetworkTemplates.isEmpty()) {
716                 mUnderlyingNetworkTemplates.addAll(DEFAULT_UNDERLYING_NETWORK_TEMPLATES);
717             } else {
718                 mUnderlyingNetworkTemplates.addAll(underlyingNetworkTemplates);
719             }
720 
721             return this;
722         }
723 
724         /**
725          * Set the retry interval between VCN establishment attempts upon successive failures.
726          *
727          * <p>The last retry interval will be repeated until safe mode is entered, or a connection
728          * is successfully established, at which point the retry timers will be reset. For power
729          * reasons, the last (repeated) retry interval MUST be at least 15 minutes.
730          *
731          * <p>Retry intervals MAY be subject to system power saving modes. That is to say that if
732          * the system enters a power saving mode, the retry may not occur until the device leaves
733          * the specified power saving mode. Intervals are sequential, and intervals will NOT be
734          * skipped if system power saving results in delaying retries (even if it exceed multiple
735          * retry intervals).
736          *
737          * <p>Each Gateway Connection will retry according to the retry intervals configured, but if
738          * safe mode is enabled, all Gateway Connection(s) will be disabled.
739          *
740          * @param retryIntervalsMs an array of between 1 and 10 millisecond intervals after which
741          *     the VCN will attempt to retry a session initiation. The last (repeating) retry
742          *     interval must be at least 15 minutes. Defaults to: {@code [1s, 2s, 5s, 30s, 1m, 5m,
743          *     15m]}
744          * @return this {@link Builder} instance, for chaining
745          * @see VcnManager for additional discussion on fail-safe mode
746          */
747         @NonNull
setRetryIntervalsMillis(@onNull long[] retryIntervalsMs)748         public Builder setRetryIntervalsMillis(@NonNull long[] retryIntervalsMs) {
749             validateRetryInterval(retryIntervalsMs);
750 
751             mRetryIntervalsMs = retryIntervalsMs;
752             return this;
753         }
754 
755         /**
756          * Sets the maximum MTU allowed for this VCN Gateway Connection.
757          *
758          * <p>This MTU is applied to the VCN Gateway Connection exposed Networks, and represents the
759          * MTU of the virtualized network.
760          *
761          * <p>The system may reduce the MTU below the maximum specified based on signals such as the
762          * MTU of the underlying networks (and adjusted for Gateway Connection overhead).
763          *
764          * @param maxMtu the maximum MTU allowed for this Gateway Connection. Must be greater than
765          *     the IPv6 minimum MTU of 1280. Defaults to 1500.
766          * @return this {@link Builder} instance, for chaining
767          */
768         @NonNull
setMaxMtu(@ntRangefrom = MIN_MTU_V6) int maxMtu)769         public Builder setMaxMtu(@IntRange(from = MIN_MTU_V6) int maxMtu) {
770             Preconditions.checkArgument(
771                     maxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)");
772 
773             mMaxMtu = maxMtu;
774             return this;
775         }
776 
777         /**
778          * Sets the maximum supported IKEv2/IPsec NATT keepalive timeout.
779          *
780          * <p>This is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs,
781          * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data.
782          *
783          * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN
784          *     Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN
785          *     Gateway; or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET} to clear this value.
786          * @return this {@link Builder} instance, for chaining
787          */
788         @NonNull
setMinUdpPort4500NatTimeoutSeconds( @ntRangefrom = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) int minUdpPort4500NatTimeoutSeconds)789         public Builder setMinUdpPort4500NatTimeoutSeconds(
790                 @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS)
791                         int minUdpPort4500NatTimeoutSeconds) {
792             if (Flags.mainlineVcnModuleApi()) {
793                 Preconditions.checkArgument(
794                         minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET
795                                 || minUdpPort4500NatTimeoutSeconds
796                                         >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
797                         "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET");
798             } else {
799                 Preconditions.checkArgument(
800                         minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
801                         "Timeout must be at least 120s");
802             }
803 
804             mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds;
805             return this;
806         }
807 
808         /**
809          * Enables the specified VCN gateway option.
810          *
811          * @param option the option to be enabled
812          * @return this {@link Builder} instance, for chaining
813          * @throws IllegalArgumentException if the provided option is invalid
814          */
815         @NonNull
addGatewayOption(@cnGatewayOption int option)816         public Builder addGatewayOption(@VcnGatewayOption int option) {
817             validateGatewayOption(option);
818             mGatewayOptions.add(option);
819             return this;
820         }
821 
822         /**
823          * Resets (disables) the specified VCN gateway option.
824          *
825          * @param option the option to be disabled
826          * @return this {@link Builder} instance, for chaining
827          * @throws IllegalArgumentException if the provided option is invalid
828          */
829         @NonNull
removeGatewayOption(@cnGatewayOption int option)830         public Builder removeGatewayOption(@VcnGatewayOption int option) {
831             validateGatewayOption(option);
832             mGatewayOptions.remove(option);
833             return this;
834         }
835 
836         /**
837          * Enable/disable safe mode
838          *
839          * <p>If a VCN fails to provide connectivity within a system-provided timeout, it will enter
840          * safe mode. In safe mode, the VCN Network will be torn down and the system will restore
841          * connectivity by allowing underlying cellular or WiFi networks to be used as default. At
842          * the same time, VCN will continue to retry until it succeeds.
843          *
844          * <p>When safe mode is disabled and VCN connection fails to provide connectivity, end users
845          * might not have connectivity, and may not have access to carrier-owned underlying
846          * networks.
847          *
848          * @param enabled whether safe mode should be enabled. Defaults to {@code true}
849          */
850         @FlaggedApi(FLAG_SAFE_MODE_CONFIG)
851         @NonNull
setSafeModeEnabled(boolean enabled)852         public Builder setSafeModeEnabled(boolean enabled) {
853             mIsSafeModeDisabled = !enabled;
854             return this;
855         }
856 
857         /**
858          * Builds and validates the VcnGatewayConnectionConfig.
859          *
860          * @return an immutable VcnGatewayConnectionConfig instance
861          */
862         @NonNull
build()863         public VcnGatewayConnectionConfig build() {
864             return new VcnGatewayConnectionConfig(
865                     mGatewayConnectionName,
866                     mTunnelConnectionParams,
867                     mExposedCapabilities,
868                     mUnderlyingNetworkTemplates,
869                     mRetryIntervalsMs,
870                     mMaxMtu,
871                     mMinUdpPort4500NatTimeoutSeconds,
872                     mIsSafeModeDisabled,
873                     mGatewayOptions);
874         }
875     }
876 }
877