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