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